9a8fec2e9c
layout 之前把 data-theme 硬编码 light、挂载后才由 UIProvider effect 应用保存的主题, 暗色偏好用户每次刷新先见浅色再翻暗色 = 整页配色重绘(叠加内容加载,观感"刷两次")。 照官网 Site.astro 做法:<head> 内联脚本在首屏渲染前读 localStorage(pg_uc_theme/ pg_uc_lang)设好 data-theme 与 html lang。/user/* CSP 允许 unsafe-inline 脚本,直接内联; 脚本为编译期常量、无插值、只读 localStorage,无 XSS 风险。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
1.7 KiB
TypeScript
42 lines
1.7 KiB
TypeScript
import type { Metadata, Viewport } from 'next';
|
|
import './globals.css';
|
|
import { UIProvider } from '../lib/theme';
|
|
|
|
export const metadata: Metadata = {
|
|
title: 'Pangolin · Account',
|
|
description: 'Manage your subscription, redeem codes, view usage, referrals and account security.',
|
|
};
|
|
|
|
export const viewport: Viewport = {
|
|
width: 'device-width',
|
|
initialScale: 1,
|
|
};
|
|
|
|
// basePath 前缀(与 next.config.mjs 同源)。public/ 的根绝对资源(colors_and_type.css)
|
|
// 不会被 Next 自动加 basePath,需手动拼,否则挂到 /user/ 下会 404。
|
|
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? '/user';
|
|
|
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html lang="en" data-theme="light" suppressHydrationWarning>
|
|
<head>
|
|
{/* 首屏渲染前据 localStorage 设好 data-theme/lang,避免明暗主题(整页配色)在
|
|
挂载后才应用造成的 FOUC 闪烁。/user/* CSP 允许 'unsafe-inline' 脚本,故直接内联。
|
|
与官网 Site.astro 的 no-FOUC 脚本同法(键名用用户中心的 pg_uc_theme/pg_uc_lang)。 */}
|
|
<script
|
|
dangerouslySetInnerHTML={{
|
|
__html:
|
|
"(function(){try{var t=localStorage.getItem('pg_uc_theme');if(t==='dark'||t==='light')document.documentElement.dataset.theme=t;var l=localStorage.getItem('pg_uc_lang');if(l)document.documentElement.lang=l;}catch(e){}})()",
|
|
}}
|
|
/>
|
|
{/* 设计令牌单一真相源,原样链入(SRI 由构建期注入) */}
|
|
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
|
<link rel="stylesheet" href={`${BASE_PATH}/colors_and_type.css`} />
|
|
</head>
|
|
<body>
|
|
<UIProvider>{children}</UIProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|