ai-chatbot/components/flow-board/xmind-annotation-panel.tsx

130 lines
4.4 KiB
TypeScript

"use client";
import { Trash2, X } from "lucide-react";
import type { AnnotatedElement } from "@/lib/flow-board/mind-annotations";
export function XmindAnnotationPanel({
element,
onChange,
onDelete,
onClose,
}: {
element: AnnotatedElement;
onChange: (patch: Record<string, unknown>) => void;
onDelete: () => void;
onClose: () => void;
}) {
const relationship = element.mindAnnotation.kind === "relationship";
const label = (element.texts?.[0]?.text?.children || [])
.map((leaf: { text?: string }) => leaf.text || "")
.join("");
return (
<aside
className="absolute right-0 top-[94px] bottom-9 z-30 w-full max-w-[304px] overflow-y-auto border-l border-[#dfe2e7] bg-white text-[#343b48]"
data-flow-board-shell-control="true"
>
<div className="flex h-12 items-center justify-between border-b border-[#eceef1] px-4">
<h2 className="text-sm font-semibold">
{relationship ? "联系格式" : "外框格式"}
</h2>
<button aria-label="关闭格式面板" onClick={onClose} type="button">
<X size={16} />
</button>
</div>
<div className="space-y-5 p-4 text-xs">
{relationship ? (
<label className="block space-y-2">
<span>联系文字</span>
<input
className="h-9 w-full rounded border border-[#dfe2e7] px-2 text-sm"
value={label}
onChange={(event) =>
onChange({
texts: event.target.value
? [
{
position: 0.5,
text: {
type: "paragraph",
children: [{ text: event.target.value }],
},
},
]
: [],
})
}
/>
</label>
) : (
<label className="flex items-center justify-between">
<span>外框留白</span>
<select
aria-label="外框留白"
className="h-8 rounded border border-[#dfe2e7] px-2"
value={
element.mindAnnotation.kind === "boundary"
? element.mindAnnotation.padding
: 18
}
onChange={(event) =>
onChange({
mindAnnotation: {
...element.mindAnnotation,
padding: Number(event.target.value),
},
})
}
>
{[12, 18, 24, 32].map((value) => (
<option key={value} value={value}>
{value} px
</option>
))}
</select>
</label>
)}
<label className="flex items-center justify-between">
<span>线条颜色</span>
<input
aria-label="联系或外框颜色"
className="h-7 w-12 cursor-pointer"
type="color"
value={element.strokeColor || "#64748b"}
onChange={(event) => onChange({ strokeColor: event.target.value })}
/>
</label>
<label className="flex items-center justify-between">
<span>线条粗细</span>
<select
aria-label="联系或外框粗细"
className="h-8 rounded border border-[#dfe2e7] px-2"
value={element.strokeWidth || 2}
onChange={(event) =>
onChange({ strokeWidth: Number(event.target.value) })
}
>
{[1, 2, 3, 4].map((value) => (
<option key={value} value={value}>
{value} pt
</option>
))}
</select>
</label>
<p className="leading-5 text-[#8b919c]">
{relationship
? "联系线会跟随主题移动。双击线上的文字也可以编辑。"
: "外框包含所选主题及其展开的子主题,随分支布局自动调整。"}
</p>
<button
className="flex h-9 w-full items-center justify-center gap-2 rounded border border-[#e5e7eb] text-[#b44343] hover:bg-red-50"
onClick={onDelete}
type="button"
>
<Trash2 size={14} />
删除{relationship ? "联系" : "外框"}
</button>
</div>
</aside>
);
}