Files
DOSSIER-STANDALONE/src/panels/SitePanel.tsx
T
karim a35a4fcdff Native Selects auf einheitliche Dropdown-Komponente umgestellt
Mehrere Stellen (ResourceManager SelectField + Material-Browser,
ImportDialog, AttributesPanel, SitePanel, ToolsPanel,
DisplayModeSelect, RichTextEditor) nutzten noch native <select>, deren
Optionsliste vom Betriebssystem gerendert wird und optisch nicht zur
eigenen Dropdown-Komponente (dunkles Kontextmenü-Popover) passt. Jetzt
durchgaengig dieselbe Optik.
2026-07-04 05:01:03 +02:00

139 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Inhalts-Panel „Gelände & Kontext" — verwaltet die Kontext-Schicht
// (importierte Meshes, Höhenlinien-Sätze, abgeleitetes Gelände-TIN). Daten/
// Handler kommen über usePanelHost (kein Prop-Drilling).
//
// Aufbau:
// • Aktions-Zeile: „DXF importieren" (öffnet den in App montierten Datei-
// Dialog) + „Gelände erzeugen" (aus dem gewählten Kontur-Satz).
// • Liste der Kontext-Objekte: Name + Typ-Badge + „Entfernen".
// • DWG-Hinweis am Fuß.
//
// Bezeichner englisch, UI-Text/Kommentare deutsch (CONVENTIONS.md). Alle sichtbaren
// Texte über t(...).
import { useState } from "react";
import { t } from "../i18n";
import type { TranslationKey } from "../i18n";
import { usePanelHost } from "./host";
import type { ContextObject } from "../model/types";
import { ContextImportDialog } from "../ui/ContextImportDialog";
import { Dropdown } from "../ui/Dropdown";
/** Typ-spezifisches Badge-Label (i18n-Key) je Kontext-Objekt-Art. */
function typeBadgeKey(obj: ContextObject): TranslationKey {
switch (obj.type) {
case "importedMesh":
return "site.type.mesh";
case "contourSet":
return "site.type.contours";
case "terrainMesh":
return "site.type.terrain";
}
}
export function SitePanel() {
const host = usePanelHost();
const objects = host.contextObjects;
const contourSets = objects.filter((o) => o.type === "contourSet");
// Standort-Import-Dialog (geo.admin/OSM) offen?
const [ctxImportOpen, setCtxImportOpen] = useState(false);
// Gewählter Kontur-Satz für „Gelände erzeugen" (default: erster vorhandener).
const [selectedSet, setSelectedSet] = useState<string>("");
const effectiveSet =
selectedSet && contourSets.some((c) => c.id === selectedSet)
? selectedSet
: (contourSets[0]?.id ?? "");
const onGenerate = () => {
if (!effectiveSet) return;
const id = host.onGenerateTerrain(effectiveSet);
if (id === null) {
// Kein sinnvolles TIN — ruhiger Hinweis (keine harte Fehlerbox).
// eslint-disable-next-line no-alert
alert(t("site.terrainFailed"));
}
};
return (
<div className="site-panel">
{/* Aktions-Zeile: Import + Gelände-Erzeugung. */}
<div className="site-actions">
<button
type="button"
className="site-btn"
onClick={() => host.onImportDxf()}
>
{t("site.import")}
</button>
<button
type="button"
className="site-btn"
onClick={() => setCtxImportOpen(true)}
>
{t("site.importLocation")}
</button>
</div>
{ctxImportOpen && (
<ContextImportDialog
onImport={(objs) => host.onAddContextObjects(objs)}
onClose={() => setCtxImportOpen(false)}
/>
)}
{contourSets.length > 0 && (
<div className="site-terrain-row">
{contourSets.length > 1 ? (
<Dropdown
value={effectiveSet}
onChange={(v) => setSelectedSet(v)}
title={t("site.contourSet")}
options={contourSets.map((cs) => ({ value: cs.id, label: cs.name }))}
/>
) : (
<span className="site-terrain-src" title={t("site.contourSet")}>
{contourSets[0].name}
</span>
)}
<button type="button" className="site-btn" onClick={onGenerate}>
{t("site.generateTerrain")}
</button>
</div>
)}
<div className="site-sep" />
{/* Liste der Kontext-Objekte (Name + Typ-Badge + Entfernen). */}
{objects.length === 0 ? (
<div className="site-empty">{t("site.empty")}</div>
) : (
<ul className="site-list">
{objects.map((obj) => (
<li key={obj.id} className="site-row">
<span className="site-name" title={obj.name}>
{obj.name}
</span>
<span className={"site-badge site-badge-" + obj.type}>
{t(typeBadgeKey(obj))}
</span>
<button
type="button"
className="site-remove"
title={t("site.delete")}
aria-label={t("site.delete")}
onClick={() => host.onRemoveContextObject(obj.id)}
>
×
</button>
</li>
))}
</ul>
)}
<div className="site-hint">{t("site.dwgHint")}</div>
</div>
);
}