| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- import type { Metadata } from "next";
- import { Geist, Geist_Mono } from "next/font/google";
- import Script from "next/script";
- import React from "react";
- import "./globals.scss";
- import { SignalRProvider } from '@/contexts/signalrProvider';
- import { AuthProvider } from "@/contexts/authProvider";
- import { MemberProvider } from "@/contexts/memberProvider";
- import { ConfigProvider } from "@/contexts/configProvider";
- import { ThemeProvider } from "@/contexts/themeProvider";
- import { getAccessToken, getSignalRChatUrl } from "@/lib/utils/server";
- import { fetchConfig } from "@/lib/api/system";
- const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
- });
- const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
- });
- type ColorSchemeEnum = 'normal' | 'light' | 'dark' | 'light dark' | 'dark light' | 'only light';
- function parseMetaAdds(html: string | null | undefined) {
- if (!html) return { other: {} as Record<string, string>, themeColor: [] as { media?: string; color: string }[], colorScheme: undefined as ColorSchemeEnum | undefined };
- const other: Record<string, string> = {};
- const themeColor: { media?: string; color: string }[] = [];
- const validColorSchemes: ColorSchemeEnum[] = ['normal', 'light', 'dark', 'light dark', 'dark light', 'only light'];
- let colorScheme: ColorSchemeEnum | undefined;
- const tagRegex = /<meta\s+([^>]+)\/?>/gi;
- const attrRegex = /(\w[\w-]*)=["']([^"']*?)["']/gi;
- let tagMatch;
- while ((tagMatch = tagRegex.exec(html)) !== null) {
- const attrs: Record<string, string> = {};
- let attrMatch;
- while ((attrMatch = attrRegex.exec(tagMatch[1])) !== null) {
- attrs[attrMatch[1].toLowerCase()] = attrMatch[2];
- }
- const name = attrs['name'];
- const content = attrs['content'];
- if (!name || !content) continue;
- if (name === 'theme-color') {
- themeColor.push(attrs['media'] ? { media: attrs['media'], color: content } : { color: content });
- } else if (name === 'color-scheme') {
- if (validColorSchemes.includes(content as ColorSchemeEnum)) {
- colorScheme = content as ColorSchemeEnum;
- }
- } else {
- other[name] = content;
- }
- }
- return { other, themeColor, colorScheme };
- }
- export async function generateMetadata(): Promise<Metadata> {
- const config = (await fetchConfig())?.data;
- const metaAdds = parseMetaAdds(config?.meta?.adds);
- return {
- title: config?.basic?.siteName ?? 'dpot',
- description: config?.meta?.description ?? '',
- keywords: config?.meta?.keywords ?? '',
- authors: config?.meta?.author ? [{ name: config.meta.author }] : undefined,
- applicationName: config?.meta.applicationName,
- generator: config?.meta.generator,
- robots: config?.meta.robots,
- ...(metaAdds.themeColor.length > 0 && { themeColor: metaAdds.themeColor }),
- ...(metaAdds.colorScheme && { colorScheme: metaAdds.colorScheme }),
- other: {
- 'naver-site-verification': '18dc0d1c5cb466a765e5f5093f94638ed6537d1c',
- ...metaAdds.other,
- },
- };
- }
- export default async function RootLayout({
- children,
- }: Readonly<{
- children: React.ReactNode;
- }>) {
- const accessToken = await getAccessToken();
- const signalRChatUrl = await getSignalRChatUrl();
- const config = (await fetchConfig())?.data;
- return (
- <html lang="ko" suppressHydrationWarning>
- <head>
- <link rel="manifest" href="/manifest.json" />
- <Script src="https://www.googletagmanager.com/gtag/js?id=G-DY6YFW4CTM" strategy="afterInteractive" />
- <Script id="gtag-init" strategy="afterInteractive">
- {`
- window.dataLayer = window.dataLayer || [];
- function gtag(){dataLayer.push(arguments);}
- gtag('js', new Date());
- gtag('config', 'G-DY6YFW4CTM');
- `}
- </Script>
- </head>
- <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
- <ThemeProvider>
- <SignalRProvider accessToken={accessToken} signalRChatUrl={signalRChatUrl}>
- <AuthProvider>
- <MemberProvider>
- <ConfigProvider initialConfig={config}>
- {children}
- </ConfigProvider>
- </MemberProvider>
- </AuthProvider>
- </SignalRProvider>
- </ThemeProvider>
- </body>
- </html>
- );
- }
|