Files
Edu/packages/hooks/src/use-plugin-store.ts
SpecialX 9cedf0c437 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 路由生成成功
2026-07-17 16:10:05 +08:00

81 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 未注入时的空操作
},
};