feat(portal-shell): v2.0 P0 shadcn standardization + security + streaming + error handling
- shadcn/ui 标准化:废弃纸感令牌,统一 bg-background/text-foreground 等 - Tailwind v4 + @theme inline,移除 tailwind.config.js - React 19 use() + Suspense 流式渲染,首屏骨架秒出 - 三级错误边界:Route → Section → Widget 层层兜底 - 错误上报:useErrorReport → sendBeacon → /api/log mock 端点 - 三层安全边界:L1 角色门禁 / L2 权限点门禁 / L3 数据范围 - 权限位图 base36 压缩:67 权限点 → ~14 字符,JWT 体积减少 ≥ 99% - notify 统一 Toast 封装,禁止业务直接 import sonner - PluginBoundary 替代 PluginLoader(错误边界 + Suspense + Skeleton 三件套) 验证:typecheck 0 错误 / lint 0 错误 / build 6 路由生成成功
This commit is contained in:
@@ -1,29 +1,129 @@
|
||||
/**
|
||||
* Layer 3: Tailwind Theme Mapping(Tailwind 主题映射)
|
||||
* Layer 3: Tailwind Theme Mapping(Tailwind v4 @theme inline)
|
||||
*
|
||||
* 将 Layer 2 Semantic 令牌映射为 Tailwind 类名(bg-* / text-* / font-* 等)。
|
||||
* 维护者:ai13(teacher-portal)
|
||||
* 关联:project_rules §3.10、03-long-term-architecture.md §1.5
|
||||
* 将 Layer 2 Semantic 令牌暴露为 Tailwind 类(bg-background / text-foreground / ...)。
|
||||
* 业务代码使用 bg-background / text-foreground / font-sans 等。
|
||||
*
|
||||
* Tailwind 3.4 通过 tailwind.config.js 的 theme.extend 映射;
|
||||
* Tailwind 4 将改用 @theme inline 指令(未来升级时本文件可转为 @theme 块)。
|
||||
*
|
||||
* 使用方式(业务组件):
|
||||
* <div className="bg-paper text-ink font-serif">...</div>
|
||||
* <p className="text-sm text-ink-muted">...</p>
|
||||
*
|
||||
* 对应 tailwind.config.js 中:
|
||||
* colors: { paper: 'var(--bg-paper)', ink: 'var(--color-ink)', ... }
|
||||
* fontFamily: { sans: 'var(--font-family-sans)', serif: 'var(--font-family-serif)', ... }
|
||||
* 对齐:CICD 项目 src/app/styles/tokens/tailwind-theme.css
|
||||
* 关联:project_rules §3.10
|
||||
*/
|
||||
|
||||
/* 显式引用语义令牌,确保 CSS 变量在构建产物中可用 */
|
||||
:root {
|
||||
/* Tailwind 颜色类映射(与 tailwind.config.js theme.extend.colors 对齐) */
|
||||
--tw-color-paper: var(--bg-paper);
|
||||
--tw-color-surface: var(--bg-surface);
|
||||
--tw-color-ink: var(--color-ink);
|
||||
--tw-color-ink-muted: var(--color-ink-muted);
|
||||
--tw-color-accent: var(--color-accent);
|
||||
--tw-color-rule: var(--color-rule);
|
||||
@theme inline {
|
||||
/* ============ shadcn 标准颜色 ============ */
|
||||
--color-background: hsl(var(--background));
|
||||
--color-foreground: hsl(var(--foreground));
|
||||
--color-card: hsl(var(--card));
|
||||
--color-card-foreground: hsl(var(--card-foreground));
|
||||
--color-popover: hsl(var(--popover));
|
||||
--color-popover-foreground: hsl(var(--popover-foreground));
|
||||
--color-primary: hsl(var(--primary));
|
||||
--color-primary-foreground: hsl(var(--primary-foreground));
|
||||
--color-secondary: hsl(var(--secondary));
|
||||
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
||||
--color-muted: hsl(var(--muted));
|
||||
--color-muted-foreground: hsl(var(--muted-foreground));
|
||||
--color-accent: hsl(var(--accent));
|
||||
--color-accent-foreground: hsl(var(--accent-foreground));
|
||||
--color-destructive: hsl(var(--destructive));
|
||||
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
||||
--color-border: hsl(var(--border));
|
||||
--color-input: hsl(var(--input));
|
||||
--color-ring: hsl(var(--ring));
|
||||
|
||||
/* ============ chart 颜色 ============ */
|
||||
--color-chart-1: hsl(var(--chart-1));
|
||||
--color-chart-2: hsl(var(--chart-2));
|
||||
--color-chart-3: hsl(var(--chart-3));
|
||||
--color-chart-4: hsl(var(--chart-4));
|
||||
--color-chart-5: hsl(var(--chart-5));
|
||||
|
||||
/* ============ sidebar 颜色 ============ */
|
||||
--color-sidebar: hsl(var(--sidebar-background));
|
||||
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
|
||||
--color-sidebar-primary: hsl(var(--sidebar-primary));
|
||||
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
|
||||
--color-sidebar-accent: hsl(var(--sidebar-accent));
|
||||
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
|
||||
--color-sidebar-border: hsl(var(--sidebar-border));
|
||||
--color-sidebar-ring: hsl(var(--sidebar-ring));
|
||||
|
||||
/* ============ 扩展语义颜色 ============ */
|
||||
--color-background-elevated: hsl(var(--background-elevated));
|
||||
--color-background-sunken: hsl(var(--background-sunken));
|
||||
--color-text-primary: hsl(var(--text-primary));
|
||||
--color-text-secondary: hsl(var(--text-secondary));
|
||||
--color-text-tertiary: hsl(var(--text-tertiary));
|
||||
--color-border-strong: hsl(var(--border-strong));
|
||||
--color-border-subtle: hsl(var(--border-subtle));
|
||||
--color-diff-add: hsl(var(--diff-add));
|
||||
--color-diff-add-bg: hsl(var(--diff-add-bg));
|
||||
--color-diff-remove: hsl(var(--diff-remove));
|
||||
--color-diff-remove-bg: hsl(var(--diff-remove-bg));
|
||||
--color-graph-node-1: hsl(var(--graph-node-1));
|
||||
--color-graph-node-2: hsl(var(--graph-node-2));
|
||||
--color-graph-node-3: hsl(var(--graph-node-3));
|
||||
--color-graph-node-4: hsl(var(--graph-node-4));
|
||||
--color-graph-node-5: hsl(var(--graph-node-5));
|
||||
--color-graph-node-6: hsl(var(--graph-node-6));
|
||||
|
||||
/* ============ 字体家族 ============ */
|
||||
--font-sans: var(--font-family-sans);
|
||||
--font-serif: var(--font-family-serif);
|
||||
--font-mono: var(--font-family-mono);
|
||||
|
||||
/* ============ 字号阶梯 ============ */
|
||||
--text-size-0: var(--font-size-0);
|
||||
--text-size-1: var(--font-size-1);
|
||||
--text-size-2: var(--font-size-2);
|
||||
--text-size-3: var(--font-size-3);
|
||||
--text-size-4: var(--font-size-4);
|
||||
--text-size-5: var(--font-size-5);
|
||||
--text-size-6: var(--font-size-6);
|
||||
--text-size-7: var(--font-size-7);
|
||||
--text-size-8: var(--font-size-8);
|
||||
--text-size-9: var(--font-size-9);
|
||||
|
||||
/* ============ 圆角阶梯 ============ */
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--radius-2xl: calc(var(--radius) + 8px);
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* ============ 阴影阶梯 ============ */
|
||||
--shadow-1: var(--shadow-1);
|
||||
--shadow-2: var(--shadow-2);
|
||||
--shadow-3: var(--shadow-3);
|
||||
--shadow-4: var(--shadow-4);
|
||||
--shadow-5: var(--shadow-5);
|
||||
--shadow-6: var(--shadow-6);
|
||||
|
||||
/* ============ 动效 ============ */
|
||||
--duration-fast: var(--duration-fast);
|
||||
--duration-normal: var(--duration-normal);
|
||||
--duration-slow: var(--duration-slow);
|
||||
--ease-in: var(--ease-in);
|
||||
--ease-out: var(--ease-out);
|
||||
--ease-in-out: var(--ease-in-out);
|
||||
|
||||
/* ============ z-index ============ */
|
||||
--z-dropdown: var(--z-dropdown);
|
||||
--z-sticky: var(--z-sticky);
|
||||
--z-modal: var(--z-modal);
|
||||
--z-popover: var(--z-popover);
|
||||
--z-toast: var(--z-toast);
|
||||
|
||||
/* ============ 动画 ============ */
|
||||
--animate-accordion-down: accordion-down 0.2s ease-out;
|
||||
--animate-accordion-up: accordion-up 0.2s ease-out;
|
||||
|
||||
@keyframes accordion-down {
|
||||
from { height: 0; }
|
||||
to { height: var(--radix-accordion-content-height); }
|
||||
}
|
||||
@keyframes accordion-up {
|
||||
from { height: var(--radix-accordion-content-height); }
|
||||
to { height: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user