fix(canvas): 添加节点菜单 - 统一命令入口并修复文字溢出与分区拥挤

This commit is contained in:
ddCat committed 2026-08-05 14:23:57 +08:00
1 parent 54ffdebbd9
commit 16c31a8ca1
11 files changed
+182 -110

No files matched your search

@@ -3,16 +3,17 @@ import { Clapperboard, FolderOpen, Image as ImageIcon, Layers3, Music2, Palette,
import { registerAddNodeMenuCommands, type AddNodeMenuCommand } from "@/lib/canvas/tool-registry";
export const addNodeMenuCommands: AddNodeMenuCommand[] = [
// 项目级动作不占用节点网格,保证 8 个节点稳定保持四列两行。
{ id: "style", label: "项目画风", icon: <Palette />, section: "project", defaultOrder: 10, applicable: (ctx) => !ctx.isProjectLinked, run: (ctx) => ctx.handlers.onChooseStyle() },
// 创作节点
{ id: "text", label: "文本", icon: <Type />, section: "node", defaultOrder: 10, run: (ctx) => ctx.handlers.onAddText() },
{ id: "style", label: "项目画风", icon: <Palette />, section: "node", defaultOrder: 20, applicable: (ctx) => !ctx.isProjectLinked, run: (ctx) => ctx.handlers.onChooseStyle() },
{ id: "drawing", label: "绘图", icon: <Pencil />, section: "node", defaultOrder: 20, run: (ctx) => ctx.handlers.onAddDrawing() },
{ id: "script", label: "分镜脚本", icon: <Clapperboard />, badge: "核心", section: "node", defaultOrder: 30, run: (ctx) => ctx.handlers.onAddScript() },
{ id: "frame", label: "背板", icon: <PanelTop />, section: "node", defaultOrder: 40, applicable: (ctx) => ctx.workspaceMode !== "simple", run: (ctx) => ctx.handlers.onAddFrame() },
{ id: "drawing", label: "绘图", icon: <Pencil />, section: "node", defaultOrder: 50, run: (ctx) => ctx.handlers.onAddDrawing() },
{ id: "image", label: "图片", icon: <ImageIcon />, section: "node", defaultOrder: 60, run: (ctx) => ctx.handlers.onAddImage() },
{ id: "video", label: "视频", icon: <Video />, section: "node", defaultOrder: 70, run: (ctx) => ctx.handlers.onAddVideo() },
{ id: "director", label: "导演台", icon: <Layers3 />, badge: "3D", section: "node", defaultOrder: 80, applicable: (ctx) => ctx.workspaceMode !== "simple", run: (ctx) => ctx.handlers.onOpenDirector() },
{ id: "audio", label: "音频", icon: <Music2 />, section: "node", defaultOrder: 90, applicable: (ctx) => ctx.workspaceMode !== "simple", run: (ctx) => ctx.handlers.onAddAudio() },
{ id: "image", label: "图片", icon: <ImageIcon />, section: "node", defaultOrder: 50, run: (ctx) => ctx.handlers.onAddImage() },
{ id: "video", label: "视频", icon: <Video />, section: "node", defaultOrder: 60, run: (ctx) => ctx.handlers.onAddVideo() },
{ id: "director", label: "导演台", icon: <Layers3 />, badge: "3D", section: "node", defaultOrder: 70, applicable: (ctx) => ctx.workspaceMode !== "simple", run: (ctx) => ctx.handlers.onOpenDirector() },
{ id: "audio", label: "音频", icon: <Music2 />, section: "node", defaultOrder: 80, applicable: (ctx) => ctx.workspaceMode !== "simple", run: (ctx) => ctx.handlers.onAddAudio() },
// 导入资源
{ id: "upload", label: "上传文件", icon: <UploadCloud />, section: "resource", defaultOrder: 10, run: (ctx) => ctx.handlers.onUpload() },
{ id: "project-character", label: "添加角色卡", icon: <UserRound />, section: "resource", defaultOrder: 20, applicable: (ctx) => ctx.isProjectLinked, run: (ctx) => ctx.handlers.onOpenProjectCharacters() },
+1 -1
View File
@@ -1,4 +1,4 @@
export type { AddNodeMenuCommand, ToolbarHandlers, ToolbarId, ToolbarPrefs, ToolCategory, ToolContext, ToolDefinition } from "./tool-definition";
export type { AddNodeMenuCommand, AddNodeMenuContext, ToolbarHandlers, ToolbarId, ToolbarPrefs, ToolCategory, ToolContext, ToolDefinition } from "./tool-definition";
export { clearToolbarPrefs, persistToolbarPrefs, readToolbarPrefs } from "./tool-persistence";
export { defaultToolbarPrefs, getAddNodeMenuCommands, getToolbarTools, registerAddNodeMenuCommands, registerToolbarTools, resolveAddNodeMenuCommands, resolveToolbarEntries, resolveToolbarTools } from "./tool-registry";
import "./definitions";
@@ -112,6 +112,26 @@ export type ToolContext = {
handlers: ToolbarHandlers;
};
/** 添加节点菜单只依赖创建动作,避免右键菜单为工具栏状态补无意义字段。 */
export type AddNodeMenuContext = {
workspaceMode: CanvasWorkspaceMode;
isProjectLinked: boolean;
handlers: Pick<ToolbarHandlers,
| "onAddText"
| "onAddImage"
| "onAddVideo"
| "onAddAudio"
| "onAddScript"
| "onAddFrame"
| "onAddDrawing"
| "onChooseStyle"
| "onOpenDirector"
| "onUpload"
| "onOpenMyAssets"
| "onOpenProjectCharacters"
>;
};
/** 工具定义——注册表的基本单元 */
export type ToolDefinition = {
id: string;
@@ -137,17 +157,16 @@ export type ToolDefinition = {
run: (ctx: ToolContext, event?: MouseEvent<HTMLElement>) => void;
};
/** 添加节点菜单命令(复用 CanvasCreateCommand 结构 + 上下文谓词) */
/** 添加节点菜单命令:项目级动作与真正的节点创建分开呈现。 */
export type AddNodeMenuCommand = {
id: string;
label: string;
icon: ReactNode;
badge?: string;
/** 菜单分区:创作节点 / 导入资源 */
section: "node" | "resource";
section: "node" | "project" | "resource";
defaultOrder: number;
applicable?: (ctx: ToolContext) => boolean;
run: (ctx: ToolContext) => void;
applicable?: (ctx: AddNodeMenuContext) => boolean;
run: (ctx: AddNodeMenuContext) => void;
};
/** 用户偏好——排序与显隐 */
@@ -1,6 +1,6 @@
import type { FloatingDockEntry } from "@/components/ui/aceternity/floating-dock";
import type { AddNodeMenuCommand, ToolCategory, ToolContext, ToolDefinition, ToolbarId, ToolbarPrefs } from "./tool-definition";
import type { AddNodeMenuCommand, AddNodeMenuContext, ToolCategory, ToolContext, ToolDefinition, ToolbarId, ToolbarPrefs } from "./tool-definition";
/** 模块级注册表 */
const registry = new Map<ToolbarId, ToolDefinition[]>();
@@ -67,7 +67,7 @@ export function resolveToolbarTools(toolbar: ToolbarId, ctx: ToolContext, prefs:
}
/** 解析添加节点菜单命令——仅 applicable 过滤,不参与排序/显隐 */
export function resolveAddNodeMenuCommands(ctx: ToolContext): AddNodeMenuCommand[] {
export function resolveAddNodeMenuCommands(ctx: AddNodeMenuContext): AddNodeMenuCommand[] {
return getAddNodeMenuCommands().filter((command) => !command.applicable || command.applicable(ctx));
}