refactor(electrobun): modularize stores + shared UI components

Stores:
- notifications-store.svelte.ts: owns notifications array (was inline in App)
- workspace-store.svelte.ts: extended with addProjectFromWizard, loadGroupsFromDb,
  loadProjectsFromDb, derived getters (totalCost, totalTokens, mountedGroupIds)

Shared UI components (ui/):
- SegmentedControl.svelte: replaces repeated .seg button groups
- SliderInput.svelte: labeled range slider with value display
- StatusDot.svelte: colored dot with pulse support
- IconButton.svelte: icon-only button with tooltip, 3 sizes
- Section.svelte: settings section wrapper with heading

App.svelte: script 390→221 lines (removed all inline CRUD, delegates to stores)
ProjectCard: uses StatusDot shared component
AgentSettings + OrchestrationSettings: use SegmentedControl, SliderInput, Section
This commit is contained in:
Hibryda 2026-03-23 19:42:47 +01:00
parent 265ddd3f1d
commit c88577a34a
12 changed files with 647 additions and 437 deletions

View file

@ -7,6 +7,7 @@
import TaskBoardTab from './TaskBoardTab.svelte';
import DocsTab from './DocsTab.svelte';
import SshTab from './SshTab.svelte';
import StatusDot from './ui/StatusDot.svelte';
import {
startAgent, stopAgent, sendPrompt, getSession, hasSession,
loadLastSession,
@ -162,12 +163,7 @@
<!-- Header -->
<header class="project-header">
<div class="status-dot-wrap" aria-label="Status: {agentStatus}">
<div
class="status-dot {agentStatus}"
class:blink-off={agentStatus === 'running' && !blinkVisible}
role="img"
aria-label={agentStatus}
></div>
<StatusDot status={agentStatus} blinkOff={agentStatus === 'running' && !blinkVisible} />
</div>
<span class="project-name" title={name}>{name}</span>
@ -476,19 +472,6 @@
position: relative;
}
.status-dot {
width: 100%;
height: 100%;
border-radius: 50%;
background: var(--ctp-overlay0);
}
.status-dot.running { background: var(--ctp-green); }
.status-dot.idle { background: var(--ctp-overlay1); }
.status-dot.done { background: var(--ctp-green); }
.status-dot.error { background: var(--ctp-red); }
.status-dot.stalled { background: var(--ctp-peach); }
.status-dot.blink-off { opacity: 0.3; }
.project-name {
font-weight: 600;