Symbol-Picker als Satellite-Fenster (statt Modal im Elemente-Panel)

UX-Verbesserung: Modal-Overlay im engen Elemente-Panel war unpraktisch.
Symbol-Picker oeffnet sich jetzt als eigenstaendiges Eto.Form-Fenster
(wie Library/Project-Settings).

Frontend:
- SymbolPicker bekommt embedded-Prop (Satellite-Mount vs Modal-Overlay)
- Neuer SymbolPickerApp Satellite-Wrapper (PANEL_PARAMS lesen + Bridge)
- main.jsx: 'symbol_picker' Mode-Routing
- ElementeApp: Symbol-Button ruft nur noch listLibrary() — Backend
  oeffnet das Fenster

Backend:
- _cmd_list_library oeffnet jetzt das Satellite-Window mit eigener
  Bridge (PICK -> CREATE_SYMBOL, CANCEL -> Close)
- PICK schliesst Fenster + triggert interactive GetPoint im Viewport

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 03:39:03 +02:00
parent 8184f559fc
commit de57c320c2
5 changed files with 168 additions and 115 deletions
+3 -23
View File
@@ -9,9 +9,8 @@ import {
openSwisstopo, openSwisstopoDialog, openOsmDialog,
updateElement, deleteElement, openElementeUebersicht, openElementeProperties,
saveOeffStyle, deleteOeffStyle,
listLibrary, createSymbol,
listLibrary,
} from './lib/rhinoBridge'
import SymbolPicker from './components/SymbolPicker'
const labelXs = {
fontSize: 10, fontWeight: 600, color: 'var(--text-muted)',
@@ -329,16 +328,7 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
const [treppeMenuOpen, setTreppeMenuOpen] = useState(false)
const [stuetzeMenuOpen, setStuetzeMenuOpen] = useState(false)
const [traegerMenuOpen, setTraegerMenuOpen] = useState(false)
const [symbolPickerOpen, setSymbolPickerOpen] = useState(false)
const [libraryItems, setLibraryItems] = useState([])
const treppeWrapperRef = useRef(null)
// Library-Items kommen via LIBRARY_LIST message vom Backend nach LIST_LIBRARY.
useEffect(() => {
onMessage('LIBRARY_LIST', ({ items }) => {
if (Array.isArray(items)) setLibraryItems(items)
})
}, [])
const dis = noGeschoss
const baseHint = (label) =>
noGeschoss ? 'Erst im Ebenen-Manager ein Geschoss aktivieren'
@@ -491,9 +481,9 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
<PillGroup label="Library">
<PillButton icon="inventory_2" label="Symbol"
hint={dis ? baseHint('Symbol') :
'Library-Item auswählen · im Viewport Punkt klicken zum Platzieren'}
'Library-Picker oeffnen · Item waehlen · im Viewport Punkt klicken zum Platzieren'}
disabled={dis}
onClick={() => { listLibrary(); setSymbolPickerOpen(true) }} />
onClick={() => listLibrary()} />
</PillGroup>
<PillGroup label="Importer">
@@ -507,16 +497,6 @@ function NeuesElementSection({ noGeschoss, activeName, elementsCount }) {
hint="Öffnet map.geo.admin.ch im Browser zur visuellen Inspektion"
onClick={() => openSwisstopo('both')} />
</PillGroup>
{symbolPickerOpen && (
<SymbolPicker
items={libraryItems}
onPick={(id) => {
setSymbolPickerOpen(false)
createSymbol(id)
}}
onClose={() => setSymbolPickerOpen(false)} />
)}
</div>
)
}