tans-agents-ui / lib /mind-map-layout.ts
Đào Minh Tú
feat(wave5): mind-map, templates, personas marketplace, meeting mode, pinned, notes, link-preview
26c925a
Raw
History Blame Contribute Delete
2.52 kB
import type { BranchTree, ChatSession } from "@/hooks/use-chat-history"
export const MIND_MAP_NODE_WIDTH = 168
export const MIND_MAP_NODE_HEIGHT = 60
export const MIND_MAP_LEVEL_GAP = 200
export const MIND_MAP_ROW_GAP = 20
export interface MindMapNode {
id: string
title: string
depth: number
x: number
y: number
session: ChatSession
isVirtual?: boolean
}
export interface MindMapEdge {
id: string
from: string
to: string
fromX: number
fromY: number
toX: number
toY: number
}
export interface MindMapLayout {
nodes: MindMapNode[]
edges: MindMapEdge[]
width: number
height: number
}
const ROW_SPACING = MIND_MAP_NODE_HEIGHT + MIND_MAP_ROW_GAP
const PADDING = 48
export function truncateTitle(title: string, max = 24) {
const normalized = (title || "Cuộc trò chuyện mới").trim() || "Cuộc trò chuyện mới"
return normalized.length > max ? `${normalized.slice(0, max)}…` : normalized
}
export function layoutMindMap(tree: BranchTree | null): MindMapLayout {
if (!tree) return { nodes: [], edges: [], width: 0, height: 0 }
const nodes: MindMapNode[] = []
const edges: MindMapEdge[] = []
let leafIndex = 0
let maxDepth = 0
function walk(current: BranchTree, depth: number): number {
maxDepth = Math.max(maxDepth, depth)
const children = current.children ?? []
const childYs = children.map((child) => walk(child, depth + 1))
const y = childYs.length
? (Math.min(...childYs) + Math.max(...childYs)) / 2
: leafIndex++ * ROW_SPACING
const x = depth * MIND_MAP_LEVEL_GAP
const isVirtual = current.session.id === "__all__"
nodes.push({
id: current.session.id,
title: truncateTitle(current.session.title),
depth,
x,
y,
session: current.session,
isVirtual,
})
for (const child of children) {
const childNodeY = nodes.find((node) => node.id === child.session.id)?.y ?? y
edges.push({
id: `${current.session.id}->${child.session.id}`,
from: current.session.id,
to: child.session.id,
fromX: x + MIND_MAP_NODE_WIDTH,
fromY: y + MIND_MAP_NODE_HEIGHT / 2,
toX: (depth + 1) * MIND_MAP_LEVEL_GAP,
toY: childNodeY + MIND_MAP_NODE_HEIGHT / 2,
})
}
return y
}
walk(tree, 0)
return {
nodes,
edges,
width: maxDepth * MIND_MAP_LEVEL_GAP + MIND_MAP_NODE_WIDTH + PADDING * 2,
height: Math.max(MIND_MAP_NODE_HEIGHT + PADDING * 2, leafIndex * ROW_SPACING + PADDING * 2),
}
}