117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
AssetInput,
|
|
BuildingNode,
|
|
LevelNode,
|
|
useScene,
|
|
} from "@pascal-app/core";
|
|
import { useViewer } from "@pascal-app/viewer";
|
|
import { create } from "zustand";
|
|
|
|
export type Phase = "site" | "structure" | "furnish";
|
|
|
|
export type Mode = "select" | "edit" | "delete" | "build";
|
|
|
|
// Structure mode tools (building elements)
|
|
export type StructureTool =
|
|
| "wall"
|
|
| "room"
|
|
| "custom-room"
|
|
| "slab"
|
|
| "ceiling"
|
|
| "roof"
|
|
| "column"
|
|
| "stair"
|
|
| "item"
|
|
| "zone";
|
|
|
|
// Furnish mode tools (items and decoration)
|
|
export type FurnishTool = "item";
|
|
|
|
// Site mode tools
|
|
export type SiteTool = "property-line";
|
|
|
|
// Catalog categories for furnish mode items
|
|
export type CatalogCategory =
|
|
| "furniture"
|
|
| "appliance"
|
|
| "bathroom"
|
|
| "kitchen"
|
|
| "outdoor"
|
|
| "window"
|
|
| "door";
|
|
|
|
// Combined tool type
|
|
export type Tool = SiteTool | StructureTool | FurnishTool;
|
|
|
|
type EditorState = {
|
|
phase: Phase;
|
|
setPhase: (phase: Phase) => void;
|
|
mode: Mode;
|
|
setMode: (mode: Mode) => void;
|
|
tool: Tool | null;
|
|
setTool: (tool: Tool | null) => void;
|
|
catalogCategory: CatalogCategory | null;
|
|
setCatalogCategory: (category: CatalogCategory | null) => void;
|
|
selectedItem: AssetInput | null;
|
|
setSelectedItem: (item: AssetInput) => void;
|
|
};
|
|
|
|
const useEditor = create<EditorState>()((set, get) => ({
|
|
phase: "site",
|
|
setPhase: (phase) => {
|
|
const currentPhase = get().phase;
|
|
if (currentPhase === phase) return;
|
|
|
|
set({ phase });
|
|
|
|
const viewer = useViewer.getState();
|
|
const scene = useScene.getState();
|
|
|
|
switch (phase) {
|
|
case "site":
|
|
// In Site mode, we zoom out and deselect specific levels/buildings
|
|
viewer.setCurrentBuildingId(null);
|
|
viewer.setCurrentLevelId(null);
|
|
viewer.setLevelMode("stacked");
|
|
break;
|
|
|
|
case "structure":
|
|
// In Structure mode, we often want to focus on a specific building/level
|
|
// Auto-select the first building if none is selected
|
|
if (!viewer.currentBuildingId) {
|
|
const firstBuildingId = scene.rootNodeIds.find((id) => {
|
|
const node = scene.nodes[id];
|
|
return node?.type === "building" || null;
|
|
});
|
|
if (firstBuildingId) {
|
|
viewer.setCurrentBuildingId(firstBuildingId as BuildingNode["id"]);
|
|
const buildingNode = scene.nodes[firstBuildingId] as BuildingNode;
|
|
const firstLevelId = buildingNode.children[0];
|
|
if (firstLevelId) {
|
|
viewer.setCurrentLevelId(firstLevelId as LevelNode["id"]);
|
|
}
|
|
}
|
|
}
|
|
viewer.setLevelMode("exploded"); // Better for structure editing
|
|
break;
|
|
|
|
case "furnish":
|
|
// Maybe in furnish mode we force "solo" level view to see inside rooms
|
|
viewer.setLevelMode("solo");
|
|
break;
|
|
}
|
|
},
|
|
mode: "select",
|
|
setMode: (mode) => set({ mode }),
|
|
tool: null,
|
|
setTool: (tool) => set({ tool }),
|
|
catalogCategory: null,
|
|
setCatalogCategory: (category) => set({ catalogCategory: category }),
|
|
selectedItem: null,
|
|
setSelectedItem: (item) => set({ selectedItem: item }),
|
|
}));
|
|
|
|
export default useEditor;
|