Ressourcen: Dachtypen-Tab (Schicht-Editor wie Wand/Decke)
Dachaufbauten sind jetzt im Ressourcen-Manager anleg-/editier-/löschbar
(RoofStylesTab auf dem LayeredStylesTab-Rumpf, Ressource roofTypes):
Schichtliste mit Bauteil/Dicke/Fugen-Linienstil, Löschen geschützt solange
ein Dach den Typ referenziert. Host-/App-Handler (patch/add/deleteRoofType)
+ i18n de/en. Vervollständigt die Dach-Schichtlogik (3a986ec) um die UI.
This commit is contained in:
+34
@@ -39,6 +39,7 @@ import type {
|
||||
OverrideRule,
|
||||
Project,
|
||||
Roof,
|
||||
RoofType,
|
||||
Stair,
|
||||
StairType,
|
||||
Vec2,
|
||||
@@ -2273,6 +2274,33 @@ export default function App() {
|
||||
ceilingTypes: (p.ceilingTypes ?? []).filter((ct) => ct.id !== id),
|
||||
};
|
||||
});
|
||||
// ── Dachtypen (Dachaufbauten) — analog Deckentyp ──────────────────────────
|
||||
const patchRoofType = (id: string, patch: Partial<RoofType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
roofTypes: (p.roofTypes ?? []).map((rt) => (rt.id === id ? { ...rt, ...patch } : rt)),
|
||||
}));
|
||||
const addRoofType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const roofType: RoofType = {
|
||||
id: `rt-${Date.now()}`,
|
||||
name: t("default.roofTypeName"),
|
||||
layers: [{ componentId, thickness: 0.2 }],
|
||||
};
|
||||
return { ...p, roofTypes: [...(p.roofTypes ?? []), roofType] };
|
||||
});
|
||||
// Dachtyp löschen — geschützt, solange ihn ein Dach verwendet.
|
||||
const deleteRoofType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.roofs ?? []).some((r) => r.roofTypeId === id);
|
||||
if (used) {
|
||||
const name = (p.roofTypes ?? []).find((rt) => rt.id === id)?.name ?? id;
|
||||
notify(t("alert.roofTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, roofTypes: (p.roofTypes ?? []).filter((rt) => rt.id !== id) };
|
||||
});
|
||||
// ── Bauteil-Typen: Tür / Fenster / Treppe (Bibliothek) ────────────────────
|
||||
// Anlegen/Patchen/Löschen analog Wand-/Deckentyp — direkt über setProject
|
||||
// (kein eigener Slice). Löschen ist geschützt, solange ein Element den Typ
|
||||
@@ -2954,6 +2982,9 @@ export default function App() {
|
||||
onPatchCeilingType: patchCeilingType,
|
||||
onAddCeilingType: addCeilingType,
|
||||
onDeleteCeilingType: deleteCeilingType,
|
||||
onPatchRoofType: patchRoofType,
|
||||
onAddRoofType: addRoofType,
|
||||
onDeleteRoofType: deleteRoofType,
|
||||
onImportLineStyles: importLineStyles,
|
||||
onImportHatches: importHatches,
|
||||
selection,
|
||||
@@ -3941,6 +3972,9 @@ export default function App() {
|
||||
onPatchCeilingType: patchCeilingType,
|
||||
onAddCeilingType: addCeilingType,
|
||||
onDeleteCeilingType: deleteCeilingType,
|
||||
onPatchRoofType: patchRoofType,
|
||||
onAddRoofType: addRoofType,
|
||||
onDeleteRoofType: deleteRoofType,
|
||||
onAddDoorType: addDoorType,
|
||||
onPatchDoorType: patchDoorType,
|
||||
onDeleteDoorType: deleteDoorType,
|
||||
|
||||
@@ -638,6 +638,7 @@ export const de = {
|
||||
"default.ceilingTypeSingle": "Decke {thickness} m",
|
||||
"default.wallTypeName": "Neuer Wandtyp",
|
||||
"default.ceilingTypeName": "Neuer Deckentyp",
|
||||
"default.roofTypeName": "Neuer Dachtyp",
|
||||
"default.doorTypeName": "Neuer Türtyp",
|
||||
"default.windowTypeName": "Neuer Fenstertyp",
|
||||
"default.stairTypeName": "Neuer Treppentyp",
|
||||
@@ -649,6 +650,7 @@ export const de = {
|
||||
"alert.lineStyleInUse": "Linienstil „{name}\" wird von einer Schraffur verwendet und kann nicht gelöscht werden.",
|
||||
"alert.wallTypeInUse": "Wandtyp „{name}\" wird von einer Wand verwendet und kann nicht gelöscht werden.",
|
||||
"alert.ceilingTypeInUse": "Deckentyp „{name}\" wird von einer Decke verwendet und kann nicht gelöscht werden.",
|
||||
"alert.roofTypeInUse": "Dachtyp „{name}\" wird von einem Dach verwendet und kann nicht gelöscht werden.",
|
||||
"alert.doorTypeInUse": "Türtyp „{name}\" wird von einer Tür verwendet und kann nicht gelöscht werden.",
|
||||
"alert.windowTypeInUse": "Fenstertyp „{name}\" wird von einem Fenster verwendet und kann nicht gelöscht werden.",
|
||||
"alert.stairTypeInUse": "Treppentyp „{name}\" wird von einer Treppe verwendet und kann nicht gelöscht werden.",
|
||||
@@ -662,6 +664,7 @@ export const de = {
|
||||
"resources.tab.lines": "Linien",
|
||||
"resources.tab.wallStyles": "Wandstile",
|
||||
"resources.tab.ceilingStyles": "Deckenstile",
|
||||
"resources.tab.roofStyles": "Dachtypen",
|
||||
"resources.tab.doorStyles": "Türtypen",
|
||||
"resources.tab.windowStyles": "Fenstertypen",
|
||||
"resources.tab.stairStyles": "Treppentypen",
|
||||
@@ -703,6 +706,10 @@ export const de = {
|
||||
"resources.ceilingStyles.empty": "Noch keine Deckentypen.",
|
||||
"resources.wallStyles.placeholder": "Wandtyp",
|
||||
"resources.ceilingStyles.placeholder": "Deckentyp",
|
||||
"resources.roofStyles.hint":
|
||||
"Je Dachtyp (Schichtaufbau aussen/Eindeckung → innen/Verkleidung) die Schichtfugen als wählbaren Linienstil. Ohne Zuweisung: Haarlinie 0.02 mm.",
|
||||
"resources.roofStyles.empty": "Noch keine Dachtypen.",
|
||||
"resources.roofStyles.placeholder": "Dachtyp",
|
||||
|
||||
// Bauteil-Typen (Tür/Fenster/Treppe) — Formular-Bibliotheken.
|
||||
"resources.doorTypes.hint":
|
||||
@@ -878,6 +885,7 @@ export const de = {
|
||||
"resources.delete.hatch": "Schraffur „{name}\" löschen",
|
||||
"resources.delete.wallType": "Wandtyp „{name}\" löschen",
|
||||
"resources.delete.ceilingType": "Deckentyp „{name}\" löschen",
|
||||
"resources.delete.roofType": "Dachtyp „{name}\" löschen",
|
||||
|
||||
// Schraffur-/Linien-Typ (Master-Detail-Editor).
|
||||
"resources.field.type": "Typ",
|
||||
|
||||
@@ -633,6 +633,7 @@ export const en: Record<TranslationKey, string> = {
|
||||
"default.ceilingTypeSingle": "Ceiling {thickness} m",
|
||||
"default.wallTypeName": "New wall type",
|
||||
"default.ceilingTypeName": "New ceiling type",
|
||||
"default.roofTypeName": "New roof type",
|
||||
"default.doorTypeName": "New door type",
|
||||
"default.windowTypeName": "New window type",
|
||||
"default.stairTypeName": "New stair type",
|
||||
@@ -644,6 +645,7 @@ export const en: Record<TranslationKey, string> = {
|
||||
"alert.lineStyleInUse": "Line style “{name}” is used by a hatch and cannot be deleted.",
|
||||
"alert.wallTypeInUse": "Wall type “{name}” is used by a wall and cannot be deleted.",
|
||||
"alert.ceilingTypeInUse": "Ceiling type “{name}” is used by a ceiling and cannot be deleted.",
|
||||
"alert.roofTypeInUse": "Roof type “{name}” is used by a roof and cannot be deleted.",
|
||||
"alert.doorTypeInUse": "Door type “{name}” is used by a door and cannot be deleted.",
|
||||
"alert.windowTypeInUse": "Window type “{name}” is used by a window and cannot be deleted.",
|
||||
"alert.stairTypeInUse": "Stair type “{name}” is used by a stair and cannot be deleted.",
|
||||
@@ -657,6 +659,7 @@ export const en: Record<TranslationKey, string> = {
|
||||
"resources.tab.lines": "Lines",
|
||||
"resources.tab.wallStyles": "Wall styles",
|
||||
"resources.tab.ceilingStyles": "Ceiling styles",
|
||||
"resources.tab.roofStyles": "Roof types",
|
||||
"resources.tab.doorStyles": "Door types",
|
||||
"resources.tab.windowStyles": "Window types",
|
||||
"resources.tab.stairStyles": "Stair types",
|
||||
@@ -698,6 +701,10 @@ export const en: Record<TranslationKey, string> = {
|
||||
"resources.ceilingStyles.empty": "No ceiling types yet.",
|
||||
"resources.wallStyles.placeholder": "Wall type",
|
||||
"resources.ceilingStyles.placeholder": "Ceiling type",
|
||||
"resources.roofStyles.hint":
|
||||
"Per roof type (layer build-up outside/covering → inside/lining) the layer joints as a selectable line style. Without assignment: hairline 0.02 mm.",
|
||||
"resources.roofStyles.empty": "No roof types yet.",
|
||||
"resources.roofStyles.placeholder": "Roof type",
|
||||
|
||||
// Component types (door/window/stair) — form-based libraries.
|
||||
"resources.doorTypes.hint":
|
||||
@@ -871,6 +878,7 @@ export const en: Record<TranslationKey, string> = {
|
||||
"resources.delete.hatch": "Delete hatch “{name}”",
|
||||
"resources.delete.wallType": "Delete wall type “{name}”",
|
||||
"resources.delete.ceilingType": "Delete ceiling type “{name}”",
|
||||
"resources.delete.roofType": "Delete roof type “{name}”",
|
||||
|
||||
// Hatch/line type (master-detail editor).
|
||||
"resources.field.type": "Type",
|
||||
|
||||
@@ -38,6 +38,9 @@ export function ResourcesPanel() {
|
||||
onAddWallType: host.onAddWallType,
|
||||
onDeleteWallType: host.onDeleteWallType,
|
||||
onPatchCeilingType: host.onPatchCeilingType,
|
||||
onPatchRoofType: host.onPatchRoofType,
|
||||
onAddRoofType: host.onAddRoofType,
|
||||
onDeleteRoofType: host.onDeleteRoofType,
|
||||
onAddCeilingType: host.onAddCeilingType,
|
||||
onDeleteCeilingType: host.onDeleteCeilingType,
|
||||
onImportLineStyles: host.onImportLineStyles,
|
||||
|
||||
@@ -17,6 +17,7 @@ import type { DisplayMode } from "./types";
|
||||
import type {
|
||||
AttributeSource,
|
||||
CeilingType,
|
||||
RoofType,
|
||||
Component,
|
||||
ContextObject,
|
||||
DrawingLevel,
|
||||
@@ -132,6 +133,10 @@ export interface PanelHostValue {
|
||||
onPatchCeilingType: (id: string, patch: Partial<CeilingType>) => void;
|
||||
onAddCeilingType: () => void;
|
||||
onDeleteCeilingType: (id: string) => void;
|
||||
/** Dachtypen (Dachaufbauten): immutable Änderung/Anlage/Löschung. */
|
||||
onPatchRoofType: (id: string, patch: Partial<RoofType>) => void;
|
||||
onAddRoofType: () => void;
|
||||
onDeleteRoofType: (id: string) => void;
|
||||
/** Import fertiger (id-loser) Linienstile/Schraffuren (.lin/.pat). */
|
||||
onImportLineStyles: (styles: Omit<LineStyle, "id">[]) => void;
|
||||
onImportHatches: (hatches: Omit<HatchStyle, "id">[]) => void;
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import type { PointerEvent as ReactPointerEvent } from "react";
|
||||
import type {
|
||||
CeilingType,
|
||||
RoofType,
|
||||
Component,
|
||||
ComponentMaterial,
|
||||
DoorType,
|
||||
@@ -1893,6 +1894,39 @@ function CeilingStylesTab({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab „Dachtypen" — das geneigte Gegenstück zu {@link CeilingStylesTab}: gleicher
|
||||
* {@link LayeredStylesTab}-Rumpf (Schichtaufbau aussen/Eindeckung → innen/
|
||||
* Verkleidung), Ressource `roofTypes`. Vorschau in Decken-Orientierung
|
||||
* (gestapelt) — für die Schichtreihenfolge/-dicken ausreichend.
|
||||
*/
|
||||
function RoofStylesTab({
|
||||
project,
|
||||
onPatchRoofType,
|
||||
onAddRoofType,
|
||||
onDeleteRoofType,
|
||||
}: {
|
||||
project: Project;
|
||||
onPatchRoofType: (id: string, patch: Partial<RoofType>) => void;
|
||||
onAddRoofType: () => void;
|
||||
onDeleteRoofType: (id: string) => void;
|
||||
}) {
|
||||
return (
|
||||
<LayeredStylesTab
|
||||
project={project}
|
||||
types={project.roofTypes ?? []}
|
||||
orientation="ceiling"
|
||||
hintKey="resources.roofStyles.hint"
|
||||
emptyKey="resources.roofStyles.empty"
|
||||
placeholderKey="resources.roofStyles.placeholder"
|
||||
deleteKeyPrefix="resources.delete.roofType"
|
||||
onPatch={onPatchRoofType}
|
||||
onAdd={onAddRoofType}
|
||||
onDelete={onDeleteRoofType}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei-Import-Schaltfläche (verstecktes <input type=file>). Liest die gewählte
|
||||
* Datei als Text und reicht ihn nach oben. Für .lin/.pat-Import.
|
||||
@@ -2957,6 +2991,7 @@ export type TabId =
|
||||
| "lines"
|
||||
| "wallStyles"
|
||||
| "ceilingStyles"
|
||||
| "roofStyles"
|
||||
| "doorStyles"
|
||||
| "windowStyles"
|
||||
| "stairStyles"
|
||||
@@ -2969,6 +3004,7 @@ const TABS: { id: TabId; labelKey: string }[] = [
|
||||
{ id: "lines", labelKey: "resources.tab.lines" },
|
||||
{ id: "wallStyles", labelKey: "resources.tab.wallStyles" },
|
||||
{ id: "ceilingStyles", labelKey: "resources.tab.ceilingStyles" },
|
||||
{ id: "roofStyles", labelKey: "resources.tab.roofStyles" },
|
||||
{ id: "doorStyles", labelKey: "resources.tab.doorStyles" },
|
||||
{ id: "windowStyles", labelKey: "resources.tab.windowStyles" },
|
||||
{ id: "stairStyles", labelKey: "resources.tab.stairStyles" },
|
||||
@@ -2995,6 +3031,10 @@ export interface ResourceManagerHandlers {
|
||||
onPatchCeilingType: (id: string, patch: Partial<CeilingType>) => void;
|
||||
onAddCeilingType: () => void;
|
||||
onDeleteCeilingType: (id: string) => void;
|
||||
/** Dachtypen (Dachaufbauten): immutable Änderung/Anlage/Löschung. */
|
||||
onPatchRoofType: (id: string, patch: Partial<RoofType>) => void;
|
||||
onAddRoofType: () => void;
|
||||
onDeleteRoofType: (id: string) => void;
|
||||
/** Import: fügt fertige (id-lose) Linienstile/Schraffuren hinzu (.lin/.pat). */
|
||||
onImportLineStyles: (styles: Omit<LineStyle, "id">[]) => void;
|
||||
onImportHatches: (hatches: Omit<HatchStyle, "id">[]) => void;
|
||||
@@ -3219,6 +3259,14 @@ export function ResourceManager({
|
||||
onDeleteCeilingType={handlers.onDeleteCeilingType}
|
||||
/>
|
||||
)}
|
||||
{tab === "roofStyles" && (
|
||||
<RoofStylesTab
|
||||
project={project}
|
||||
onPatchRoofType={handlers.onPatchRoofType}
|
||||
onAddRoofType={handlers.onAddRoofType}
|
||||
onDeleteRoofType={handlers.onDeleteRoofType}
|
||||
/>
|
||||
)}
|
||||
{tab === "doorStyles" && (
|
||||
<DoorStylesTab
|
||||
project={project}
|
||||
|
||||
Reference in New Issue
Block a user