From f8cabc92e66d29be809e5acb64eb815966ae9bb7 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Mon, 29 Jun 2026 16:52:43 +0200 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E4=B8=96=E7=95=8C=E8=A7=82?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E8=A1=A5=E3=80=8C=E4=BB=85=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E3=80=8D=E8=AF=B4=E6=98=8E=E4=B8=8E=E6=8C=89=E5=8D=A1=E5=A4=8D?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/generation/WorldGenerator.tsx | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/apps/web/components/generation/WorldGenerator.tsx b/apps/web/components/generation/WorldGenerator.tsx index 599737e..677cea4 100644 --- a/apps/web/components/generation/WorldGenerator.tsx +++ b/apps/web/components/generation/WorldGenerator.tsx @@ -1,14 +1,18 @@ "use client"; import { useCallback, useState } from "react"; -import { Sparkles } from "lucide-react"; +import { Copy, Sparkles } from "lucide-react"; +import { useToast } from "@/components/Toast"; import { Button } from "@/components/ui/Button"; import { Field } from "@/components/ui/Field"; import { SectionHeader } from "@/components/ui/SectionHeader"; +import { StatusNote } from "@/components/ui/StatusNote"; import { TextArea } from "@/components/ui/TextArea"; import { worldEntityRules } from "@/lib/generation/cards"; +import type { WorldEntityCardView } from "@/lib/api/types"; import { useWorldGen } from "@/lib/generation/useWorldGen"; +import { cardClass } from "@/lib/ui/variants"; interface WorldGeneratorProps { projectId: string; @@ -16,14 +20,34 @@ interface WorldGeneratorProps { // 世界观设计器(UX §6.5):一句话需求 → 预览实体卡(type/name/rules)。 // 本期世界观入库端点未建(仅预览);预览结果供作者参考/复制。 +// 复制文案:名称 + 硬规则正文(供作者粘贴到「规则」或「设定库」)。 +function entityClipboardText(entity: WorldEntityCardView): string { + const rules = worldEntityRules(entity); + const body = rules.length > 0 ? rules.join("\n") : "(无显式硬规则)"; + return `${entity.name}(${entity.type})\n${body}`; +} + export function WorldGenerator({ projectId }: WorldGeneratorProps) { const gen = useWorldGen(); + const toast = useToast(); const [brief, setBrief] = useState(""); const onGenerate = useCallback(async () => { await gen.generate(projectId, brief); }, [gen, projectId, brief]); + const onCopy = useCallback( + async (entity: WorldEntityCardView): Promise => { + try { + await navigator.clipboard.writeText(entityClipboardText(entity)); + toast("已复制到剪贴板。", "success"); + } catch { + toast("复制失败,请手动选择文本。", "error"); + } + }, + [toast], + ); + const generating = gen.status === "generating"; return ( @@ -49,11 +73,15 @@ export function WorldGenerator({ projectId }: WorldGeneratorProps) { {gen.status === "done" && gen.entities.length > 0 ? ( -
- {gen.entities.map((entity, i) => ( +
+ + 当前为预览,世界观入库尚未开放;可复制后粘到「规则」或「设定库」。 + +
+ {gen.entities.map((entity, i) => (
@@ -62,6 +90,17 @@ export function WorldGenerator({ projectId }: WorldGeneratorProps) { {entity.type} +
{worldEntityRules(entity).length > 0 ? (
    @@ -73,7 +112,8 @@ export function WorldGenerator({ projectId }: WorldGeneratorProps) {

    (无显式硬规则)

    )}
- ))} + ))} +
) : null}