forked from zhangyonghao/minimap
first commit
This commit is contained in:
90
frontend/components/MindmapNodeCard.tsx
Normal file
90
frontend/components/MindmapNodeCard.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { memo, useCallback, type MouseEvent } from "react";
|
||||
import { Handle, Position, type NodeProps } from "reactflow";
|
||||
import type { GraphNodeData } from "@/types/mindmap";
|
||||
|
||||
function MindmapNodeCard({ data }: NodeProps<GraphNodeData>) {
|
||||
const isRoot = data.level === 0;
|
||||
const canOpenChat = typeof data.onOpenChat === "function";
|
||||
|
||||
const handleToggleClick = useCallback(
|
||||
(event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
data.onToggle?.();
|
||||
},
|
||||
[data],
|
||||
);
|
||||
|
||||
const handleContentDoubleClick = useCallback(
|
||||
(event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
data.onOpenChat?.();
|
||||
},
|
||||
[data],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex h-[84px] w-[220px] items-center justify-center rounded-[18px] border px-5 py-4 ${
|
||||
isRoot
|
||||
? "border-blue-500 bg-blue-600 text-white shadow-[0_18px_40px_rgba(37,99,235,0.24)]"
|
||||
: "border-slate-200 bg-white text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.08)]"
|
||||
} cursor-default`}
|
||||
>
|
||||
<Handle
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
className={`!pointer-events-none !left-[-7px] !h-3 !w-3 !border ${
|
||||
isRoot ? "!border-blue-200 !bg-blue-100" : "!border-slate-300 !bg-white"
|
||||
}`}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onDoubleClick={handleContentDoubleClick}
|
||||
disabled={!canOpenChat}
|
||||
title={canOpenChat ? "双击发起聊天" : undefined}
|
||||
className={`nodrag nopan max-w-[156px] select-none rounded-xl px-2 py-1 text-center text-sm font-semibold leading-6 transition-colors ${
|
||||
canOpenChat
|
||||
? isRoot
|
||||
? "cursor-pointer hover:bg-white/10"
|
||||
: "cursor-pointer hover:bg-slate-50"
|
||||
: "cursor-default"
|
||||
} disabled:pointer-events-none disabled:opacity-100`}
|
||||
>
|
||||
{data.label}
|
||||
</button>
|
||||
|
||||
{data.hasChildren ? (
|
||||
<>
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
className={`!pointer-events-none !right-[-7px] !h-3 !w-3 !border ${
|
||||
isRoot ? "!border-blue-200 !bg-blue-100" : "!border-blue-300 !bg-white"
|
||||
}`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={data.isExpanded ? "收起子节点" : "展开子节点"}
|
||||
onClick={handleToggleClick}
|
||||
className="nodrag nopan absolute right-0 top-1/2 z-20 flex h-9 w-9 translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-blue-200 bg-white text-lg font-semibold text-blue-700 shadow-[0_8px_18px_rgba(37,99,235,0.14)] transition-all hover:border-blue-300 hover:bg-blue-50 active:scale-95"
|
||||
>
|
||||
{data.isExpanded ? "-" : "+"}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<span
|
||||
className={`pointer-events-none absolute -right-[7px] top-1/2 h-3 w-3 -translate-y-1/2 rounded-full border ${
|
||||
isRoot ? "border-blue-200 bg-blue-100" : "border-slate-300 bg-white"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(MindmapNodeCard);
|
||||
Reference in New Issue
Block a user