diff --git a/docs/miniapp-design.md b/docs/miniapp-design.md index 2cbead9..d5dc4e9 100644 --- a/docs/miniapp-design.md +++ b/docs/miniapp-design.md @@ -26,10 +26,10 @@ Telegram’s guidelines state: Theme is resolved in this order: -1. Hash parameters: `tgWebAppColorScheme`, `tgWebAppThemeParams` (parsed in the inline script in `webapp-next/src/app/layout.tsx`). -2. At runtime: `Telegram.WebApp.colorScheme` and `Telegram.WebApp.themeParams` via `use-telegram-theme.ts` and `TelegramProvider`. +1. Hash parameters: `tgWebAppColorScheme`, `tgWebAppThemeParams` (parsed in the shared inline script from `webapp-next/src/lib/theme-bootstrap-script.ts`, used in layout and global-error). +2. At runtime: `Telegram.WebApp.colorScheme` and `Telegram.WebApp.themeParams` via **TelegramProvider** (theme sync is provider-owned in `ThemeSync` / `useTelegramTheme`), so every route (/, /admin, not-found, error) receives live theme updates. -The inline script in the layout maps all Telegram theme keys to `--tg-theme-*` CSS variables on the document root. The hook sets `data-theme` (`light` / `dark`) and applies Mini App background/header colors. +The inline script maps all Telegram theme keys to `--tg-theme-*` CSS variables on the document root. The provider sets `data-theme` (`light` / `dark`) and applies Mini App background/header colors. ### 2.2 Mapping (ThemeParams → app tokens) @@ -95,10 +95,9 @@ Use **only** these tokens and Tailwind/shadcn aliases (`bg-background`, `text-mu ### 3.3 Safe area and content safe area -- **Class `.content-safe`** (in `globals.css`): Applies: - - `padding-top: var(--tg-viewport-content-safe-area-inset-top, env(safe-area-inset-top, 0))` - - `padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, env(safe-area-inset-bottom, 0))` -- Use `.content-safe` on the **root container of each page** so content is not covered by the Telegram header or bottom bar (Bot API 8.0+). +- **CSS custom properties** (in `globals.css`): `--app-safe-top`, `--app-safe-bottom`, `--app-safe-left`, `--app-safe-right` use Telegram viewport content-safe-area insets with `env(safe-area-inset-*)` fallbacks. Use these for sticky positioning and padding so layout works on notched and landscape devices. +- **Class `.content-safe`**: Applies padding on all four sides using the above tokens so content does not sit under Telegram header, bottom bar, or side chrome (Bot API 8.0+). Use `.content-safe` on the **root container of each page** and on full-screen fallback screens (not-found, error, access denied). +- **Sticky headers:** Use `top-[var(--app-safe-top)]` (not `top-0`) for sticky elements (e.g. calendar header, admin header) so they sit below the Telegram UI instead of overlapping it. - Lists that extend to the bottom should also account for bottom inset (e.g. `padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, 12px)` in `.container-app`). ### 3.4 Sheets and modals @@ -197,7 +196,8 @@ See `webapp-next/src/components/day-detail/DayDetail.tsx` for the Sheet content. ## 8. Telegram integration -- **Header and background:** On init (layout script and `use-telegram-theme.ts`), call: +- **Ready gate:** `callMiniAppReadyOnce()` (in `lib/telegram-ready.ts`) is invoked by the layout’s `ReadyGate` when `appContentReady` becomes true. Any route (/, /admin, not-found, in-app error) that sets `appContentReady` will trigger it so Telegram hides its loader; no route-specific logic is required. +- **Header and background:** On init (layout script and provider’s theme sync), call: - `setBackgroundColor('bg_color')` - `setHeaderColor('bg_color')` - `setBottomBarColor('bottom_bar_bg_color')` when available (Bot API 7.10+). diff --git a/webapp-next/src/app/admin/page.tsx b/webapp-next/src/app/admin/page.tsx index 1222120..87d55ca 100644 --- a/webapp-next/src/app/admin/page.tsx +++ b/webapp-next/src/app/admin/page.tsx @@ -6,8 +6,10 @@ "use client"; +import { useEffect } from "react"; import { useAdminPage, AdminDutyList, ReassignSheet } from "@/components/admin"; import { useTranslation } from "@/i18n/use-translation"; +import { useAppStore } from "@/store/app-store"; import { AccessDeniedScreen } from "@/components/states/AccessDeniedScreen"; import { LoadingState } from "@/components/states/LoadingState"; import { ErrorState } from "@/components/states/ErrorState"; @@ -20,6 +22,12 @@ const PAGE_WRAPPER_CLASS = export default function AdminPage() { const { t, monthName } = useTranslation(); const admin = useAdminPage(); + const setAppContentReady = useAppStore((s) => s.setAppContentReady); + + // Signal ready so Telegram hides loader when opening /admin directly. + useEffect(() => { + setAppContentReady(true); + }, [setAppContentReady]); if (!admin.isAllowed) { return ( @@ -57,7 +65,7 @@ export default function AdminPage() { return (