Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
import '@/styles/globals.css'
|
|
import '@/styles/main.scss'
|
|
|
|
import type { Metadata, Viewport } from 'next'
|
|
|
|
import { headers } from 'next/headers'
|
|
import clsx from 'clsx'
|
|
import React from 'react'
|
|
|
|
import { Providers } from '@/app/providers'
|
|
import { pinarFont } from '@/config/fonts'
|
|
import { texts } from '@/texts'
|
|
import { SITE_URL } from '@/lib/seo/metadata'
|
|
import { OfflineBanner } from '@/components/feedback/OfflineBanner'
|
|
import { AccountSuspensionBanner } from '@/components/feedback/AccountSuspensionBanner'
|
|
import { withBasePath } from '@/constants/images'
|
|
import { AppToastProvider } from '@/components/feedback/AppToastProvider'
|
|
|
|
export const metadata: Metadata = {
|
|
metadataBase: new URL(SITE_URL),
|
|
title: {
|
|
default: `${texts.common.brandName} — Backoffice`,
|
|
template: `%s | ${texts.common.brandName} Backoffice`,
|
|
},
|
|
description: 'پنل مدیریت قبیله',
|
|
applicationName: `${texts.common.brandName} Backoffice`,
|
|
robots: { index: false, follow: false, nocache: true },
|
|
icons: {
|
|
icon: [
|
|
{ url: withBasePath('/logo.svg'), type: 'image/svg+xml' },
|
|
{ url: withBasePath('/icons/icon-192.png'), sizes: '192x192', type: 'image/png' },
|
|
{ url: withBasePath('/icons/icon-512.png'), sizes: '512x512', type: 'image/png' },
|
|
],
|
|
apple: [{ url: withBasePath('/icons/apple-touch-icon.png'), sizes: '180x180' }],
|
|
},
|
|
formatDetection: {
|
|
telephone: false,
|
|
},
|
|
}
|
|
|
|
export const viewport: Viewport = {
|
|
themeColor: '#6d28d9',
|
|
width: 'device-width',
|
|
initialScale: 1,
|
|
viewportFit: 'cover',
|
|
}
|
|
|
|
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
// Reading the nonce-bearing request headers opts the route into dynamic
|
|
// rendering so Next can apply the per-request CSP nonce to its scripts.
|
|
const nonce = (await headers()).get('x-nonce') ?? undefined
|
|
|
|
return (
|
|
<html
|
|
suppressHydrationWarning
|
|
className={clsx('!overflow-auto', pinarFont.variable)}
|
|
dir="rtl"
|
|
lang="fa"
|
|
>
|
|
<body
|
|
suppressHydrationWarning
|
|
className="min-h-[100dvh] bg-background font-sans antialiased overflow-hidden"
|
|
>
|
|
<Providers
|
|
themeProps={{
|
|
attribute: 'class',
|
|
defaultTheme: 'light',
|
|
forcedTheme: 'light',
|
|
nonce,
|
|
}}
|
|
>
|
|
<AccountSuspensionBanner />
|
|
<OfflineBanner />
|
|
<div className="min-h-[100dvh]">{children}</div>
|
|
<AppToastProvider />
|
|
</Providers>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|