mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
@@ -2,7 +2,7 @@
|
||||
<html lang="ru" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" href="data:," />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#0a0f1a" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
|
||||
@@ -113,10 +113,13 @@ function detectPlatform(): string | null {
|
||||
}
|
||||
|
||||
function useIsMobile() {
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
// Initialize synchronously to avoid flash between desktop/mobile layouts
|
||||
const [isMobile, setIsMobile] = useState(() => {
|
||||
if (typeof window === 'undefined') return false
|
||||
return window.innerWidth < 768
|
||||
})
|
||||
useEffect(() => {
|
||||
const check = () => setIsMobile(window.innerWidth < 768)
|
||||
check()
|
||||
window.addEventListener('resize', check)
|
||||
return () => window.removeEventListener('resize', check)
|
||||
}, [])
|
||||
@@ -132,7 +135,8 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
|
||||
const { isTelegramWebApp, isFullscreen, safeAreaInset, contentSafeAreaInset } = useTelegramWebApp()
|
||||
const isMobileScreen = useIsMobile()
|
||||
const isMobile = isMobileScreen || isTelegramWebApp
|
||||
// Use mobile layout only on small screens, even in Telegram Desktop
|
||||
const isMobile = isMobileScreen
|
||||
|
||||
const safeBottom = isTelegramWebApp ? Math.max(safeAreaInset.bottom, contentSafeAreaInset.bottom) : 0
|
||||
// In fullscreen mode, add +45px for Telegram native controls (close/menu buttons in corners)
|
||||
@@ -208,10 +212,23 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
window.location.href = redirectUrl
|
||||
}
|
||||
|
||||
// Desktop modal wrapper
|
||||
// Desktop modal wrapper - compact centered modal with max height
|
||||
const DesktopWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="fixed inset-0 bg-black/60 z-[60] flex items-center justify-center p-4" onClick={onClose}>
|
||||
<div className="w-full max-w-md bg-dark-900 rounded-2xl border border-dark-700/50 shadow-2xl" onClick={e => e.stopPropagation()}>
|
||||
<div
|
||||
className="fixed inset-0 backdrop-blur-sm z-[60] flex items-center justify-center p-4 animate-fade-in"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className="relative w-full max-w-md max-h-[85vh] bg-dark-900 rounded-2xl border border-dark-700/50 shadow-2xl flex flex-col overflow-hidden animate-scale-in"
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{/* Desktop close button */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute top-3 right-3 z-10 p-2 rounded-xl bg-dark-800/80 hover:bg-dark-700 text-dark-400 hover:text-dark-200 transition-colors"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
@@ -257,7 +274,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className="flex-1 flex items-center justify-center p-8">
|
||||
<div className={`${isMobile ? 'flex-1' : ''} flex items-center justify-center p-12`}>
|
||||
<div className="w-10 h-10 border-3 border-accent-500 border-t-transparent rounded-full animate-spin" />
|
||||
</div>
|
||||
</Wrapper>
|
||||
@@ -268,7 +285,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
if (error || !appConfig) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className="flex-1 flex flex-col items-center justify-center p-8 text-center">
|
||||
<div className={`${isMobile ? 'flex-1' : ''} flex flex-col items-center justify-center p-8 text-center`}>
|
||||
<div className="text-5xl mb-4">😕</div>
|
||||
<p className="text-dark-300 text-lg mb-6">{t('common.error')}</p>
|
||||
<button onClick={onClose} className="btn-primary px-8 py-3 text-base">{t('common.close')}</button>
|
||||
@@ -281,7 +298,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
if (!appConfig.hasSubscription) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className="flex-1 flex flex-col items-center justify-center p-8 text-center">
|
||||
<div className={`${isMobile ? 'flex-1' : ''} flex flex-col items-center justify-center p-8 text-center`}>
|
||||
<div className="text-5xl mb-4">📱</div>
|
||||
<h3 className="font-bold text-dark-100 text-xl mb-2">{t('subscription.connection.title')}</h3>
|
||||
<p className="text-dark-400 mb-6">{t('subscription.connection.noSubscription')}</p>
|
||||
@@ -314,7 +331,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
</div>
|
||||
|
||||
{/* Apps grouped by platform */}
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-5">
|
||||
<div className={`${isMobile ? 'flex-1' : 'max-h-[60vh]'} overflow-y-auto p-4 space-y-5`}>
|
||||
{availablePlatforms.map(platform => {
|
||||
const apps = appConfig.platforms[platform]
|
||||
if (!apps?.length) return null
|
||||
@@ -387,7 +404,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
||||
<div className={`${isMobile ? 'flex-1' : 'max-h-[60vh]'} overflow-y-auto p-4 space-y-4`}>
|
||||
{/* Step 1 */}
|
||||
{selectedApp?.installationStep && (
|
||||
<div className="p-4 rounded-2xl bg-dark-800/30">
|
||||
@@ -461,12 +478,6 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Desktop footer */}
|
||||
{!isMobile && (
|
||||
<div className="p-4 border-t border-dark-800">
|
||||
<button onClick={onClose} className="btn-secondary w-full py-3 text-base">{t('common.close')}</button>
|
||||
</div>
|
||||
)}
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@ export const setCachedFullscreenEnabled = (enabled: boolean) => {
|
||||
* Provides fullscreen mode, safe area insets, and other WebApp features
|
||||
*/
|
||||
export function useTelegramWebApp() {
|
||||
const [isFullscreen, setIsFullscreen] = useState(false)
|
||||
const [isTelegramWebApp, setIsTelegramWebApp] = useState(false)
|
||||
const [safeAreaInset, setSafeAreaInset] = useState({ top: 0, bottom: 0, left: 0, right: 0 })
|
||||
const [contentSafeAreaInset, setContentSafeAreaInset] = useState({ top: 0, bottom: 0, left: 0, right: 0 })
|
||||
|
||||
// Initialize synchronously to avoid flash/flicker on first render
|
||||
const webApp = typeof window !== 'undefined' ? window.Telegram?.WebApp : undefined
|
||||
|
||||
const [isFullscreen, setIsFullscreen] = useState(() => webApp?.isFullscreen || false)
|
||||
const [isTelegramWebApp, setIsTelegramWebApp] = useState(() => !!webApp)
|
||||
const [safeAreaInset, setSafeAreaInset] = useState(() => webApp?.safeAreaInset || { top: 0, bottom: 0, left: 0, right: 0 })
|
||||
const [contentSafeAreaInset, setContentSafeAreaInset] = useState(() => webApp?.contentSafeAreaInset || { top: 0, bottom: 0, left: 0, right: 0 })
|
||||
|
||||
useEffect(() => {
|
||||
if (!webApp) {
|
||||
setIsTelegramWebApp(false)
|
||||
|
||||
Reference in New Issue
Block a user