"use client"; import { useCallback, useMemo, useState } from "react"; import { useRouter } from "next/navigation"; import { AppShell } from "@/components/AppShell"; import type { ProjectResponse, ToolDescriptorView } from "@/lib/api/types"; import { isLegacyTool, resolveLegacyRoute } from "@/lib/toolbox/toolbox"; import { ToolCard } from "./ToolCard"; import { GeneratorRunner } from "./GeneratorRunner"; interface ToolboxPageProps { project: ProjectResponse; tools: ToolDescriptorView[]; // 命令面板 action-gen- 深链:进页直接打开该工具的 runner(仅新工具)。 initialOpenKey?: string; } // 创作工具箱(通用生成器框架):声明驱动的卡片栅格。 // legacy 工具(世界观/人设/大纲)跳现有页面保其更丰富的入库流;新工具开 GeneratorRunner。 export function ToolboxPage({ project, tools, initialOpenKey, }: ToolboxPageProps) { const router = useRouter(); const findOpenable = useCallback( (key: string | undefined): ToolDescriptorView | null => { if (!key) return null; const tool = tools.find((t) => t.key === key); return tool && !isLegacyTool(tool) ? tool : null; }, [tools], ); const [active, setActive] = useState(() => findOpenable(initialOpenKey), ); const onOpen = useCallback( (tool: ToolDescriptorView): void => { if (isLegacyTool(tool) && tool.legacy_route) { router.push(resolveLegacyRoute(tool.legacy_route, project.id)); return; } setActive(tool); }, [router, project.id], ); const sorted = useMemo( // 新工具靠前(更想被发现),legacy 收后;同组保持后端顺序。 () => [...tools].sort((a, b) => Number(a.is_legacy) - Number(b.is_legacy)), [tools], ); return (

创作工具箱

声明驱动的生成器集合:脑洞 / 书名 / 简介 / 名字 / 金手指 / 词条 / 黄金开篇 / 细纲… 选一个开始,结构化产物可一键入库(经一致性预检)。

{active ? ( setActive(null)} /> ) : sorted.length === 0 ? (

(暂无可用生成器)

) : (
{sorted.map((tool) => ( ))}
)}
); }