made the legends clickable in the graph view

This commit is contained in:
Arjun 2026-01-14 14:32:39 +05:30 committed by Ramnique Singh
parent 6dcd082561
commit a74b07d865

View file

@ -71,6 +71,7 @@ export function GraphView({ nodes, edges, isLoading, error, onSelectNode }: Grap
const [zoom, setZoom] = useState(1) const [zoom, setZoom] = useState(1)
const [hoveredNodeId, setHoveredNodeId] = useState<string | null>(null) const [hoveredNodeId, setHoveredNodeId] = useState<string | null>(null)
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [selectedGroup, setSelectedGroup] = useState<string | null>(null)
const [, forceRender] = useState(0) const [, forceRender] = useState(0)
const edgeList = useMemo( const edgeList = useMemo(
@ -83,11 +84,12 @@ export function GraphView({ nodes, edges, isLoading, error, onSelectNode }: Grap
return map return map
}, [nodes]) }, [nodes])
const legendItems = useMemo(() => { const legendItems = useMemo(() => {
const grouped = new Map<string, { label: string; color: string; stroke: string }>() const grouped = new Map<string, { group: string; label: string; color: string; stroke: string }>()
nodes.forEach((node) => { nodes.forEach((node) => {
const group = node.group || 'root' const group = node.group || 'root'
if (grouped.has(group)) return if (grouped.has(group)) return
grouped.set(group, { grouped.set(group, {
group,
label: group === 'root' ? 'knowledge' : group, label: group === 'root' ? 'knowledge' : group,
color: node.color, color: node.color,
stroke: node.stroke, stroke: node.stroke,
@ -483,16 +485,26 @@ export function GraphView({ nodes, edges, isLoading, error, onSelectNode }: Grap
<div className="mb-2 text-[0.7rem] font-semibold uppercase tracking-wide text-muted-foreground"> <div className="mb-2 text-[0.7rem] font-semibold uppercase tracking-wide text-muted-foreground">
Folders Folders
</div> </div>
<div className="grid gap-1.5"> <div className="grid gap-1">
{legendItems.map((item) => ( {legendItems.map((item) => {
<div key={item.label} className="flex items-center gap-2"> const isSelected = selectedGroup === item.group
<span return (
className="inline-flex h-2.5 w-2.5 rounded-full" <button
style={{ backgroundColor: item.color, boxShadow: `0 0 0 1px ${item.stroke}` }} key={item.group}
/> onClick={() => setSelectedGroup(isSelected ? null : item.group)}
<span className="truncate">{item.label}</span> className={`flex items-center gap-2 rounded px-1.5 py-1 text-left transition-colors hover:bg-foreground/10 ${
</div> isSelected ? 'bg-foreground/15' : ''
))} }`}
>
<span
className="inline-flex h-2.5 w-2.5 rounded-full"
style={{ backgroundColor: item.color, boxShadow: `0 0 0 1px ${item.stroke}` }}
/>
<span className="truncate">{item.label}</span>
{isSelected && <X className="ml-auto size-3 text-muted-foreground" />}
</button>
)
})}
</div> </div>
</div> </div>
) : null} ) : null}
@ -532,15 +544,23 @@ export function GraphView({ nodes, edges, isLoading, error, onSelectNode }: Grap
const source = displayPositions.get(edge.source) const source = displayPositions.get(edge.source)
const target = displayPositions.get(edge.target) const target = displayPositions.get(edge.target)
if (!source || !target) return null if (!source || !target) return null
const sourceGroup = nodeGroupMap.get(edge.source) ?? 'root'
const targetGroup = nodeGroupMap.get(edge.target) ?? 'root'
const isActiveEdge = activeNodeId const isActiveEdge = activeNodeId
? edge.source === activeNodeId || edge.target === activeNodeId ? edge.source === activeNodeId || edge.target === activeNodeId
: false : false
const isSearchEdge = searchMatchingNodes const isSearchEdge = searchMatchingNodes
? searchMatchingNodes.matches.has(edge.source) && searchMatchingNodes.matches.has(edge.target) ? searchMatchingNodes.matches.has(edge.source) && searchMatchingNodes.matches.has(edge.target)
: false : false
const isGroupEdge = selectedGroup
? sourceGroup === selectedGroup && targetGroup === selectedGroup
: false
let strokeOpacity = 0.4 let strokeOpacity = 0.4
let strokeWidth = 1 let strokeWidth = 1
if (searchMatchingNodes) { if (selectedGroup) {
strokeOpacity = isGroupEdge ? 0.6 : 0.05
strokeWidth = isGroupEdge ? 1.5 : 1
} else if (searchMatchingNodes) {
strokeOpacity = isSearchEdge ? 0.6 : 0.05 strokeOpacity = isSearchEdge ? 0.6 : 0.05
strokeWidth = isSearchEdge ? 1.5 : 1 strokeWidth = isSearchEdge ? 1.5 : 1
} else if (activeNodeId) { } else if (activeNodeId) {
@ -569,12 +589,16 @@ export function GraphView({ nodes, edges, isLoading, error, onSelectNode }: Grap
{nodes.map((node) => { {nodes.map((node) => {
const pos = displayPositions.get(node.id) const pos = displayPositions.get(node.id)
if (!pos) return null if (!pos) return null
const nodeGroup = node.group || 'root'
const isConnected = connectedNodes ? connectedNodes.has(node.id) : true const isConnected = connectedNodes ? connectedNodes.has(node.id) : true
const isSearchMatch = searchMatchingNodes ? searchMatchingNodes.matches.has(node.id) : true const isSearchMatch = searchMatchingNodes ? searchMatchingNodes.matches.has(node.id) : true
const isDirectMatch = searchMatchingNodes ? searchMatchingNodes.directMatches.has(node.id) : false const isDirectMatch = searchMatchingNodes ? searchMatchingNodes.directMatches.has(node.id) : false
const isPrimary = activeNodeId === node.id || isDirectMatch const isGroupMatch = selectedGroup ? nodeGroup === selectedGroup : true
const isPrimary = activeNodeId === node.id || isDirectMatch || (selectedGroup && isGroupMatch)
let nodeOpacity = 1 let nodeOpacity = 1
if (searchMatchingNodes) { if (selectedGroup) {
nodeOpacity = isGroupMatch ? 1 : 0.1
} else if (searchMatchingNodes) {
if (isDirectMatch) { if (isDirectMatch) {
nodeOpacity = 1 nodeOpacity = 1
} else if (isSearchMatch) { } else if (isSearchMatch) {