将三个硬编码工具栏(主工具栏/多选工具栏/节点悬停工具栏)统一改造为注册表驱动体系: - 新增 tool-registry 核心基础设施(ToolDefinition/ToolContext/ToolbarHandlers 类型、 注册表解析器 resolveToolbarEntries/resolveToolbarTools、偏好持久化 readToolbarPrefs/persistToolbarPrefs) - 提取四个工具定义文件(main/selection/node-hover/add-node-menu),通过 applicable 谓词实现上下文感知 - FloatingDock 新增 expands 字段(aria-expanded 语义修正)和 danger-group 分组渲染(危险操作视觉隔离) - 主工具栏新增工具栏设置面板(ToolbarSettingsModal),支持拖拽排序+显隐控制(motion/react Reorder,零新增依赖) - 偏好持久化到 scopedLocalStorage,按工具栏独立存储 Co-authored-by: sikongyue <3155157671@qq.com>
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { scopedLocalStorage } from "@/lib/user-scope";
|
||
|
||
import type { ToolbarId, ToolbarPrefs } from "./tool-definition";
|
||
|
||
const STORAGE_VERSION = "v1";
|
||
const storageKey = (toolbar: ToolbarId) => `canvas-toolbar-prefs-${toolbar}-${STORAGE_VERSION}`;
|
||
|
||
/**
|
||
* 读取工具栏偏好。缺失或解析失败时返回 null(由调用方决定是否用默认值)
|
||
*/
|
||
export function readToolbarPrefs(toolbar: ToolbarId): ToolbarPrefs | null {
|
||
try {
|
||
const stored = scopedLocalStorage.getItem(storageKey(toolbar));
|
||
if (!stored) return null;
|
||
const parsed = JSON.parse(stored) as unknown;
|
||
if (!isPrefsShape(parsed)) return null;
|
||
return { order: Array.isArray(parsed.order) ? parsed.order.filter((id) => typeof id === "string") : [], hidden: Array.isArray(parsed.hidden) ? parsed.hidden.filter((id) => typeof id === "string") : [] };
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export function persistToolbarPrefs(toolbar: ToolbarId, prefs: ToolbarPrefs) {
|
||
try {
|
||
scopedLocalStorage.setItem(storageKey(toolbar), JSON.stringify(prefs));
|
||
} catch {
|
||
// 浏览器禁用本地存储时保留当前会话内的选择
|
||
}
|
||
}
|
||
|
||
export function clearToolbarPrefs(toolbar: ToolbarId) {
|
||
try {
|
||
scopedLocalStorage.removeItem(storageKey(toolbar));
|
||
} catch {
|
||
// 忽略
|
||
}
|
||
}
|
||
|
||
function isPrefsShape(value: unknown): value is Partial<ToolbarPrefs> {
|
||
return typeof value === "object" && value !== null;
|
||
}
|