M8: portal-shell unified frontend shell (Modular Monolith + micro-kernel). - Apollo Client -> apollo-router (port 4010, RSC prefetch) - 5 layouts: classic/focus/split/triple/canvas - Registry + PluginLoader (dynamic import ssr:false) - 3-layer props merge, Zustand PluginStore - 4 widgets: grades/notification-bell/user-menu/class-selector - config-service: new pluginConfig GraphQL resolver - apollo-router: CORS + header propagation for portal-shell - docker-compose.yml: portal-shell service block
56 lines
1.3 KiB
TypeScript
56 lines
1.3 KiB
TypeScript
import "./globals.css";
|
||
import type { Metadata } from "next";
|
||
import { Inter, Fraunces, JetBrains_Mono } from "next/font/google";
|
||
import type { ReactNode } from "react";
|
||
|
||
/**
|
||
* 字体加载(next/font/google self-host)
|
||
*
|
||
* 通过 CSS 变量暴露字体族(--font-inter / --font-fraunces / --font-jetbrains-mono),
|
||
* ui-tokens 的 semantic 层将它们映射为 --font-family-sans/serif/mono。
|
||
* 禁止字体名字面量(project_rules §3.10)。
|
||
*/
|
||
const inter = Inter({
|
||
subsets: ["latin"],
|
||
variable: "--font-inter",
|
||
display: "swap",
|
||
});
|
||
|
||
const fraunces = Fraunces({
|
||
subsets: ["latin"],
|
||
variable: "--font-fraunces",
|
||
display: "swap",
|
||
});
|
||
|
||
const mono = JetBrains_Mono({
|
||
subsets: ["latin"],
|
||
variable: "--font-jetbrains-mono",
|
||
display: "swap",
|
||
});
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Edu Portal Shell",
|
||
description: "K12 智慧教务平台 - 插件化仪表盘",
|
||
};
|
||
|
||
/**
|
||
* RootLayout
|
||
*
|
||
* 仅负责 <html>/<body> 与字体变量。需要 RSC 数据的 Providers
|
||
* (Apollo/Auth/ThemeI18n)在 ClientShell 中挂载(spec §5.5)。
|
||
*/
|
||
export default function RootLayout({
|
||
children,
|
||
}: {
|
||
children: ReactNode;
|
||
}): ReactNode {
|
||
return (
|
||
<html
|
||
lang="zh-CN"
|
||
className={`${inter.variable} ${fraunces.variable} ${mono.variable}`}
|
||
>
|
||
<body>{children}</body>
|
||
</html>
|
||
);
|
||
}
|