diff --git a/frontend/src/components/simulator/ComponentPropertyDialog.tsx b/frontend/src/components/simulator/ComponentPropertyDialog.tsx index b5678731..dad1c97e 100644 --- a/frontend/src/components/simulator/ComponentPropertyDialog.tsx +++ b/frontend/src/components/simulator/ComponentPropertyDialog.tsx @@ -18,6 +18,7 @@ interface ComponentPropertyDialogProps { onClose: () => void; onRotate: (componentId: string) => void; onDelete: (componentId: string) => void; + lockComponents?: boolean; } export const ComponentPropertyDialog: React.FC = ({ @@ -29,6 +30,7 @@ export const ComponentPropertyDialog: React.FC = ( onClose, onRotate, onDelete, + lockComponents = false, }) => { const dialogRef = useRef(null); const [dialogPosition, setDialogPosition] = useState({ x: 0, y: 0 }); @@ -151,17 +153,19 @@ export const ComponentPropertyDialog: React.FC = ( > Rotate - + {!lockComponents && ( + + )} ); diff --git a/frontend/src/components/simulator/SimulatorCanvas.tsx b/frontend/src/components/simulator/SimulatorCanvas.tsx index 8d81f9de..bfea5f72 100644 --- a/frontend/src/components/simulator/SimulatorCanvas.tsx +++ b/frontend/src/components/simulator/SimulatorCanvas.tsx @@ -59,6 +59,7 @@ export const SimulatorCanvas = () => { updateComponent, serialMonitorOpen, toggleSerialMonitor, + lockComponents, } = useSimulatorStore(); // Active board (for WiFi/BLE status display) @@ -992,6 +993,8 @@ export const SimulatorCanvas = () => { useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Delete' || e.key === 'Backspace') { + if (lockComponents) return; // Prevent deletion if locked + if (selectedComponentId) { removeComponent(selectedComponentId); setSelectedComponentId(null); @@ -1004,7 +1007,7 @@ export const SimulatorCanvas = () => { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [selectedComponentId, removeComponent, activeBoardId, boards.length]); + }, [selectedComponentId, removeComponent, activeBoardId, boards.length, lockComponents]); // Handle component selection from modal const handleSelectComponent = (metadata: ComponentMetadata) => { @@ -1607,18 +1610,20 @@ export const SimulatorCanvas = () => { {/* Add Component */} - + {!lockComponents && ( + + )} @@ -1831,6 +1836,7 @@ export const SimulatorCanvas = () => { removeComponent(id); setShowPropertyDialog(false); }} + lockComponents={lockComponents} /> ); })()} @@ -1884,29 +1890,31 @@ export const SimulatorCanvas = () => {
{label}
- + {!lockComponents && ( + + )} ); diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx index 69b92c18..af181253 100644 --- a/frontend/src/pages/EditorPage.tsx +++ b/frontend/src/pages/EditorPage.tsx @@ -61,9 +61,18 @@ export const EditorPage: React.FC = () => { return { enabled: params.get('embed') === 'true', hideEditor: params.get('hideEditor') === 'true', + lockComponents: params.get('lockComponents') === 'true', }; }); const [embedHideComponentPicker, setEmbedHideComponentPicker] = useState(false); + const setLockComponents = useSimulatorStore((s) => s.setLockComponents); + + // Initial URL params sync + useEffect(() => { + if (embedMode.lockComponents) { + setLockComponents(true); + } + }, [embedMode.lockComponents, setLockComponents]); // Listen for embed mode commands from parent useEffect(() => { @@ -71,6 +80,7 @@ export const EditorPage: React.FC = () => { const handler = (e: Event) => { const detail = (e as CustomEvent).detail || {}; if (detail.hideComponentPicker) setEmbedHideComponentPicker(true); + if (detail.lockComponents !== undefined) setLockComponents(detail.lockComponents); }; window.addEventListener('velxio-embed-mode', handler); // Notify parent that Velxio is ready diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts index af6297f5..879e7e8d 100644 --- a/frontend/src/store/useSimulatorStore.ts +++ b/frontend/src/store/useSimulatorStore.ts @@ -222,6 +222,10 @@ interface SimulatorState { esp32CrashBoardId: string | null; dismissEsp32Crash: () => void; + // ── Lock components ───────────────────────────────────────────────────── + lockComponents: boolean; + setLockComponents: (locked: boolean) => void; + // ── Components ────────────────────────────────────────────────────────── components: Component[]; addComponent: (component: Component) => void; @@ -786,6 +790,9 @@ export const useSimulatorStore = create((set, get) => { esp32CrashBoardId: null, dismissEsp32Crash: () => set({ esp32CrashBoardId: null }), + lockComponents: false, + setLockComponents: (locked: boolean) => set({ lockComponents: locked }), + setBoardType: (type: BoardType) => { const { activeBoardId, running, stopSimulation } = get(); if (running) stopSimulation();