From 2b1194c809f5e47be3c60172cbc6cb6f407eeda4 Mon Sep 17 00:00:00 2001 From: Hibryda Date: Mon, 23 Mar 2026 20:26:07 +0100 Subject: [PATCH] refactor(electrobun): centralize all shared state into global stores New stores: - ui-store.svelte.ts: settingsOpen, paletteOpen, searchOpen, notifDrawerOpen, showWizard, settingsCategory, projectToDelete, showAddGroup, newGroupName - project-tabs-store.svelte.ts: per-project activeTab + activatedTabs via Map Wired: - App.svelte: 8 inline $state removed, reads/writes via ui-store - ProjectCard: activeTab/activatedTabs from project-tabs-store - SettingsDrawer: activeCategory from ui-store - CommandPalette: 4 commands call ui-store directly (no CustomEvent dispatch) Components are now pure view layers reading from stores. --- ui-electrobun/src/mainview/App.svelte | 90 +++++++++--------- .../src/mainview/CommandPalette.svelte | 13 ++- ui-electrobun/src/mainview/ProjectCard.svelte | 16 ++-- .../src/mainview/SettingsDrawer.svelte | 10 +- .../src/mainview/project-tabs-store.svelte.ts | 67 +++++++++++++ ui-electrobun/src/mainview/ui-store.svelte.ts | 94 +++++++++++++++++++ 6 files changed, 230 insertions(+), 60 deletions(-) create mode 100644 ui-electrobun/src/mainview/project-tabs-store.svelte.ts create mode 100644 ui-electrobun/src/mainview/ui-store.svelte.ts diff --git a/ui-electrobun/src/mainview/App.svelte b/ui-electrobun/src/mainview/App.svelte index b8080d5..36fa84b 100644 --- a/ui-electrobun/src/mainview/App.svelte +++ b/ui-electrobun/src/mainview/App.svelte @@ -27,17 +27,20 @@ import { getNotifications, clearAll as clearNotifications, getNotifCount, } from './notifications-store.svelte.ts'; + import { + getSettingsOpen, setSettingsOpen, toggleSettings, + getPaletteOpen, setPaletteOpen, togglePalette, + getSearchOpen, toggleSearch, + getNotifDrawerOpen, setNotifDrawerOpen, toggleNotifDrawer, + getShowWizard, setShowWizard, + getProjectToDelete, setProjectToDelete, + getShowAddGroup, setShowAddGroup, toggleAddGroup, + getNewGroupName, setNewGroupName, resetAddGroupForm, + toggleWizard, + } from './ui-store.svelte.ts'; - // ── Local UI state (view-only, not domain state) ──────────── + // ── Local view-only state (not shared across components) ──── let appReady = $state(false); - let settingsOpen = $state(false); - let paletteOpen = $state(false); - let drawerOpen = $state(false); - let searchOpen = $state(false); - let showWizard = $state(false); - let projectToDelete = $state(null); - let showAddGroup = $state(false); - let newGroupName = $state(''); let sessionStart = $state(Date.now()); // ── Blink timer ───────────────────────────────────────────── @@ -81,28 +84,28 @@ // ── Wizard handler ────────────────────────────────────────── function handleWizardCreated(result: WizardResult) { addProjectFromWizard(result); - showWizard = false; + setShowWizard(false); } async function confirmDeleteProject() { - if (!projectToDelete) return; - await deleteProject(projectToDelete); - projectToDelete = null; + const toDelete = getProjectToDelete(); + if (!toDelete) return; + await deleteProject(toDelete); + setProjectToDelete(null); } // ── Group add (local UI + store) ──────────────────────────── async function handleAddGroup() { - const name = newGroupName.trim(); + const name = getNewGroupName().trim(); if (!name) return; await wsAddGroup(name); - showAddGroup = false; - newGroupName = ''; + resetAddGroupForm(); } // ── Notification drawer ───────────────────────────────────── function handleClearNotifications() { clearNotifications(); - drawerOpen = false; + setNotifDrawerOpen(false); } // ── Toast ref for agent notifications ─────────────────────── @@ -183,8 +186,8 @@ trackAllProjects(); }); - keybindingStore.on('palette', () => { paletteOpen = !paletteOpen; }); - keybindingStore.on('settings', () => { settingsOpen = !settingsOpen; }); + keybindingStore.on('palette', () => { togglePalette(); }); + keybindingStore.on('settings', () => { toggleSettings(); }); keybindingStore.on('group1', () => setActiveGroup(getGroups()[0]?.id)); keybindingStore.on('group2', () => setActiveGroup(getGroups()[1]?.id)); keybindingStore.on('group3', () => setActiveGroup(getGroups()[2]?.id)); @@ -194,7 +197,7 @@ function handleSearchShortcut(e: KeyboardEvent) { if (e.ctrlKey && e.shiftKey && e.key === 'F') { e.preventDefault(); - searchOpen = !searchOpen; + toggleSearch(); } } document.addEventListener('keydown', handleSearchShortcut); @@ -202,10 +205,10 @@ function handlePaletteCommand(e: Event) { const detail = (e as CustomEvent).detail; switch (detail) { - case 'settings': settingsOpen = !settingsOpen; break; - case 'search': searchOpen = !searchOpen; break; - case 'new-project': showWizard = true; break; - case 'toggle-sidebar': settingsOpen = !settingsOpen; break; + case 'settings': toggleSettings(); break; + case 'search': toggleSearch(); break; + case 'new-project': setShowWizard(true); break; + case 'toggle-sidebar': toggleSettings(); break; default: console.log(`[palette] unhandled command: ${detail}`); } } @@ -221,15 +224,15 @@ - settingsOpen = false} /> - paletteOpen = false} /> - searchOpen = false} /> + setSettingsOpen(false)} /> + setPaletteOpen(false)} /> + setSearchOpen(false)} /> drawerOpen = false} + onClose={() => setNotifDrawerOpen(false)} />
- {#if showAddGroup} + {#if getShowAddGroup()}
{ if (e.key === 'Enter') handleAddGroup(); if (e.key === 'Escape') showAddGroup = false; }} + value={getNewGroupName()} + oninput={(e) => setNewGroupName((e.target as HTMLInputElement).value)} + onkeydown={(e) => { if (e.key === 'Enter') handleAddGroup(); if (e.key === 'Escape') setShowAddGroup(false); }} autofocus />
@@ -286,7 +290,7 @@ + @@ -382,8 +386,8 @@