import { useEffect, useState, useMemo } from 'react' import Icon from './components/Icon' import { BarToggle, BarButton } from './components/BarControls' import { onMessage, notifyReady, send } from './lib/rhinoBridge' // BIM-artige Project-Tree-Ansicht: Geschoss → Kind → Element. // Klick → selektiert in Rhino. Shift-Klick → Zoom-to-Element. const KIND_ORDER = [ 'wand', 'decke', 'dach', 'fenster', 'tuer', 'aussparung', 'treppe', 'stuetze', 'traeger', 'raum', ] const KIND_META = { wand: { icon: 'view_week', label: 'Wände', color: '#888888' }, decke: { icon: 'layers', label: 'Decken', color: '#605850' }, dach: { icon: 'roofing', label: 'Dächer', color: '#7a4a3a' }, fenster: { icon: 'window', label: 'Fenster', color: '#5080c8' }, tuer: { icon: 'sensor_door', label: 'Türen', color: '#5080c8' }, aussparung: { icon: 'rectangle', label: 'Aussparungen', color: '#a89070' }, treppe: { icon: 'stairs', label: 'Treppen', color: '#c87050' }, stuetze: { icon: 'square_foot', label: 'Stützen', color: '#c87050' }, traeger: { icon: 'horizontal_rule', label: 'Träger', color: '#a87858' }, raum: { icon: 'crop_free', label: 'Räume', color: '#5fa896' }, } export default function ElementeUebersichtApp() { const [state, setState] = useState({ geschosse: [], items: [] }) const [expanded, setExpanded] = useState({}) // { 'g_id': true, 'g_id::kind': true } const [filter, setFilter] = useState('') // text search const [filterKind, setFilterKind] = useState('') // single kind filter useEffect(() => { onMessage('STATE', (s) => setState(s || { geschosse: [], items: [] })) notifyReady() }, []) const items = state.items || [] const geschosse = state.geschosse || [] const filtered = useMemo(() => { let r = items if (filterKind) r = r.filter(it => it.kind === filterKind) if (filter.trim()) { const q = filter.toLowerCase() r = r.filter(it => (it.name || '').toLowerCase().includes(q) || (it.info || '').toLowerCase().includes(q) || it.kind.toLowerCase().includes(q)) } return r }, [items, filter, filterKind]) // Pre-grouped: g_id -> kind -> [items] const tree = useMemo(() => { const out = {} for (const it of filtered) { const g = it.geschossId || '__keingeschoss__' const k = it.kind if (!out[g]) out[g] = {} if (!out[g][k]) out[g][k] = [] out[g][k].push(it) } return out }, [filtered]) // Counts per kind across all (unfiltered) items — für Filter-Chips const kindCounts = useMemo(() => { const m = {} for (const it of items) m[it.kind] = (m[it.kind] || 0) + 1 return m }, [items]) const toggle = (key) => setExpanded(s => ({ ...s, [key]: !s[key] })) const expandAll = () => { const next = {} for (const g of geschosse) { next[g.id] = true for (const k of KIND_ORDER) { if (tree[g.id]?.[k]) next[g.id + '::' + k] = true } } setExpanded(next) } const collapseAll = () => setExpanded({}) const onSelect = (item, ev) => { if (ev.shiftKey) { send('ZOOM_TO_ELEMENT', { objectId: item.objectId }) } else { send('SELECT_ELEMENT', { objectId: item.objectId }) } } const totalCount = items.length const filteredCount = filtered.length return (