80 lines
2.9 KiB
JavaScript
80 lines
2.9 KiB
JavaScript
import { useState } from 'react'
|
|
import { VARIABLES, CATEGORIES } from '../engine/variables.js'
|
|
import { PaletteCard } from './VariableCard.jsx'
|
|
|
|
export function VariablePalette({ workspaceVarIds, onAddVariable }) {
|
|
const [search, setSearch] = useState('')
|
|
const [collapsed, setCollapsed] = useState({})
|
|
|
|
const toggleCategory = (cat) =>
|
|
setCollapsed(prev => ({ ...prev, [cat]: !prev[cat] }))
|
|
|
|
const q = search.toLowerCase()
|
|
const filtered = (varIds) =>
|
|
varIds.filter(id => {
|
|
if (!q) return true
|
|
const v = VARIABLES[id]
|
|
return (
|
|
v.name.toLowerCase().includes(q) ||
|
|
v.symbol.toLowerCase().includes(q) ||
|
|
v.id.toLowerCase().includes(q)
|
|
)
|
|
})
|
|
|
|
// Group vars by category
|
|
const byCategory = {}
|
|
for (const [id, v] of Object.entries(VARIABLES)) {
|
|
if (!byCategory[v.category]) byCategory[v.category] = []
|
|
byCategory[v.category].push(id)
|
|
}
|
|
|
|
return (
|
|
<aside className="flex flex-col h-full bg-slate-900 border-r border-slate-700 w-64 shrink-0">
|
|
<div className="p-3 border-b border-slate-700">
|
|
<h2 className="text-slate-300 font-semibold text-sm mb-2 tracking-wide uppercase">Variables</h2>
|
|
<input
|
|
type="text"
|
|
value={search}
|
|
onChange={e => setSearch(e.target.value)}
|
|
placeholder="Search…"
|
|
className="w-full bg-slate-800 border border-slate-600 rounded-md px-2 py-1.5 text-sm text-slate-200 placeholder-slate-500 outline-none focus:border-blue-500"
|
|
/>
|
|
</div>
|
|
<div className="flex-1 overflow-y-auto p-2 space-y-1">
|
|
{CATEGORIES.map(cat => {
|
|
const ids = filtered(byCategory[cat] ?? [])
|
|
if (ids.length === 0) return null
|
|
const isCollapsed = collapsed[cat]
|
|
return (
|
|
<div key={cat}>
|
|
<button
|
|
onClick={() => toggleCategory(cat)}
|
|
className="w-full flex items-center justify-between px-2 py-1.5 rounded-md text-xs font-semibold text-slate-400 uppercase tracking-wider hover:text-slate-200 hover:bg-slate-800 transition-colors"
|
|
>
|
|
<span>{cat}</span>
|
|
<span>{isCollapsed ? '▶' : '▼'}</span>
|
|
</button>
|
|
{!isCollapsed && (
|
|
<div className="space-y-1 mt-1 ml-1">
|
|
{ids.map(id => (
|
|
<div
|
|
key={id}
|
|
onDoubleClick={() => !workspaceVarIds.includes(id) && onAddVariable(id)}
|
|
title={VARIABLES[id].description}
|
|
>
|
|
<PaletteCard varId={id} isInWorkspace={workspaceVarIds.includes(id)} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
<div className="p-2 border-t border-slate-700 text-xs text-slate-500 text-center">
|
|
Drag or double-click to add
|
|
</div>
|
|
</aside>
|
|
)
|
|
}
|