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:
SpecialX
2026-07-17 16:10:05 +08:00
parent f7e52b5b7f
commit 9cedf0c437
140 changed files with 10872 additions and 3192 deletions

View File

@@ -0,0 +1,80 @@
import { useSyncExternalStore } from "react";
import type {
PluginStoreState,
ThemeMode,
Locale,
} from "@edu/shared-ts/contracts";
/**
* usePluginStore - Zustand 全局状态 Hookportal-shell spec §5.2.2
*
* 封装 Zustand store 的订阅,提供 theme/locale/sidebarCollapsed 状态管理。
* 此 hook 是通用封装,实际 store 实例由 portal-shell 创建并注入。
*
* 设计原则(@edu/hookshooks 不直接依赖特定 store 实例,
* 通过 subscribe/getSnapshot 与外部 store 交互。
*
* 关联portal-shell spec §5.2.2、§9.3
*/
/** Store 实例接口(与 Zustand create() 返回值兼容) */
export interface PluginStoreInstance extends PluginStoreState {
subscribe: (listener: () => void) => () => void;
getState: () => PluginStoreState;
}
/** 全局 store 引用(由 portal-shell 注入) */
let globalStore: PluginStoreInstance | null = null;
/**
* 注入全局 PluginStore 实例portal-shell 启动时调用)
*
* @example
* import { usePluginStore as originalStore } from "@/shell/PluginStore";
* injectPluginStore(originalStore as PluginStoreInstance);
*/
export function injectPluginStore(store: PluginStoreInstance): void {
globalStore = store;
}
/**
* 读取 PluginStore 全局状态theme/locale/sidebarCollapsed
*
* @example
* const { theme, setTheme } = usePluginStore();
*/
export function usePluginStore(): PluginStoreState {
return useSyncExternalStore(
(listener) => {
if (!globalStore) return () => {};
return globalStore.subscribe(listener);
},
() => {
if (!globalStore) {
return DEFAULT_STATE;
}
return globalStore.getState();
},
() => DEFAULT_STATE,
);
}
/** 默认状态store 未注入时使用) */
const DEFAULT_STATE: PluginStoreState = {
theme: "light",
setTheme: (_theme: ThemeMode) => {
// store 未注入时的空操作
},
locale: "zh-CN",
setLocale: (_locale: Locale) => {
// store 未注入时的空操作
},
sidebarCollapsed: false,
toggleSidebar: () => {
// store 未注入时的空操作
},
unreadNotificationIds: [],
markNotificationsRead: (_ids: string[]) => {
// store 未注入时的空操作
},
};