From 84e2c6416d65a21033e13fb0efeb03eb92713b90 Mon Sep 17 00:00:00 2001 From: drjones Date: Sat, 13 Jun 2026 21:55:37 -0700 Subject: [PATCH] Implement Smart Timers, Power & Water Schedule Dashboard, and tighten UI layout spacing --- src/App.tsx | 9 +- src/components/PartLibrary.tsx | 30 +- src/components/PropertiesPanel.tsx | 93 +++++- src/components/ScheduleDashboard.tsx | 417 +++++++++++++++++++++++++++ src/components/StatusPanel.tsx | 22 +- src/components/Toolbar.tsx | 19 +- src/parts/catalog.ts | 12 +- 7 files changed, 552 insertions(+), 50 deletions(-) create mode 100644 src/components/ScheduleDashboard.tsx diff --git a/src/App.tsx b/src/App.tsx index 9d6294f6..985c4d47 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,6 +20,7 @@ import { LoginModal } from './auth/LoginModal'; import { ToastContainer, addToast } from './components/Toast'; import { useSaveStatus } from './store/saveStatusStore'; import { TestimonialScroller } from './components/TestimonialScroller'; +import { ScheduleDashboard } from './components/ScheduleDashboard'; /** Restore the autosaved design, or seed the demo system on first visit. */ /** Restore the autosaved design, or seed the demo system on first visit. */ @@ -206,6 +207,7 @@ function BuilderApp() { const activeRoomId = useBuilder((s) => s.activeRoomId); const sim = useSimulation(); const [bomOpen, setBomOpen] = useState(false); + const [dashboardOpen, setDashboardOpen] = useState(false); const [checkFindings, setCheckFindings] = useState(null); const roomParts = useMemo(() => { @@ -384,7 +386,11 @@ function BuilderApp() { return (
- setBomOpen(true)} onCheckBuild={runDesignCheck} /> + setBomOpen(true)} + onCheckBuild={runDesignCheck} + onOpenDashboard={() => setDashboardOpen(true)} + />
{bomOpen && setBomOpen(false)} />} + {dashboardOpen && setDashboardOpen(false)} />} {checkFindings && ( -
+

Parts Library

@@ -60,14 +60,14 @@ export function PartLibrary() { Click then place in scene, or drag onto the canvas. Shift-click to stamp copies.

-
+
setSearch(e.target.value)} placeholder="Search parts…" - className="w-full rounded-md border border-zinc-800 bg-zinc-900 px-2.5 py-1.5 text-xs text-zinc-200 placeholder:text-zinc-600 outline-none focus:border-zinc-600 focus:ring-1 focus:ring-zinc-700" + className="w-full rounded border border-zinc-800 bg-zinc-900 px-2 py-1 text-xs text-zinc-200 placeholder:text-zinc-600 outline-none focus:border-zinc-600 focus:ring-1 focus:ring-zinc-700" /> {search && (
-
+
{filteredHotbar.length > 0 && ( -
-

+
+

Tool Belt

@@ -100,8 +100,8 @@ export function PartLibrary() {
)} {filteredQuickBuilds.length > 0 && ( -
-

+
+

Quick Builds

@@ -117,8 +117,8 @@ export function PartLibrary() {
)} {filteredCategories.map((cat) => ( -
-

+
+

{cat.name}

@@ -151,7 +151,7 @@ function QuickBuildButton({ @@ -709,7 +725,7 @@ function PartInspector({ partId }: { partId: string }) { ); return ( -
+
setParam(partId, key, parseFloat(e.target.value))} - className="w-full rounded-md border border-zinc-800 bg-zinc-900 px-2 py-1.5 text-[11px] text-zinc-200 outline-none focus:border-sky-600" + className="w-full rounded-md border border-zinc-800 bg-zinc-900 px-2 py-1 text-[11px] text-zinc-200 outline-none focus:border-sky-600" > {STANDARD_PIPE_SIZES.map((size) => (