feat: enhance theme handling and layout components for Telegram Mini App

- Updated theme resolution logic to utilize a shared inline script for consistent theme application across routes.
- Introduced `AppShell` and `ReadyGate` components to manage app readiness and theme synchronization, improving user experience.
- Enhanced `GlobalError` and `NotFound` pages with a unified full-screen layout for better accessibility and visual consistency.
- Refactored CSS to implement safe area insets for sticky headers and content safety, ensuring proper layout on various devices.
- Added unit tests for new functionality and improved existing tests for better coverage and reliability.
This commit is contained in:
2026-03-06 16:48:24 +03:00
parent 76bff6dc05
commit 40e2b5adc4
25 changed files with 396 additions and 131 deletions

View File

@@ -1,13 +1,12 @@
/**
* Application initialization: language sync, access-denied logic, deep link routing.
* Runs effects that depend on Telegram auth (isAllowed, startParam); caller provides those.
* Application initialization: access-denied logic and deep link routing.
* Document lang/title are owned by TelegramProvider (all routes).
*/
"use client";
import { useEffect } from "react";
import { useAppStore } from "@/store/app-store";
import { useTranslation } from "@/i18n/use-translation";
import { RETRY_DELAY_MS } from "@/lib/constants";
export interface UseAppInitParams {
@@ -18,23 +17,12 @@ export interface UseAppInitParams {
}
/**
* Applies document lang/title from store (when this hook runs, e.g. main page).
* Handles access denied when not allowed and routes to current duty view when opened via startParam=duty.
* Language is synced from window.__DT_LANG in TelegramProvider (all routes).
*/
export function useAppInit({ isAllowed, startParam }: UseAppInitParams): void {
const lang = useAppStore((s) => s.lang);
const setAccessDenied = useAppStore((s) => s.setAccessDenied);
const setLoading = useAppStore((s) => s.setLoading);
const setCurrentView = useAppStore((s) => s.setCurrentView);
const { t } = useTranslation();
// Apply lang to document (title and html lang) when main page is mounted (tests render Page without TelegramProvider).
useEffect(() => {
if (typeof document === "undefined") return;
document.documentElement.lang = lang;
document.title = t("app.title");
}, [lang, t]);
// When not allowed (no initData and not localhost), show access denied after delay.
useEffect(() => {