aboutsummaryrefslogtreecommitdiff
path: root/apps/web/components/graph/legend.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/components/graph/legend.tsx')
-rw-r--r--apps/web/components/graph/legend.tsx302
1 files changed, 204 insertions, 98 deletions
diff --git a/apps/web/components/graph/legend.tsx b/apps/web/components/graph/legend.tsx
index ca04f1e5..9410f33b 100644
--- a/apps/web/components/graph/legend.tsx
+++ b/apps/web/components/graph/legend.tsx
@@ -1,8 +1,7 @@
"use client"
-import { Brain, ChevronDown, ChevronUp, FileText } from "lucide-react"
+import { ChevronUp, ChevronDown, Settings } from "lucide-react"
import { memo, useEffect, useState } from "react"
-import { colors } from "./constants"
import type { LegendProps } from "./types"
const setCookie = (name: string, value: string, days = 365) => {
@@ -25,22 +24,51 @@ const getCookie = (name: string): string | null => {
return null
}
+// Toggle switch component
+function Toggle({ enabled, onChange }: { enabled: boolean; onChange: (v: boolean) => void }) {
+ return (
+ <button
+ type="button"
+ onClick={() => onChange(!enabled)}
+ className={`relative w-11 h-6 rounded-full transition-colors ${
+ enabled ? "bg-blue-600" : "bg-[#1E3A5F]"
+ }`}
+ >
+ <span
+ className={`absolute top-1 w-4 h-4 rounded-full bg-white transition-transform ${
+ enabled ? "left-6" : "left-1"
+ }`}
+ />
+ </button>
+ )
+}
+
export const Legend = memo(function Legend({
id,
nodes = [],
edges = [],
isLoading = false,
}: LegendProps) {
- const [isExpanded, setIsExpanded] = useState(true)
+ const [isExpanded, setIsExpanded] = useState(false)
const [isInitialized, setIsInitialized] = useState(false)
+ const [connectionsExpanded, setConnectionsExpanded] = useState(true)
+
+ // Toggle states for filtering
+ const [showDocMemory, setShowDocMemory] = useState(true)
+ const [showDocSimilarity, setShowDocSimilarity] = useState(true)
+ const [showUpdates, setShowUpdates] = useState(false)
+ const [showExtends, setShowExtends] = useState(true)
+ const [showInferences, setShowInferences] = useState(false)
+ const [showStrong, setShowStrong] = useState(true)
+ const [showWeak, setShowWeak] = useState(true)
useEffect(() => {
if (!isInitialized) {
const savedState = getCookie("legendCollapsed")
- if (savedState === "true") {
- setIsExpanded(false)
- } else if (savedState === "false") {
+ if (savedState === "false") {
setIsExpanded(true)
+ } else {
+ setIsExpanded(false)
}
setIsInitialized(true)
}
@@ -54,124 +82,202 @@ export const Legend = memo(function Legend({
const memoryCount = nodes.filter((n) => n.type === "memory").length
const documentCount = nodes.filter((n) => n.type === "document").length
+ const connectionCount = edges.length
return (
- <div
- id={id}
- className="absolute bottom-4 right-4 z-10 bg-white/5 backdrop-blur-xl border border-white/20 rounded-xl overflow-hidden"
- >
- <div className="p-3">
- {!isExpanded && (
- <button
- type="button"
- onClick={handleToggleExpanded}
- className="flex items-center gap-2 text-white/70 hover:text-white transition-colors"
- >
- <span className="text-sm font-medium">?</span>
- <ChevronUp className="w-4 h-4" />
- </button>
- )}
+ <>
+ {/* Settings button - Bottom right */}
+ <button
+ type="button"
+ className="absolute bottom-4 right-4 z-10 flex items-center justify-center w-10 h-10 text-white/70 bg-[#0A1628]/80 backdrop-blur-xl border border-[#1E3A5F] rounded-lg hover:bg-[#0A1628] hover:text-white transition-colors"
+ title="Settings"
+ >
+ <Settings className="w-5 h-5" />
+ </button>
+ {/* Legend - Positioned at bottom left */}
+ <div
+ id={id}
+ className="absolute bottom-4 left-4 z-10"
+ >
+ {/* Legend expanded content - appears above the button */}
{isExpanded && (
- <>
- <div className="flex items-center justify-between mb-3">
- <span className="text-sm font-medium text-white">Legend</span>
- <button
- type="button"
- onClick={handleToggleExpanded}
- className="text-white/60 hover:text-white transition-colors"
- >
- <ChevronDown className="w-4 h-4" />
- </button>
- </div>
+ <div className="mb-2 bg-[#0A1628]/95 backdrop-blur-xl border border-[#1E3A5F] rounded-xl overflow-hidden min-w-[280px]">
+ {/* Header */}
+ <button
+ type="button"
+ onClick={handleToggleExpanded}
+ className="w-full flex items-center gap-2 px-4 py-3 text-white font-medium hover:bg-white/5 transition-colors"
+ >
+ <ChevronUp className="w-4 h-4" />
+ <span>Legend</span>
+ </button>
- <div className="space-y-4">
- {!isLoading && (
- <div>
- <div className="text-xs text-white/50 mb-2">Statistics</div>
- <div className="space-y-1.5">
- <div className="flex items-center gap-2">
- <Brain className="w-3.5 h-3.5 text-blue-400" />
- <span className="text-xs text-white/70">
- {memoryCount} memories
- </span>
- </div>
- <div className="flex items-center gap-2">
- <FileText className="w-3.5 h-3.5 text-slate-300" />
- <span className="text-xs text-white/70">
- {documentCount} documents
- </span>
- </div>
- <div className="flex items-center gap-2">
- <div className="w-3.5 h-3.5 rounded-full bg-gradient-to-r from-blue-400 to-purple-400" />
- <span className="text-xs text-white/70">
- {edges.length} connections
- </span>
+ <div className="px-4 pb-4">
+ {/* STATISTICS */}
+ <div className="mb-4">
+ <div className="text-xs text-[#525D6E] uppercase tracking-wider mb-3">
+ Statistics
+ </div>
+ <div className="space-y-2">
+ {/* Memories */}
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div
+ className="w-4 h-4"
+ style={{
+ clipPath:
+ "polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)",
+ backgroundColor: "rgba(0, 180, 216, 0.4)",
+ border: "1px solid rgba(0, 180, 216, 0.6)",
+ }}
+ />
+ <span className="text-white/90">Memories</span>
+ <ChevronDown className="w-3 h-3 text-white/50" />
</div>
+ <span className="text-white/60">{memoryCount}</span>
</div>
- </div>
- )}
- <div>
- <div className="text-xs text-white/50 mb-2">Nodes</div>
- <div className="space-y-1.5">
- <div className="flex items-center gap-2">
- <div className="w-4 h-3 rounded bg-white/20 border border-white/40" />
- <span className="text-xs text-white/70">Document</span>
+ {/* Documents */}
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-4 h-4 rounded-sm bg-[#1E3A5F] border border-[#2E4A6F]" />
+ <span className="text-white/90">Documents</span>
+ <ChevronDown className="w-3 h-3 text-white/50" />
+ </div>
+ <span className="text-white/60">{documentCount}</span>
</div>
- <div className="flex items-center gap-2">
- <div
- className="w-3.5 h-3.5"
- style={{
- clipPath:
- "polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)",
- backgroundColor: "rgba(147, 196, 253, 0.4)",
- border: "1px solid rgba(147, 196, 253, 0.6)",
- }}
- />
- <span className="text-xs text-white/70">Memory</span>
+
+ {/* Connections */}
+ <div>
+ <button
+ type="button"
+ onClick={() => setConnectionsExpanded(!connectionsExpanded)}
+ className="w-full flex items-center justify-between"
+ >
+ <div className="flex items-center gap-3">
+ <svg
+ width="16"
+ height="16"
+ viewBox="0 0 24 24"
+ fill="none"
+ stroke="currentColor"
+ strokeWidth="2"
+ className="text-white/70"
+ >
+ <circle cx="18" cy="5" r="3" />
+ <circle cx="6" cy="12" r="3" />
+ <circle cx="18" cy="19" r="3" />
+ <line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
+ <line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
+ </svg>
+ <span className="text-white/90">Connections</span>
+ {connectionsExpanded ? (
+ <ChevronUp className="w-3 h-3 text-white/50" />
+ ) : (
+ <ChevronDown className="w-3 h-3 text-white/50" />
+ )}
+ </div>
+ <span className="text-white/60">{connectionCount}</span>
+ </button>
+
+ {/* Expanded connections */}
+ {connectionsExpanded && (
+ <div className="ml-7 mt-2 space-y-2">
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-4 h-0.5 bg-cyan-500/60" />
+ <span className="text-white/70 text-sm">Doc &gt; Memory</span>
+ </div>
+ </div>
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div
+ className="w-4 h-0.5"
+ style={{
+ background:
+ "repeating-linear-gradient(90deg, rgba(0, 180, 216, 0.6) 0px, rgba(0, 180, 216, 0.6) 2px, transparent 2px, transparent 4px)",
+ }}
+ />
+ <span className="text-white/70 text-sm">Doc similarity</span>
+ </div>
+ <Toggle enabled={showDocSimilarity} onChange={setShowDocSimilarity} />
+ </div>
+ </div>
+ )}
</div>
</div>
</div>
- <div>
- <div className="text-xs text-white/50 mb-2">Connections</div>
- <div className="space-y-1.5">
- <div className="flex items-center gap-2">
- <div className="w-4 h-0.5 bg-slate-400/40" />
- <span className="text-xs text-white/70">Doc → Memory</span>
+ {/* RELATIONS */}
+ <div className="mb-4">
+ <div className="text-xs text-[#525D6E] uppercase tracking-wider mb-3">
+ Relations
+ </div>
+ <div className="space-y-2">
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-4 h-0.5 bg-pink-500" />
+ <span className="text-white/90">Updates</span>
+ </div>
+ <Toggle enabled={showUpdates} onChange={setShowUpdates} />
</div>
- <div className="flex items-center gap-2">
- <div
- className="w-4 h-0.5"
- style={{
- background:
- "repeating-linear-gradient(90deg, rgba(35, 189, 255, 0.6) 0px, rgba(35, 189, 255, 0.6) 3px, transparent 3px, transparent 6px)",
- }}
- />
- <span className="text-xs text-white/70">Doc similarity</span>
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-4 h-0.5 bg-emerald-500" />
+ <span className="text-white/90">Extends</span>
+ </div>
+ <Toggle enabled={showExtends} onChange={setShowExtends} />
+ </div>
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-4 h-0.5 bg-cyan-500" />
+ <span className="text-white/90">Inferences</span>
+ </div>
+ <Toggle enabled={showInferences} onChange={setShowInferences} />
</div>
</div>
</div>
+ {/* SIMILARITY */}
<div>
- <div className="text-xs text-white/50 mb-2">Similarity</div>
- <div className="space-y-1.5">
- <div className="flex items-center gap-2">
- <div className="w-4 h-0.5 bg-cyan-500/30" />
- <span className="text-xs text-white/70">Weak</span>
+ <div className="text-xs text-[#525D6E] uppercase tracking-wider mb-3">
+ Similarity
+ </div>
+ <div className="space-y-2">
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-3 h-3 rounded-full bg-[#1E3A5F] border border-[#3E5A7F]" />
+ <span className="text-white/90">Strong</span>
+ </div>
+ <Toggle enabled={showStrong} onChange={setShowStrong} />
</div>
- <div className="flex items-center gap-2">
- <div className="w-4 h-1 bg-cyan-400/90" />
- <span className="text-xs text-white/70">Strong</span>
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-3">
+ <div className="w-3 h-3 rounded-full bg-[#1E3A5F] border border-[#3E5A7F]" />
+ <span className="text-white/90">Weak</span>
+ </div>
+ <Toggle enabled={showWeak} onChange={setShowWeak} />
</div>
</div>
</div>
</div>
- </>
+ </div>
+ )}
+
+ {/* Legend toggle button (collapsed state) */}
+ {!isExpanded && (
+ <button
+ type="button"
+ onClick={handleToggleExpanded}
+ className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-white/70 bg-[#0A1628]/80 backdrop-blur-xl border border-[#1E3A5F] rounded-lg hover:bg-[#0A1628] hover:text-white transition-colors"
+ >
+ <ChevronDown className="w-4 h-4" />
+ <span>Legend</span>
+ </button>
)}
</div>
- </div>
+ </>
)
})