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:
51
webapp-next/src/components/states/FullScreenStateShell.tsx
Normal file
51
webapp-next/src/components/states/FullScreenStateShell.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Shared full-screen state layout for fallback screens (access denied, not-found, error).
|
||||
* Uses content-safe, app tokens, and consistent spacing so all fallback screens look like the same app.
|
||||
*/
|
||||
|
||||
"use client";
|
||||
|
||||
export interface FullScreenStateShellProps {
|
||||
/** Main heading (e.g. "Access denied", "Page not found"). */
|
||||
title: React.ReactNode;
|
||||
/** Optional description or message below the title. */
|
||||
description?: React.ReactNode;
|
||||
/** Optional extra content (e.g. server detail, secondary text). */
|
||||
children?: React.ReactNode;
|
||||
/** Primary action (Button or Link). */
|
||||
primaryAction: React.ReactNode;
|
||||
/** Wrapper role. Default "alert" for error/denied states. */
|
||||
role?: "alert" | "status";
|
||||
/** Optional extra class names for the wrapper. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const WRAPPER_CLASS =
|
||||
"content-safe flex min-h-[var(--tg-viewport-stable-height,100vh)] flex-col items-center justify-center gap-4 bg-background px-4 text-foreground";
|
||||
|
||||
/**
|
||||
* Full-screen centered shell with title, optional description, and primary action.
|
||||
* Use for access denied, not-found, and in-app error boundary screens.
|
||||
*/
|
||||
export function FullScreenStateShell({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
primaryAction,
|
||||
role = "alert",
|
||||
className,
|
||||
}: FullScreenStateShellProps) {
|
||||
return (
|
||||
<div
|
||||
className={className ? `${WRAPPER_CLASS} ${className}` : WRAPPER_CLASS}
|
||||
role={role}
|
||||
>
|
||||
<h1 className="text-xl font-semibold">{title}</h1>
|
||||
{description != null && (
|
||||
<p className="text-center text-muted-foreground">{description}</p>
|
||||
)}
|
||||
{children}
|
||||
{primaryAction}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user