feat: add mindmap components from jarvis frontend
- Copied mindmap visualization components (ReactFlow-based interactive graph) - Added MindmapViewer, ReactFlowEditor, MermaidViewer - Included all node types: Concept, Task, Idea, Project - Added controls: NodeCreateModal, ExportButton - Created mindmap route at /mindmap - Added useGraphData hook for knowledge graph API - Copied auth-client and api utilities (dependencies) Note: Requires better-auth packages to be installed for full compilation
This commit is contained in:
89
apps/web/src/components/mindmap/nodes/BaseNode.tsx
Normal file
89
apps/web/src/components/mindmap/nodes/BaseNode.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
'use client';
|
||||
|
||||
import { Handle, Position, NodeProps } from '@xyflow/react';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface BaseNodeData {
|
||||
label: string;
|
||||
content?: string | null;
|
||||
nodeType: string;
|
||||
tags?: string[];
|
||||
domain?: string | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface BaseNodeProps extends NodeProps {
|
||||
data: BaseNodeData;
|
||||
icon: ReactNode;
|
||||
color: string;
|
||||
borderStyle?: 'solid' | 'dashed' | 'dotted';
|
||||
}
|
||||
|
||||
export function BaseNode({
|
||||
data,
|
||||
selected,
|
||||
icon,
|
||||
color,
|
||||
borderStyle = 'solid',
|
||||
}: BaseNodeProps) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
px-4 py-3 rounded-lg shadow-md min-w-[150px] max-w-[250px]
|
||||
bg-white dark:bg-gray-800
|
||||
border-2 transition-all duration-200
|
||||
${selected ? 'ring-2 ring-blue-500 ring-offset-2 dark:ring-offset-gray-900' : ''}
|
||||
`}
|
||||
style={{
|
||||
borderColor: color,
|
||||
borderStyle,
|
||||
}}
|
||||
>
|
||||
<Handle
|
||||
type="target"
|
||||
position={Position.Top}
|
||||
className="w-3 h-3 !bg-gray-400 dark:!bg-gray-500"
|
||||
/>
|
||||
|
||||
<div className="flex items-start gap-2">
|
||||
<div
|
||||
className="flex-shrink-0 w-6 h-6 rounded flex items-center justify-center text-white text-sm"
|
||||
style={{ backgroundColor: color }}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-gray-900 dark:text-gray-100 truncate">
|
||||
{data.label}
|
||||
</div>
|
||||
{data.content && (
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 line-clamp-2">
|
||||
{data.content}
|
||||
</div>
|
||||
)}
|
||||
{data.tags && data.tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-2">
|
||||
{data.tags.slice(0, 3).map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="px-1.5 py-0.5 text-xs rounded bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
{data.tags.length > 3 && (
|
||||
<span className="text-xs text-gray-400">+{data.tags.length - 3}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
className="w-3 h-3 !bg-gray-400 dark:!bg-gray-500"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
24
apps/web/src/components/mindmap/nodes/ConceptNode.tsx
Normal file
24
apps/web/src/components/mindmap/nodes/ConceptNode.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import { NodeProps } from '@xyflow/react';
|
||||
import { BaseNode, BaseNodeData } from './BaseNode';
|
||||
|
||||
export function ConceptNode(props: NodeProps) {
|
||||
return (
|
||||
<BaseNode
|
||||
{...props}
|
||||
data={props.data as BaseNodeData}
|
||||
icon={
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
color="#6366f1"
|
||||
/>
|
||||
);
|
||||
}
|
||||
25
apps/web/src/components/mindmap/nodes/IdeaNode.tsx
Normal file
25
apps/web/src/components/mindmap/nodes/IdeaNode.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import { NodeProps } from '@xyflow/react';
|
||||
import { BaseNode, BaseNodeData } from './BaseNode';
|
||||
|
||||
export function IdeaNode(props: NodeProps) {
|
||||
return (
|
||||
<BaseNode
|
||||
{...props}
|
||||
data={props.data as BaseNodeData}
|
||||
icon={
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M13 10V3L4 14h7v7l9-11h-7z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
color="#f59e0b"
|
||||
borderStyle="dashed"
|
||||
/>
|
||||
);
|
||||
}
|
||||
24
apps/web/src/components/mindmap/nodes/ProjectNode.tsx
Normal file
24
apps/web/src/components/mindmap/nodes/ProjectNode.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import { NodeProps } from '@xyflow/react';
|
||||
import { BaseNode, BaseNodeData } from './BaseNode';
|
||||
|
||||
export function ProjectNode(props: NodeProps) {
|
||||
return (
|
||||
<BaseNode
|
||||
{...props}
|
||||
data={props.data as BaseNodeData}
|
||||
icon={
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
color="#3b82f6"
|
||||
/>
|
||||
);
|
||||
}
|
||||
24
apps/web/src/components/mindmap/nodes/TaskNode.tsx
Normal file
24
apps/web/src/components/mindmap/nodes/TaskNode.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import { NodeProps } from '@xyflow/react';
|
||||
import { BaseNode, BaseNodeData } from './BaseNode';
|
||||
|
||||
export function TaskNode(props: NodeProps) {
|
||||
return (
|
||||
<BaseNode
|
||||
{...props}
|
||||
data={props.data as BaseNodeData}
|
||||
icon={
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
color="#10b981"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user