feat(web): 角色关系图谱(灵感⑥缩减版/D4)
设定库人物 tab 新增 React Flow 关系图谱,仅用现有角色读端点数据
(CharacterRelationView={name,kind,note}):边按 name-join、kind 作中文
标签、节点按 role 上色,无 closeness/阵营(数据不存在,不硬造)。
- lib/characters/graphLayout.ts:纯逻辑(role→分组配色关键词映射 / 节点
去空重名 / kind→标签+DEFAULT_RELATION_LABEL / 悬空边跳过并计数 / 自指
跳过 / 互指无向去重 / @dagrejs/dagre 一次性确定性初始坐标、中心→左上、
不可变更新)+22 单测。
- components/characters/RelationshipGraph.tsx:'use client',经 CodexPage
dynamic(ssr:false) 挂载;显式容器高度 + import RF CSS + prefers-reduced-
motion 关 fitView 动画 + 纸感 CSS 变量配色 + 悬空计数提示。
- 依赖:@xyflow/react@^12.11.2 + @dagrejs/dagre@^3.0.0。
无后端契约变更/迁移/gen:api。门禁:lint/typecheck 干净、vitest 565、
coverage lib 95.4%(graphLayout 97.6%)、build OK。
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import { Clock3, Globe2, Sparkles, UserRound } from "lucide-react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Clock3, Globe2, Share2, Sparkles, UserRound } from "lucide-react";
|
||||
|
||||
import { AppShell } from "@/components/AppShell";
|
||||
import { CharacterGenerator } from "@/components/generation/CharacterGenerator";
|
||||
@@ -39,6 +40,23 @@ const TABS: { key: CodexTab; label: string }[] = [
|
||||
{ key: "timeline", label: "时间线" },
|
||||
];
|
||||
|
||||
// 关系图谱(React Flow)只在客户端渲染:ssr:false 绕开 canvas/window 依赖,
|
||||
// 并把 React Flow 及其样式拆到独立 chunk,进人物 tab 才加载。
|
||||
const RelationshipGraph = dynamic(
|
||||
() =>
|
||||
import("@/components/characters/RelationshipGraph").then(
|
||||
(mod) => mod.RelationshipGraph,
|
||||
),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="flex h-[28rem] items-center justify-center rounded border border-line bg-bg text-sm text-ink-soft">
|
||||
关系图谱加载中…
|
||||
</div>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
// 设定库 Codex(UX §6.5):管理人物 / 世界观 / 时间线。
|
||||
// 初始列表来自后端读端点(跨会话全量真源);本会话新入库的角色卡再合并补显,
|
||||
// 故刷新后不再为空、且不与真源重复(按 name 去重,见 mergeCharacterCards)。
|
||||
@@ -143,6 +161,15 @@ export function CodexPage({
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
{characters.length > 0 ? (
|
||||
<Card as="section" className="p-4">
|
||||
<h3 className="mb-3 flex items-center gap-2 font-serif text-sm text-ink">
|
||||
<Share2 className="h-4 w-4 text-cinnabar" aria-hidden="true" />
|
||||
关系图谱
|
||||
</h3>
|
||||
<RelationshipGraph characters={characters} />
|
||||
</Card>
|
||||
) : null}
|
||||
<div id="character-generator">
|
||||
<CharacterGenerator
|
||||
projectId={project.id}
|
||||
|
||||
Reference in New Issue
Block a user