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.
This commit is contained in:
Hibryda 2026-03-23 20:26:07 +01:00
parent c88577a34a
commit 2b1194c809
6 changed files with 230 additions and 60 deletions

View file

@ -10,6 +10,10 @@
import RemoteMachinesSettings from './settings/RemoteMachinesSettings.svelte';
import DiagnosticsTab from './settings/DiagnosticsTab.svelte';
import { t } from './i18n.svelte.ts';
import {
getSettingsCategory, setSettingsCategory,
type SettingsCategory,
} from './ui-store.svelte.ts';
interface Props {
open: boolean;
@ -18,7 +22,7 @@
let { open, onClose }: Props = $props();
type CategoryId = 'appearance' | 'agents' | 'security' | 'projects' | 'orchestration' | 'machines' | 'advanced' | 'marketplace' | 'keyboard' | 'diagnostics';
type CategoryId = SettingsCategory;
interface Category {
id: CategoryId;
@ -43,7 +47,7 @@
CATEGORY_DEFS.map(d => ({ id: d.id, label: t(d.key as any), icon: d.icon }))
);
let activeCategory = $state<CategoryId>('appearance');
let activeCategory = $derived(getSettingsCategory());
function handleBackdropClick(e: MouseEvent) {
if (e.target === e.currentTarget) onClose();
@ -83,7 +87,7 @@
<button
class="cat-btn"
class:active={activeCategory === cat.id}
onclick={() => activeCategory = cat.id}
onclick={() => setSettingsCategory(cat.id)}
aria-current={activeCategory === cat.id ? 'page' : undefined}
>
<span class="cat-icon" aria-hidden="true">{cat.icon}</span>