"use client" import { useIsMobile } from "@/hooks/use-mobile" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/ui/collapsible" import { GlassMenuEffect } from "@/ui/glass-effect" import { Brain, ChevronDown, ChevronUp, FileText } from "lucide-react" import { memo, useEffect, useState } from "react" import { colors } from "@/constants" import type { GraphEdge, GraphNode, LegendProps } from "@/types" import * as styles from "./legend.css" // Cookie utility functions for legend state const setCookie = (name: string, value: string, days = 365) => { if (typeof document === "undefined") return const expires = new Date() expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000) document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/` } const getCookie = (name: string): string | null => { if (typeof document === "undefined") return null const nameEQ = `${name}=` const ca = document.cookie.split(";") for (let i = 0; i < ca.length; i++) { let c = ca[i] if (!c) continue while (c.charAt(0) === " ") c = c.substring(1, c.length) if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length) } return null } interface ExtendedLegendProps extends LegendProps { id?: string nodes?: GraphNode[] edges?: GraphEdge[] isLoading?: boolean } export const Legend = memo(function Legend({ variant = "console", id, nodes = [], edges = [], isLoading = false, }: ExtendedLegendProps) { const isMobile = useIsMobile() const [isExpanded, setIsExpanded] = useState(true) const [isInitialized, setIsInitialized] = useState(false) // Load saved preference on client side useEffect(() => { if (!isInitialized) { const savedState = getCookie("legendCollapsed") if (savedState === "true") { setIsExpanded(false) } else if (savedState === "false") { setIsExpanded(true) } else { // Default: collapsed on mobile, expanded on desktop setIsExpanded(!isMobile) } setIsInitialized(true) } }, [isInitialized, isMobile]) // Save to cookie when state changes const handleToggleExpanded = (expanded: boolean) => { setIsExpanded(expanded) setCookie("legendCollapsed", expanded ? "false" : "true") } // Get container class based on variant and mobile state const getContainerClass = () => { if (variant === "console") { return isMobile ? styles.legendContainer.consoleMobile : styles.legendContainer.consoleDesktop } return isMobile ? styles.legendContainer.consumerMobile : styles.legendContainer.consumerDesktop } // Calculate stats const memoryCount = nodes.filter((n) => n.type === "memory").length const documentCount = nodes.filter((n) => n.type === "document").length const containerClass = isMobile && !isExpanded ? `${getContainerClass()} ${styles.mobileSize.collapsed}` : isMobile ? `${getContainerClass()} ${styles.mobileSize.expanded}` : getContainerClass() return (
{/* Glass effect background */}
{/* Mobile and Desktop collapsed state */} {!isExpanded && (
?
)} {/* Expanded state */} {isExpanded && ( <> {/* Header with toggle */}
Legend
{/* Stats Section */} {!isLoading && (
Statistics
{memoryCount} memories
{documentCount} documents
{edges.length} connections
)} {/* Node Types */}
Nodes
Document
Memory (latest)
Memory (older)
{/* Status Indicators */}
Status
Forgotten
Expiring soon
New memory
{/* Connection Types */}
Connections
Doc → Memory
Doc similarity
{/* Relation Types */}
Relations
{[ ["updates", colors.relations.updates], ["extends", colors.relations.extends], ["derives", colors.relations.derives], ].map(([label, color]) => (
{label}
))}
{/* Similarity Strength */}
Similarity
Weak
Strong
)}
) }) Legend.displayName = "Legend"