SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
2.8 KB · 62 lines tsx
Raw Blame History
1import type { Metadata, Viewport } from 'next';2import './globals.css';3import { t } from '@/i18n';4import { fontDisplay, fontUi } from '@/lib/fonts';5import { SITE_NAME, SITE_URL, TAGLINE } from '@/lib/site';6import { ProvenanceProvider } from '@/components/data/provenance-context';7import { ProvenanceSheet } from '@/components/data/provenance-sheet';8import { MainFrame } from '@/components/layout/main-frame';9import { MobileTabBar } from '@/components/layout/mobile-tab-bar';10import { SearchContainer } from '@/components/layout/search-container';11import { SearchProvider } from '@/components/layout/search-context';12import { SiteFooter } from '@/components/layout/site-footer';13import { SiteHeader } from '@/components/layout/site-header';14import { THEME_BOOT } from '@/components/layout/theme-toggle';1516export const metadata: Metadata = {17  metadataBase: new URL(SITE_URL),18  title: { default: `${SITE_NAME} — ${TAGLINE}`, template: `%s — ${SITE_NAME}` },19  description: t('site.description'),20  applicationName: SITE_NAME,21  robots: { index: true, follow: true },22  alternates: { canonical: '/' },23  openGraph: { type: 'website', siteName: SITE_NAME, url: SITE_URL, title: `${SITE_NAME} — ${TAGLINE}`, description: t('site.description') },24  twitter: { card: 'summary_large_image', title: `${SITE_NAME} — ${TAGLINE}`, description: t('site.description') },25  icons: { icon: [{ url: '/icon.svg', type: 'image/svg+xml' }, { url: '/icon.png', sizes: '512x512', type: 'image/png' }], apple: [{ url: '/apple-icon.png', sizes: '180x180' }] },26};2728export const viewport: Viewport = {29  width: 'device-width',30  initialScale: 1,31  viewportFit: 'cover',32  themeColor: [33    { media: '(prefers-color-scheme: light)', color: '#fbfaf7' },34    { media: '(prefers-color-scheme: dark)', color: '#151513' },35  ],36};3738export default function RootLayout({ children }: { children: React.ReactNode }) {39  return (40    <html lang="en" className={`${fontUi.variable} ${fontDisplay.variable} h-full antialiased`} suppressHydrationWarning>41      <head>42        <script dangerouslySetInnerHTML={{ __html: THEME_BOOT }} />43      </head>44      <body className="flex min-h-full flex-col pb-[calc(56px+env(safe-area-inset-bottom,0px))] md:pb-0">45        <a href="#main" className="sr-only focus:not-sr-only focus:fixed focus:left-3 focus:top-3 focus:z-[200] focus:rounded-sm focus:bg-accent focus:px-3 focus:py-2 focus:text-sm focus:text-accent-ink">46          {t('site.skip')}47        </a>48        <ProvenanceProvider>49          <SearchProvider>50            <SiteHeader />51            <MainFrame>{children}</MainFrame>52            <SiteFooter />53            <MobileTabBar />54            <SearchContainer />55            <ProvenanceSheet />56          </SearchProvider>57        </ProvenanceProvider>58      </body>59    </html>60  );61}62