Files
pargar/frontend/src/app/layout.tsx
T
ahpandClaude Sonnet 4.6 089c114019 feat: mobile-first responsive overhaul — safe areas, touch targets, bottom sheet, bottom nav
Viewport:
- Add `viewport` export with `viewport-fit=cover` (enables CSS safe-area-inset-*
  on bezel-less iOS/Android) and `interactive-widget=resizes-content` (prevents
  layout jumps from virtual keyboard open/close)

iOS zoom prevention:
- input.tsx, textarea.tsx: change text-sm (14px) → text-base sm:text-sm (16px)
  on mobile; iOS Safari auto-zooms any input with font-size < 16px

Touch targets:
- button.tsx: default h-10 → h-11 (44px), sm h-8 → h-9 (36px), icon h-10→h-11
  matching the 44×44px iOS HIG and WCAG 2.5.5 minimum
- Add touch-manipulation to buttons, inputs, textarea to eliminate 300ms tap delay

Dialog → mobile bottom sheet:
- On mobile (< 640px): anchored to bottom with full width, rounded top corners,
  slide-in-from-bottom / slide-out-to-bottom animation, drag handle affordance,
  max-h-[90svh] + overflow-y-auto to prevent viewport overflow
- Safe area padding: pb-[max(1.25rem,env(safe-area-inset-bottom))]
- On desktop (sm+): unchanged centered modal with zoom animation
- Close button gets a 32×32 tap area on mobile

Mobile navigation:
- New bottom-nav.tsx: persistent 3-tab bottom bar (مسیر/مرکز/لیگ) shown below
  md: breakpoint, hidden on desktop; 56px height + safe-area-inset-bottom;
  active tab gets heavier stroke and scale
- Only shown for authenticated non-admin users
- app-shell.tsx: injects BottomNav; main content gets dynamic padding-bottom to
  clear the bar (56px + safe area) on mobile, reverts to py-10 on md:
- Footer: safe-area-inset-bottom padding so content clears iPhone home indicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-18 10:51:37 +03:30

67 lines
2.3 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import localFont from "next/font/local";
import "./globals.css";
import { Providers } from "@/components/providers";
import { AppShell } from "@/components/app-shell";
import { PageTransition } from "@/components/page-transition";
/** Vazirmatn FD — default UI; Latin digits render as Persian glyphs. */
const vazirmatnFd = localFont({
src: [
{ path: "./fonts/Vazirmatn-FD-Thin.woff2", weight: "100", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-ExtraLight.woff2", weight: "200", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-Light.woff2", weight: "300", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-Regular.woff2", weight: "400", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-Medium.woff2", weight: "500", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-SemiBold.woff2", weight: "600", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-Bold.woff2", weight: "700", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-ExtraBold.woff2", weight: "800", style: "normal" },
{ path: "./fonts/Vazirmatn-FD-Black.woff2", weight: "900", style: "normal" },
],
display: "swap",
variable: "--font-vazirmatn",
fallback: ["Tahoma", "Segoe UI", "Arial", "sans-serif"],
});
/** Plain Vazirmatn — Latin digits stay Latin (passwords, usernames, captcha, URLs…). */
const vazirmatnLatin = localFont({
src: "./fonts/Vazirmatn-Variable.woff2",
weight: "100 900",
display: "swap",
variable: "--font-vazirmatn-latin",
fallback: ["Tahoma", "Segoe UI", "Arial", "sans-serif"],
});
export const metadata: Metadata = {
title: "پرگار",
description: "مسیر یادگیری واقعی پرگار",
};
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
viewportFit: "cover",
interactiveWidget: "resizes-content",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html
lang="fa"
dir="rtl"
className={`${vazirmatnFd.variable} ${vazirmatnLatin.variable}`}
suppressHydrationWarning
>
<body
className={`${vazirmatnFd.className} min-h-screen bg-background font-sans text-foreground antialiased`}
>
<Providers>
<AppShell>
<PageTransition>{children}</PageTransition>
</AppShell>
</Providers>
</body>
</html>
);
}