layout.tsx 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import type { Metadata } from 'next';
  2. import type { ReactNode } from 'react';
  3. import { Inter, Vazirmatn } from 'next/font/google';
  4. import './global.css';
  5. import { appName, appTagline, siteUrl } from '@/lib/shared';
  6. import { i18n, localeDirection } from '@/lib/i18n';
  7. const inter = Inter({ subsets: ['latin'], display: 'swap' });
  8. // Persian UI font; covers Arabic + Latin glyphs so mixed content renders well.
  9. const vazirmatn = Vazirmatn({ subsets: ['arabic'], display: 'swap' });
  10. // Global SEO defaults and document shell. Locale-aware html attributes are
  11. // computed from route params so RTL locales get a correct base direction.
  12. export const metadata: Metadata = {
  13. metadataBase: new URL(siteUrl),
  14. title: {
  15. default: `${appName} — ${appTagline}`,
  16. template: `%s — ${appName}`,
  17. },
  18. description: appTagline,
  19. applicationName: appName,
  20. openGraph: {
  21. siteName: appName,
  22. type: 'website',
  23. },
  24. twitter: {
  25. card: 'summary_large_image',
  26. },
  27. icons: {
  28. icon: '/favicon.png',
  29. apple: '/icon.png',
  30. },
  31. };
  32. export default async function RootLayout({
  33. children,
  34. params,
  35. }: {
  36. children: ReactNode;
  37. params: Promise<{ lang?: string }>;
  38. }) {
  39. const { lang: rawLang } = await params;
  40. const lang = i18n.languages.includes(rawLang as (typeof i18n.languages)[number])
  41. ? (rawLang as (typeof i18n.languages)[number])
  42. : i18n.defaultLanguage;
  43. const dir = localeDirection(lang);
  44. const fontClassName = lang === 'fa' ? vazirmatn.className : inter.className;
  45. return (
  46. <html lang={lang} dir={dir} className={fontClassName} suppressHydrationWarning>
  47. <body className="flex min-h-screen flex-col" suppressHydrationWarning>
  48. {children}
  49. </body>
  50. </html>
  51. );
  52. }