Ribbon 3D-Tab: Kamera-Presets + Darstellungsart; truck-Integration geplant 2026-07-07
This commit is contained in:
@@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📅 Geplant
|
||||||
|
|
||||||
|
- [ ] **truck-Integration (Profil-Extrusion / B-Rep)** — **Start: 2026-07-07 (Dienstag, nach Reset).** Nutzer zeichnet 2D-Querschnitt (L-Profil, T-Träger, Freiform) → truck-Extrusion → 3D-Körper + Boolean gegen Wand/Decke. Voraussetzung: truck-Booleans stabil + WASM-Integration. Umfang: ~4–6 Wochen. Mit Nutzer Scope/MVP klären vor Start.
|
||||||
|
|
||||||
## ⛔ Blocker (zuerst klären)
|
## ⛔ Blocker (zuerst klären)
|
||||||
|
|
||||||
- [x] ~~**Toolchain prüfen**~~ — **ERLEDIGT 2026-07-04 (macOS-Gerät):** `node`/`npm`/`cargo` (1.96.0)/`wasm-pack` (0.15.0) alle vorhanden. `npm install` + `npm approve-scripts esbuild wasm-pack …` (npm gated Install-Scripts → `allowScripts`-Block in `package.json`, ungetrackt gelassen), `rustup target add wasm32-unknown-unknown`, beide WASM-Engines gebaut, Frontend gebaut, **`npm run tauri:build` → Mac-App (`cad.app` + `cad_0.1.0_aarch64.dmg`, arm64) läuft.** Verifikations-Baseline grün: `tsc --noEmit` sauber, `vitest run` 230/230, `cargo test render3d` 56/56. **Kein Blocker mehr für Engine-Slices auf diesem Gerät.**
|
- [x] ~~**Toolchain prüfen**~~ — **ERLEDIGT 2026-07-04 (macOS-Gerät):** `node`/`npm`/`cargo` (1.96.0)/`wasm-pack` (0.15.0) alle vorhanden. `npm install` + `npm approve-scripts esbuild wasm-pack …` (npm gated Install-Scripts → `allowScripts`-Block in `package.json`, ungetrackt gelassen), `rustup target add wasm32-unknown-unknown`, beide WASM-Engines gebaut, Frontend gebaut, **`npm run tauri:build` → Mac-App (`cad.app` + `cad_0.1.0_aarch64.dmg`, arm64) läuft.** Verifikations-Baseline grün: `tsc --noEmit` sauber, `vitest run` 230/230, `cargo test render3d` 56/56. **Kein Blocker mehr für Engine-Slices auf diesem Gerät.**
|
||||||
|
|||||||
+15
-1
@@ -69,7 +69,7 @@ import type { Pick3dHit } from "./viewport/Wasm3DViewport";
|
|||||||
import { ResourceManager } from "./ui/ResourceManager";
|
import { ResourceManager } from "./ui/ResourceManager";
|
||||||
import type { ResourceManagerHandlers } from "./ui/ResourceManager";
|
import type { ResourceManagerHandlers } from "./ui/ResourceManager";
|
||||||
import { HatchSwatch } from "./ui/hatchPreview";
|
import { HatchSwatch } from "./ui/hatchPreview";
|
||||||
import { TopBar, ViewRibbonTab } from "./ui/TopBar";
|
import { TopBar, ViewRibbonTab, Ribbon3dTab } from "./ui/TopBar";
|
||||||
import { RibbonBar } from "./ui/ribbon/RibbonBar";
|
import { RibbonBar } from "./ui/ribbon/RibbonBar";
|
||||||
import type { RibbonTabId } from "./ui/ribbon/ribbonItems";
|
import type { RibbonTabId } from "./ui/ribbon/ribbonItems";
|
||||||
import { Dropdown } from "./ui/Dropdown";
|
import { Dropdown } from "./ui/Dropdown";
|
||||||
@@ -3320,6 +3320,20 @@ export default function App() {
|
|||||||
textTarget={textTarget}
|
textTarget={textTarget}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
"3d": (
|
||||||
|
<Ribbon3dTab
|
||||||
|
viewToggleEnabled={activeLevel.kind === "floor"}
|
||||||
|
viewType={viewType}
|
||||||
|
onViewType={setViewType}
|
||||||
|
view3d={view3d}
|
||||||
|
onView3d={setView3d}
|
||||||
|
fov={fov}
|
||||||
|
onFov={setFov}
|
||||||
|
renderMode={renderMode}
|
||||||
|
onRenderMode={setRenderMode}
|
||||||
|
renderModeEnabled={viewType === "perspektive"}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1262,6 +1262,99 @@ export function ViewRibbonTab({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Ribbon3dTabProps {
|
||||||
|
viewToggleEnabled: boolean;
|
||||||
|
viewType: ViewType;
|
||||||
|
onViewType: (v: ViewType) => void;
|
||||||
|
view3d: View3d;
|
||||||
|
onView3d: (v: View3d) => void;
|
||||||
|
fov: number;
|
||||||
|
onFov: (n: number) => void;
|
||||||
|
renderMode: RenderMode;
|
||||||
|
onRenderMode: (m: RenderMode) => void;
|
||||||
|
renderModeEnabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 3D-Tab des Ribbons — Kamera-Presets + Darstellungsart. Kein Duplikat des
|
||||||
|
* Ansichten-Tabs: hier nur 3D-relevante Steuerung (Blickwinkel, Rendermodus). */
|
||||||
|
export function Ribbon3dTab({
|
||||||
|
viewToggleEnabled,
|
||||||
|
viewType,
|
||||||
|
onViewType,
|
||||||
|
view3d,
|
||||||
|
onView3d,
|
||||||
|
fov,
|
||||||
|
onFov,
|
||||||
|
renderMode,
|
||||||
|
onRenderMode,
|
||||||
|
renderModeEnabled,
|
||||||
|
}: Ribbon3dTabProps) {
|
||||||
|
return (
|
||||||
|
<div className="ribbon-views">
|
||||||
|
<div className="tb-group" role="group" aria-label={t("topbar.viewGroup")}>
|
||||||
|
<div className="view-grid view-grid-4">
|
||||||
|
<button
|
||||||
|
className={`view-icon${viewToggleEnabled && viewType === "grundriss" ? " active" : ""}`}
|
||||||
|
onClick={() => onViewType("grundriss")}
|
||||||
|
disabled={!viewToggleEnabled}
|
||||||
|
title={viewToggleEnabled ? t("topbar.grundriss") : t("topbar.viewGroup.disabled")}
|
||||||
|
aria-label={t("topbar.grundriss")}
|
||||||
|
>
|
||||||
|
<ViewIcon name="grundriss" />
|
||||||
|
</button>
|
||||||
|
{(
|
||||||
|
[
|
||||||
|
["top", t("view3d.top")],
|
||||||
|
["iso", t("view3d.iso")],
|
||||||
|
["perspective", t("view3d.perspective")],
|
||||||
|
["front", t("view3d.front")],
|
||||||
|
["side", t("view3d.side")],
|
||||||
|
] as [View3d, string][]
|
||||||
|
).map(([key, label]) => (
|
||||||
|
<button
|
||||||
|
key={key}
|
||||||
|
className={`view-icon${viewToggleEnabled && viewType === "perspektive" && view3d === key ? " active" : ""}`}
|
||||||
|
onClick={() => {
|
||||||
|
onView3d(key);
|
||||||
|
if (viewType !== "perspektive") onViewType("perspektive");
|
||||||
|
}}
|
||||||
|
disabled={!viewToggleEnabled}
|
||||||
|
title={viewToggleEnabled ? `${label} — ${t(`view3d.${key}.hint`)}` : t("topbar.viewGroup.disabled")}
|
||||||
|
aria-label={label}
|
||||||
|
>
|
||||||
|
<ViewIcon name={key} />
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
<CameraMenu
|
||||||
|
fov={fov}
|
||||||
|
onFov={onFov}
|
||||||
|
disabled={!viewToggleEnabled || viewType !== "perspektive"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Sep />
|
||||||
|
<div className="tb-group" role="group" aria-label={t("display.style.group")}>
|
||||||
|
<label className="tb-field">
|
||||||
|
<span className="tb-label">{t("display.style")}</span>
|
||||||
|
<Dropdown
|
||||||
|
value={renderMode}
|
||||||
|
disabled={!renderModeEnabled}
|
||||||
|
onChange={(v) => onRenderMode(v as RenderMode)}
|
||||||
|
title={t("display.style.hint")}
|
||||||
|
options={[
|
||||||
|
{ value: "shaded", label: t("display.style.shaded") },
|
||||||
|
{ value: "white", label: t("display.style.white") },
|
||||||
|
{ value: "textured", label: t("display.style.textured") },
|
||||||
|
{ value: "wireframe", label: t("display.style.wireframe") },
|
||||||
|
{ value: "hidden", label: t("display.style.hidden") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function TopBar({
|
export function TopBar({
|
||||||
project,
|
project,
|
||||||
ribbonTab,
|
ribbonTab,
|
||||||
|
|||||||
Reference in New Issue
Block a user