fix: dynamic site name

This commit is contained in:
shinya
2025-07-01 00:20:51 +08:00
parent 0563f2478e
commit 58f505e9d7
5 changed files with 46 additions and 11 deletions

View File

@@ -4,11 +4,13 @@ import { Inter } from 'next/font/google';
import './globals.css'; import './globals.css';
import AuthProvider from '../components/AuthProvider'; import AuthProvider from '../components/AuthProvider';
import { SiteNameProvider } from '../components/SiteNameContext';
import { ThemeProvider } from '../components/ThemeProvider'; import { ThemeProvider } from '../components/ThemeProvider';
const inter = Inter({ subsets: ['latin'] }); const inter = Inter({ subsets: ['latin'] });
export const dynamic = 'force-dynamic'; export const dynamic = 'force-dynamic';
export const runtime = 'edge';
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
return { return {
@@ -31,19 +33,24 @@ export default function RootLayout({
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV';
return ( return (
<html lang='zh-CN' suppressHydrationWarning> <html lang='zh-CN' suppressHydrationWarning>
<body <body
className={`${inter.className} min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200`} className={`${inter.className} min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200`}
data-site-name={siteName}
> >
<ThemeProvider <SiteNameProvider value={siteName}>
attribute='class' <ThemeProvider
defaultTheme='system' attribute='class'
enableSystem defaultTheme='system'
disableTransitionOnChange enableSystem
> disableTransitionOnChange
<AuthProvider>{children}</AuthProvider> >
</ThemeProvider> <AuthProvider>{children}</AuthProvider>
</ThemeProvider>
</SiteNameProvider>
</body> </body>
</html> </html>
); );

View File

@@ -3,6 +3,7 @@
import { useRouter, useSearchParams } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import { Suspense, useState } from 'react'; import { Suspense, useState } from 'react';
import { useSiteName } from '@/components/SiteNameContext';
import { ThemeToggle } from '@/components/ThemeToggle'; import { ThemeToggle } from '@/components/ThemeToggle';
export const dynamic = 'force-dynamic'; export const dynamic = 'force-dynamic';
@@ -90,7 +91,7 @@ function LoginPageClient({ siteName }: { siteName: string }) {
} }
export default function LoginPage() { export default function LoginPage() {
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV'; const siteName = useSiteName();
return ( return (
<Suspense> <Suspense>
<LoginPageClient siteName={siteName} /> <LoginPageClient siteName={siteName} />

View File

@@ -2,12 +2,13 @@
import Link from 'next/link'; import Link from 'next/link';
import { useSiteName } from './SiteNameContext';
import { ThemeToggle } from './ThemeToggle'; import { ThemeToggle } from './ThemeToggle';
export const dynamic = 'force-dynamic'; export const dynamic = 'force-dynamic';
const MobileHeader = () => { const MobileHeader = () => {
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV'; const siteName = useSiteName();
return ( return (
<header className='md:hidden relative w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'> <header className='md:hidden relative w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'>
<div className='h-12 flex items-center justify-center'> <div className='h-12 flex items-center justify-center'>

View File

@@ -1,3 +1,5 @@
'use client';
import { import {
Clover, Clover,
Film, Film,
@@ -22,6 +24,8 @@ import {
useState, useState,
} from 'react'; } from 'react';
import { useSiteName } from './SiteNameContext';
interface SidebarContextType { interface SidebarContextType {
isCollapsed: boolean; isCollapsed: boolean;
} }
@@ -164,7 +168,7 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
{ icon: VenetianMask, label: '日漫', href: '/douban?type=tv&tag=日本动画' }, { icon: VenetianMask, label: '日漫', href: '/douban?type=tv&tag=日本动画' },
]; ];
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV'; const siteName = useSiteName();
return ( return (
<SidebarContext.Provider value={contextValue}> <SidebarContext.Provider value={contextValue}>

View File

@@ -0,0 +1,22 @@
import React, { createContext, useContext } from 'react';
/**
* 站点名称上下文,默认值为 "MoonTV"。
* 不包含 "use client",以便既能被 Server Component 引用,也能被 Client Component 引用。
*/
export const SiteNameContext = createContext<string>('MoonTV');
interface ProviderProps {
value: string;
children: React.ReactNode;
}
export function SiteNameProvider({ value, children }: ProviderProps) {
return (
<SiteNameContext.Provider value={value}>
{children}
</SiteNameContext.Provider>
);
}
export const useSiteName = () => useContext(SiteNameContext);