Stempel-Stil-Bulk-Apply + Manager-Tab in ProjectSettings
PHASE 1 — Bulk-Apply auf mehrere selektierte Raeume: - Backend _cmd_apply_raum_stil: leere ids im Patch → nimmt automatisch alle aktuell SELEKTIERTEN raum_outlines aus dem Doc (Bulk-Fallback) - Frontend sendet leere ids fuer die Default-Bulk-Variante. User selektiert N Raeume im Viewport → klickt Stil im Properties-Picker → Stil wird auf alle angewendet. Inkludiert immer den Properties-Raum. PHASE 2 — Stil-Manager als Settings-Tab: - Neuer Tab "Raumstile" in ProjectSettings-Dialog - Liste aller Stile mit Drag-Reorder (HTML5 native), Inline-Rename, Duplicate (content_copy-Icon), Delete (mit Confirm) - Mini-Preview: zeigt Layout-Struktur (z.B. "nummer·name / funktion / area") und der Name wird mit Font/Bold/Italic des Stils gerendert als Vorschau - Backend _cmd_reorder_raum_stile + _cmd_duplicate_raum_stil in elemente.py - ProjectSettings-Bridge dispatcht direkt zu elemente.load/save_raum_stempel_stile (kein Roundtrip via Elemente-Bridge noetig) - STILE_UPDATED-Message nach jeder Op pusht die neue Liste zum Dialog - params bei _open_project_settings enthalten jetzt raumStempelStile + fonts Bridge-Exports: reorderRaumStile / duplicateRaumStil in rhinoBridge.js
This commit is contained in:
+68
-4
@@ -6457,6 +6457,12 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
# Wendet einen gespeicherten Stil auf die im Patch genannten
|
# Wendet einen gespeicherten Stil auf die im Patch genannten
|
||||||
# raum_outline element_ids an. p = {stilId, ids=[…]}.
|
# raum_outline element_ids an. p = {stilId, ids=[…]}.
|
||||||
self._cmd_apply_raum_stil(p)
|
self._cmd_apply_raum_stil(p)
|
||||||
|
elif t == "REORDER_RAUM_STILE":
|
||||||
|
# p = {ids: [stil_id, ...]} in neuer Reihenfolge
|
||||||
|
self._cmd_reorder_raum_stile(p)
|
||||||
|
elif t == "DUPLICATE_RAUM_STIL":
|
||||||
|
# p = {id, newName?} → kopiert Stil mit neuer uuid + Name
|
||||||
|
self._cmd_duplicate_raum_stil(p)
|
||||||
elif t == "OPEN_ELEMENTE_UEBERSICHT":
|
elif t == "OPEN_ELEMENTE_UEBERSICHT":
|
||||||
try:
|
try:
|
||||||
import elemente_uebersicht
|
import elemente_uebersicht
|
||||||
@@ -8601,16 +8607,74 @@ class ElementeBridge(panel_base.BaseBridge):
|
|||||||
print("[ELEMENTE] Stempel-Stil {} geloescht".format(sid))
|
print("[ELEMENTE] Stempel-Stil {} geloescht".format(sid))
|
||||||
self._send_state()
|
self._send_state()
|
||||||
|
|
||||||
|
def _cmd_reorder_raum_stile(self, p):
|
||||||
|
"""Setzt die Reihenfolge der Stile auf die uebergebene id-Liste.
|
||||||
|
Nicht-erwaehnte Stile bleiben am Ende erhalten."""
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
new_order = p.get("ids") or []
|
||||||
|
if not isinstance(new_order, list) or not new_order: return
|
||||||
|
stile = load_raum_stempel_stile(doc)
|
||||||
|
by_id = {s.get("id"): s for s in stile if s.get("id")}
|
||||||
|
ordered = []
|
||||||
|
seen = set()
|
||||||
|
for sid in new_order:
|
||||||
|
if sid in by_id and sid not in seen:
|
||||||
|
ordered.append(by_id[sid]); seen.add(sid)
|
||||||
|
# Reste anhaengen
|
||||||
|
for s in stile:
|
||||||
|
sid = s.get("id")
|
||||||
|
if sid and sid not in seen:
|
||||||
|
ordered.append(s); seen.add(sid)
|
||||||
|
save_raum_stempel_stile(doc, ordered)
|
||||||
|
self._send_state()
|
||||||
|
|
||||||
|
def _cmd_duplicate_raum_stil(self, p):
|
||||||
|
"""Kopiert einen Stil mit neuer uuid. Payload: {id, newName?}."""
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
sid = (p.get("id") or "").strip()
|
||||||
|
if not sid: return
|
||||||
|
stile = load_raum_stempel_stile(doc)
|
||||||
|
src = next((s for s in stile if s.get("id") == sid), None)
|
||||||
|
if src is None: return
|
||||||
|
new_name = (p.get("newName") or "").strip() or (
|
||||||
|
"{} (Kopie)".format(src.get("name", "Stil")))
|
||||||
|
new_stil = dict(src)
|
||||||
|
new_stil["id"] = "stil_" + uuid.uuid4().hex[:8]
|
||||||
|
new_stil["name"] = new_name
|
||||||
|
# Einfuegen direkt nach Original
|
||||||
|
try:
|
||||||
|
i = next(j for j, s in enumerate(stile) if s.get("id") == sid)
|
||||||
|
stile.insert(i + 1, new_stil)
|
||||||
|
except StopIteration:
|
||||||
|
stile.append(new_stil)
|
||||||
|
save_raum_stempel_stile(doc, stile)
|
||||||
|
print("[ELEMENTE] Stempel-Stil '{}' dupliziert -> '{}'".format(
|
||||||
|
src.get("name"), new_name))
|
||||||
|
self._send_state()
|
||||||
|
|
||||||
def _cmd_apply_raum_stil(self, p):
|
def _cmd_apply_raum_stil(self, p):
|
||||||
"""Wendet einen Stil auf eine Liste von raum_outline-Element-IDs
|
"""Wendet einen Stil auf raum_outline-Element-IDs an. Payload:
|
||||||
an. Payload: {stilId, ids: [element_id, ...]}. Schreibt die Stil-
|
{stilId, ids: [element_id, ...]}. Wenn ids leer/missing → nimmt
|
||||||
Felder auf die Source-Outlines + triggert Regen pro Raum.
|
alle aktuell SELEKTIERTEN raum_outline-Objekte (Bulk-Apply).
|
||||||
|
Schreibt Stil-Felder auf die Source-Outlines + triggert Regen.
|
||||||
"""
|
"""
|
||||||
doc = Rhino.RhinoDoc.ActiveDoc
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
if doc is None: return
|
if doc is None: return
|
||||||
sid = (p.get("stilId") or "").strip()
|
sid = (p.get("stilId") or "").strip()
|
||||||
ids = p.get("ids") or []
|
ids = p.get("ids") or []
|
||||||
if not sid or not ids: return
|
if not sid: return
|
||||||
|
# Bulk-Fallback: keine ids im Patch → alle selektierten Raeume
|
||||||
|
if not ids:
|
||||||
|
for obj in doc.Objects:
|
||||||
|
try:
|
||||||
|
if obj.IsSelected(False) <= 0: continue
|
||||||
|
m = _read_meta(obj)
|
||||||
|
if m and m.get("type") == "raum_outline":
|
||||||
|
ids.append(m["id"])
|
||||||
|
except Exception: pass
|
||||||
|
if not ids: return
|
||||||
stile = load_raum_stempel_stile(doc)
|
stile = load_raum_stempel_stile(doc)
|
||||||
stil = next((s for s in stile if s.get("id") == sid), None)
|
stil = next((s for s in stile if s.get("id") == sid), None)
|
||||||
if stil is None:
|
if stil is None:
|
||||||
|
|||||||
@@ -961,6 +961,14 @@ class EbenenBridge(panel_base.BaseBridge):
|
|||||||
lib_root = library.library_root()
|
lib_root = library.library_root()
|
||||||
except Exception:
|
except Exception:
|
||||||
lib_items = []; lib_root = ""
|
lib_items = []; lib_root = ""
|
||||||
|
# Raumstempel-Stile + Fonts aus elemente fuer den "Raumstile"-Tab
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
raum_stile = _el.load_raum_stempel_stile(doc)
|
||||||
|
fonts_list = _el._list_system_fonts()
|
||||||
|
except Exception:
|
||||||
|
raum_stile = []
|
||||||
|
fonts_list = []
|
||||||
params = {
|
params = {
|
||||||
"defaults": current.get("defaults", {}),
|
"defaults": current.get("defaults", {}),
|
||||||
"project": current.get("project", {}),
|
"project": current.get("project", {}),
|
||||||
@@ -971,6 +979,8 @@ class EbenenBridge(panel_base.BaseBridge):
|
|||||||
"linetypes": _list_linetypes_full(doc),
|
"linetypes": _list_linetypes_full(doc),
|
||||||
"libraryItems": lib_items,
|
"libraryItems": lib_items,
|
||||||
"libraryRoot": lib_root,
|
"libraryRoot": lib_root,
|
||||||
|
"raumStempelStile": raum_stile,
|
||||||
|
"fonts": fonts_list,
|
||||||
}
|
}
|
||||||
def on_save(updated):
|
def on_save(updated):
|
||||||
doc2 = Rhino.RhinoDoc.ActiveDoc
|
doc2 = Rhino.RhinoDoc.ActiveDoc
|
||||||
@@ -1078,6 +1088,108 @@ class EbenenBridge(panel_base.BaseBridge):
|
|||||||
self._delete_library_item(p)
|
self._delete_library_item(p)
|
||||||
elif t == "SAVE_SELECTION_AS_LIBRARY":
|
elif t == "SAVE_SELECTION_AS_LIBRARY":
|
||||||
self._save_selection_as_library(p)
|
self._save_selection_as_library(p)
|
||||||
|
elif t == "SAVE_RAUM_STIL":
|
||||||
|
self._raum_stil_save(p)
|
||||||
|
elif t == "DELETE_RAUM_STIL":
|
||||||
|
self._raum_stil_delete(p)
|
||||||
|
elif t == "DUPLICATE_RAUM_STIL":
|
||||||
|
self._raum_stil_duplicate(p)
|
||||||
|
elif t == "REORDER_RAUM_STILE":
|
||||||
|
self._raum_stil_reorder(p)
|
||||||
|
|
||||||
|
# ---- Raumstempel-Stile (Settings-Tab "Raumstile") ----
|
||||||
|
# Dispatcht direkt zu elemente.py — kein Roundtrip via Elemente-
|
||||||
|
# Bridge noetig. Nach jeder Op wird die neue Liste an's Frontend
|
||||||
|
# gepushed via STILE_UPDATED.
|
||||||
|
def _raum_stil_send_updated(self):
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
d = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
self.send("STILE_UPDATED",
|
||||||
|
{"raumStempelStile": _el.load_raum_stempel_stile(d)})
|
||||||
|
except Exception as ex:
|
||||||
|
print("[PROJECT-SETTINGS] STILE_UPDATED:", ex)
|
||||||
|
|
||||||
|
def _raum_stil_save(self, p):
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
d = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
name = (p.get("name") or "").strip()
|
||||||
|
if not name: return
|
||||||
|
sid = (p.get("id") or "").strip() or (
|
||||||
|
"stil_" + __import__("uuid").uuid4().hex[:8])
|
||||||
|
stile = _el.load_raum_stempel_stile(d)
|
||||||
|
settings = p.get("settings") or {}
|
||||||
|
new_stil = {"id": sid, "name": name}
|
||||||
|
for f in _el._RAUM_STIL_FIELDS:
|
||||||
|
if f in settings: new_stil[f] = settings[f]
|
||||||
|
found = False
|
||||||
|
for i, s in enumerate(stile):
|
||||||
|
if s.get("id") == sid:
|
||||||
|
stile[i] = new_stil; found = True; break
|
||||||
|
if not found: stile.append(new_stil)
|
||||||
|
_el.save_raum_stempel_stile(d, stile)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[PROJECT-SETTINGS] raum_stil save:", ex)
|
||||||
|
self._raum_stil_send_updated()
|
||||||
|
|
||||||
|
def _raum_stil_delete(self, p):
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
d = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
sid = (p.get("id") or "").strip()
|
||||||
|
if not sid: return
|
||||||
|
stile = _el.load_raum_stempel_stile(d)
|
||||||
|
stile = [s for s in stile if s.get("id") != sid]
|
||||||
|
_el.save_raum_stempel_stile(d, stile)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[PROJECT-SETTINGS] raum_stil delete:", ex)
|
||||||
|
self._raum_stil_send_updated()
|
||||||
|
|
||||||
|
def _raum_stil_duplicate(self, p):
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
import uuid as _uuid
|
||||||
|
d = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
sid = (p.get("id") or "").strip()
|
||||||
|
if not sid: return
|
||||||
|
stile = _el.load_raum_stempel_stile(d)
|
||||||
|
src = next((s for s in stile if s.get("id") == sid), None)
|
||||||
|
if src is None: return
|
||||||
|
new_name = (p.get("newName") or "").strip() or (
|
||||||
|
"{} (Kopie)".format(src.get("name", "Stil")))
|
||||||
|
new_stil = dict(src)
|
||||||
|
new_stil["id"] = "stil_" + _uuid.uuid4().hex[:8]
|
||||||
|
new_stil["name"] = new_name
|
||||||
|
try:
|
||||||
|
i = next(j for j, s in enumerate(stile) if s.get("id") == sid)
|
||||||
|
stile.insert(i + 1, new_stil)
|
||||||
|
except StopIteration:
|
||||||
|
stile.append(new_stil)
|
||||||
|
_el.save_raum_stempel_stile(d, stile)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[PROJECT-SETTINGS] raum_stil duplicate:", ex)
|
||||||
|
self._raum_stil_send_updated()
|
||||||
|
|
||||||
|
def _raum_stil_reorder(self, p):
|
||||||
|
try:
|
||||||
|
import elemente as _el
|
||||||
|
d = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
new_order = p.get("ids") or []
|
||||||
|
if not isinstance(new_order, list) or not new_order: return
|
||||||
|
stile = _el.load_raum_stempel_stile(d)
|
||||||
|
by_id = {s.get("id"): s for s in stile if s.get("id")}
|
||||||
|
ordered = []; seen = set()
|
||||||
|
for i in new_order:
|
||||||
|
if i in by_id and i not in seen:
|
||||||
|
ordered.append(by_id[i]); seen.add(i)
|
||||||
|
for s in stile:
|
||||||
|
if s.get("id") and s["id"] not in seen:
|
||||||
|
ordered.append(s); seen.add(s["id"])
|
||||||
|
_el.save_raum_stempel_stile(d, ordered)
|
||||||
|
except Exception as ex:
|
||||||
|
print("[PROJECT-SETTINGS] raum_stil reorder:", ex)
|
||||||
|
self._raum_stil_send_updated()
|
||||||
def _pick_texture(self, payload):
|
def _pick_texture(self, payload):
|
||||||
slot = payload.get("slot") or "diffuse"
|
slot = payload.get("slot") or "diffuse"
|
||||||
try:
|
try:
|
||||||
|
|||||||
+4
-1
@@ -914,7 +914,10 @@ function RaumProperties({ raum, geschosse, onUpdate, onDelete, hatchPatterns, fo
|
|||||||
deleteRaumStil(activeStilId)
|
deleteRaumStil(activeStilId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (val) applyRaumStil(val, [raum.id])
|
// Empty ids → Backend nutzt aktuelle Rhino-Selection (Bulk-Apply auf
|
||||||
|
// alle selektierten raum_outlines). Inkludiert immer den aktuellen
|
||||||
|
// Raum (er ist ja gerade in den Properties sichtbar = selektiert).
|
||||||
|
if (val) applyRaumStil(val, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
const [name, setName] = useState(raum.name || 'Raum')
|
const [name, setName] = useState(raum.name || 'Raum')
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
renameHatch, deleteHatch, importHatchFile,
|
renameHatch, deleteHatch, importHatchFile,
|
||||||
listLibraryItems, addLibraryFile, updateLibraryItem, deleteLibraryItem,
|
listLibraryItems, addLibraryFile, updateLibraryItem, deleteLibraryItem,
|
||||||
saveSelectionAsLibrary,
|
saveSelectionAsLibrary,
|
||||||
|
saveRaumStil, deleteRaumStil, duplicateRaumStil, reorderRaumStile,
|
||||||
} from '../lib/rhinoBridge'
|
} from '../lib/rhinoBridge'
|
||||||
|
|
||||||
/* Field — Stack-Layout fuer komplexe Inputs (mehrere Felder nebeneinander) */
|
/* Field — Stack-Layout fuer komplexe Inputs (mehrere Felder nebeneinander) */
|
||||||
@@ -646,6 +647,11 @@ export default function ProjectSettingsDialog({
|
|||||||
const [libRoot, setLibRoot] = useState(initial.libraryRoot || '')
|
const [libRoot, setLibRoot] = useState(initial.libraryRoot || '')
|
||||||
const [selLib, setSelLib] = useState(null)
|
const [selLib, setSelLib] = useState(null)
|
||||||
const builtin = initial.builtinMaterials || []
|
const builtin = initial.builtinMaterials || []
|
||||||
|
// Raumstile-State: kommt von initial + wird per STATE-Refresh aktualisiert
|
||||||
|
// wenn Backend CRUD-Op fertig ist. Drag-Reorder lokal + commit beim Drop.
|
||||||
|
const [raumStile, setRaumStile] = useState(initial.raumStempelStile || [])
|
||||||
|
const [dragStilIdx, setDragStilIdx] = useState(null)
|
||||||
|
const fontsList = initial.fonts || []
|
||||||
|
|
||||||
// Aktuell ausgewaehltes Material aus Selection ableiten
|
// Aktuell ausgewaehltes Material aus Selection ableiten
|
||||||
const selectedMat = (() => {
|
const selectedMat = (() => {
|
||||||
@@ -682,6 +688,9 @@ export default function ProjectSettingsDialog({
|
|||||||
onMessage('LIBRARY_ERROR', ({ msg }) => {
|
onMessage('LIBRARY_ERROR', ({ msg }) => {
|
||||||
if (msg) alert(msg)
|
if (msg) alert(msg)
|
||||||
})
|
})
|
||||||
|
onMessage('STILE_UPDATED', ({ raumStempelStile }) => {
|
||||||
|
if (Array.isArray(raumStempelStile)) setRaumStile(raumStempelStile)
|
||||||
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Backend-File-Picker-Antwort: aktualisiert das Slot im aktuell
|
// Backend-File-Picker-Antwort: aktualisiert das Slot im aktuell
|
||||||
@@ -756,6 +765,7 @@ export default function ProjectSettingsDialog({
|
|||||||
{ key: 'linetypes', label: 'Linientypen' },
|
{ key: 'linetypes', label: 'Linientypen' },
|
||||||
{ key: 'hatches', label: 'Schraffuren' },
|
{ key: 'hatches', label: 'Schraffuren' },
|
||||||
{ key: 'symbols', label: 'Symbole' },
|
{ key: 'symbols', label: 'Symbole' },
|
||||||
|
{ key: 'raumstile', label: 'Raumstile' },
|
||||||
]} active={tab} onChange={setTab} />
|
]} active={tab} onChange={setTab} />
|
||||||
|
|
||||||
{/* Body */}
|
{/* Body */}
|
||||||
@@ -1341,6 +1351,116 @@ export default function ProjectSettingsDialog({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{tab === 'raumstile' && (
|
||||||
|
<div style={{ maxWidth: 760 }}>
|
||||||
|
<div style={{ fontSize: 10, color: 'var(--text-muted)',
|
||||||
|
padding: '6px 0 10px', lineHeight: 1.5 }}>
|
||||||
|
Raumstempel-Stile (Presets). Werden via Raum-Properties
|
||||||
|
erstellt ("+ Aktuelle Settings als Stil speichern"), hier nur
|
||||||
|
verwaltet. Drag zum Umsortieren — die Reihenfolge entspricht
|
||||||
|
dem Dropdown in den Raum-Properties.
|
||||||
|
</div>
|
||||||
|
{raumStile.length === 0 ? (
|
||||||
|
<div style={{ padding: 30, textAlign: 'center',
|
||||||
|
color: 'var(--text-muted)', fontSize: 11 }}>
|
||||||
|
Noch keine Stile gespeichert. Im Raum-Properties einen Raum
|
||||||
|
konfigurieren und "+ Aktuelle Settings als Stil speichern".
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||||
|
{raumStile.map((s, idx) => {
|
||||||
|
const isDrag = dragStilIdx === idx
|
||||||
|
return (
|
||||||
|
<div key={s.id}
|
||||||
|
draggable
|
||||||
|
onDragStart={(e) => {
|
||||||
|
setDragStilIdx(idx)
|
||||||
|
try { e.dataTransfer.effectAllowed = 'move' } catch (_) {}
|
||||||
|
}}
|
||||||
|
onDragOver={(e) => { e.preventDefault() }}
|
||||||
|
onDrop={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (dragStilIdx == null || dragStilIdx === idx) return
|
||||||
|
const next = [...raumStile]
|
||||||
|
const [moved] = next.splice(dragStilIdx, 1)
|
||||||
|
next.splice(idx, 0, moved)
|
||||||
|
setRaumStile(next)
|
||||||
|
reorderRaumStile(next.map(x => x.id))
|
||||||
|
setDragStilIdx(null)
|
||||||
|
}}
|
||||||
|
onDragEnd={() => setDragStilIdx(null)}
|
||||||
|
style={{
|
||||||
|
display: 'flex', alignItems: 'center', gap: 8,
|
||||||
|
padding: '8px 10px',
|
||||||
|
background: isDrag ? 'var(--bg-item-active)' : 'var(--bg-input)',
|
||||||
|
border: '1px solid var(--border)',
|
||||||
|
borderRadius: 'var(--r)',
|
||||||
|
cursor: 'grab',
|
||||||
|
opacity: isDrag ? 0.5 : 1,
|
||||||
|
transition: 'opacity 0.15s',
|
||||||
|
}}>
|
||||||
|
<Icon name="drag_indicator" size={14}
|
||||||
|
style={{ color: 'var(--text-muted)' }} />
|
||||||
|
<input type="text" value={s.name}
|
||||||
|
onChange={(e) => {
|
||||||
|
const next = raumStile.map(x =>
|
||||||
|
x.id === s.id ? { ...x, name: e.target.value } : x)
|
||||||
|
setRaumStile(next)
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
const newName = (e.target.value || '').trim()
|
||||||
|
if (newName && newName !== s.name) {
|
||||||
|
// Re-save mit gleicher id → effektiv rename
|
||||||
|
const { id, name: _n, ...rest } = s
|
||||||
|
saveRaumStil(id, newName, rest)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') e.target.blur() }}
|
||||||
|
style={{ flex: 1, fontSize: 11, height: BAR_H,
|
||||||
|
padding: '0 10px',
|
||||||
|
fontFamily: s.font ? `"${s.font}", monospace` : 'inherit',
|
||||||
|
fontWeight: s.bold ? 700 : 400,
|
||||||
|
fontStyle: s.italic ? 'italic' : 'normal' }} />
|
||||||
|
{/* Mini-Preview: Felder die in Layout vorkommen */}
|
||||||
|
<span style={{ fontSize: 9,
|
||||||
|
color: 'var(--text-muted)',
|
||||||
|
fontFamily: 'DM Mono, monospace',
|
||||||
|
minWidth: 100, textAlign: 'right' }}>
|
||||||
|
{(s.layout && s.layout.length)
|
||||||
|
? s.layout.map(row => row.join('·')).join(' / ')
|
||||||
|
: '—'}
|
||||||
|
</span>
|
||||||
|
<button onClick={() => duplicateRaumStil(s.id)}
|
||||||
|
title="Duplizieren"
|
||||||
|
style={{
|
||||||
|
background: 'transparent', border: '1px solid var(--border)',
|
||||||
|
borderRadius: 'var(--r)', cursor: 'pointer',
|
||||||
|
padding: '4px 8px', fontSize: 10,
|
||||||
|
color: 'var(--text-primary)',
|
||||||
|
}}>
|
||||||
|
<Icon name="content_copy" size={11} />
|
||||||
|
</button>
|
||||||
|
<button onClick={() => {
|
||||||
|
if (window.confirm(`Stil "${s.name}" löschen?`))
|
||||||
|
deleteRaumStil(s.id)
|
||||||
|
}}
|
||||||
|
title="Löschen"
|
||||||
|
style={{
|
||||||
|
background: 'transparent', border: '1px solid var(--border)',
|
||||||
|
borderRadius: 'var(--r)', cursor: 'pointer',
|
||||||
|
padding: '4px 8px', fontSize: 10,
|
||||||
|
color: 'var(--text-danger, #c44)',
|
||||||
|
}}>
|
||||||
|
<Icon name="delete" size={11} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer — Pill-Buttons */}
|
{/* Footer — Pill-Buttons */}
|
||||||
|
|||||||
@@ -252,6 +252,10 @@ export function deleteRaumStil(id) { send('DELETE_RAUM_STIL', { id }) }
|
|||||||
export function applyRaumStil(stilId, ids) {
|
export function applyRaumStil(stilId, ids) {
|
||||||
send('APPLY_RAUM_STIL', { stilId, ids })
|
send('APPLY_RAUM_STIL', { stilId, ids })
|
||||||
}
|
}
|
||||||
|
export function reorderRaumStile(ids) { send('REORDER_RAUM_STILE', { ids }) }
|
||||||
|
export function duplicateRaumStil(id, newName) {
|
||||||
|
send('DUPLICATE_RAUM_STIL', { id, newName })
|
||||||
|
}
|
||||||
export function setSectionStyle(enabled, source, color, pattern, scale, rotation,
|
export function setSectionStyle(enabled, source, color, pattern, scale, rotation,
|
||||||
opts = {}) {
|
opts = {}) {
|
||||||
send('SET_SECTION_STYLE', {
|
send('SET_SECTION_STYLE', {
|
||||||
|
|||||||
Reference in New Issue
Block a user