import { useState, useMemo, useEffect } from 'react' import Icon from './Icon' // Erzeugt ein vollstaendiges Draft-Array fuer einen Preset. // Layer die im Preset nicht enthalten sind werden auf Default (visible=true, // locked=false) gesetzt — sonst gibt es Schmutz wenn man zwischen Presets // hin- und herwechselt. function draftFromPreset(allLayers, preset) { if (!preset || !preset.layers) { return allLayers.map(l => ({ ...l })) } const map = {} ;(preset.layers || []).forEach(l => { map[l.id] = l }) return allLayers.map(l => { const ps = map[l.id] if (ps) return { ...l, visible: !!ps.visible, locked: !!ps.locked } return { ...l, visible: true, locked: false } }) } export default function AusschnittLayerDialog({ snapName, layers, presets, onSave, onClose, onSavePreset, onDeletePreset, embedded = false, }) { // Welche Kombination wird gerade angezeigt? null = aktueller Doc-State const [selectedPreset, setSelectedPreset] = useState(null) const [draft, setDraft] = useState(() => layers.map(l => ({ ...l }))) const [dirty, setDirty] = useState(false) const [filter, setFilter] = useState('') const [newName, setNewName] = useState('') // Wenn die Layer-Liste (von Backend) sich aendert wegen Doc-Update, // resetten wir den Draft — aber nur wenn nicht dirty. useEffect(() => { if (dirty) return if (selectedPreset === null) { setDraft(layers.map(l => ({ ...l }))) } else { const p = presets.find(p => p.name === selectedPreset) setDraft(draftFromPreset(layers, p)) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [layers]) const filtered = useMemo(() => { const f = filter.trim().toLowerCase() if (!f) return draft return draft.filter(l => (l.fullPath || l.name || '').toLowerCase().includes(f)) }, [draft, filter]) const pickPreset = (name) => { if (dirty && !window.confirm('Ungespeicherte Änderungen verwerfen?')) return setSelectedPreset(name || null) setDirty(false) if (!name) { setDraft(layers.map(l => ({ ...l }))) } else { const p = presets.find(p => p.name === name) setDraft(draftFromPreset(layers, p)) } } const toggle = (id, field) => { setDraft(d => d.map(l => l.id === id ? { ...l, [field]: !l[field] } : l)) setDirty(true) } const setAll = (field, value) => { setDraft(d => d.map(l => filtered.find(f => f.id === l.id) ? { ...l, [field]: value } : l)) setDirty(true) } const savePresetChanges = () => { if (!selectedPreset) return if (!window.confirm(`Änderungen an Kombination "${selectedPreset}" speichern?`)) return onSavePreset(selectedPreset, draft.map(l => ({ id: l.id, visible: l.visible, locked: l.locked }))) setDirty(false) } const saveAsNew = () => { const name = newName.trim() if (!name) return if (presets.some(p => p.name === name) && !window.confirm(`Kombination "${name}" überschreiben?`)) return onSavePreset(name, draft.map(l => ({ id: l.id, visible: l.visible, locked: l.locked }))) setSelectedPreset(name) setDirty(false) setNewName('') } const deleteSelected = () => { if (!selectedPreset) return if (!window.confirm(`Kombination "${selectedPreset}" löschen?`)) return onDeletePreset(selectedPreset) setSelectedPreset(null) setDirty(false) setDraft(layers.map(l => ({ ...l }))) } const applyToDoc = () => { if (dirty && selectedPreset && !window.confirm('Änderungen an dieser Kombination sind nicht gespeichert. Trotzdem auf das Dokument anwenden?')) return onSave(draft) } const wrapperStyle = embedded ? { position: 'absolute', inset: 0, display: 'flex' } : { position: 'absolute', inset: 0, zIndex: 150, background: 'var(--bg-overlay)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', paddingTop: 30 } const cardStyle = embedded ? { flex: 1, display: 'flex', flexDirection: 'column', background: 'var(--bg-dialog)', overflow: 'hidden' } : { background: 'var(--bg-dialog)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', boxShadow: 'var(--shadow-3)', width: 'calc(100% - 24px)', maxWidth: 480, maxHeight: 'calc(100vh - 60px)', display: 'flex', flexDirection: 'column', overflow: 'hidden' } return (
{/* Header — im embedded-Modus weggelassen (Satellite-Fenster hat schon seine native Title-Bar mit Close-Button) */} {!embedded && (
{snapName} {dirty && ( )}
)} {/* Preset-Auswahl */}
Kombination {selectedPreset && ( )}
{selectedPreset && (
Änderungen werden NICHT automatisch gespeichert.
)}
setNewName(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Enter') saveAsNew() }} placeholder="Aktuelle Auswahl als neue Kombination speichern…" style={{ flex: 1, fontSize: 10 }} />
{/* Such- und Bulk-Zeile */}
setFilter(ev.target.value)} placeholder="Filter..." style={{ flex: 1, fontSize: 10, padding: '3px 6px' }} />
{/* Layer-Liste */}
{filtered.length === 0 ? (
Keine Ebenen gefunden.
) : ( filtered.map(l => (
{l.fullPath || l.name}
)) )}
{/* Footer */}
{draft.filter(l => l.visible).length} / {draft.length} sichtbar
) }