From a503ec7c2b4719dab4765dcedd82664604ce40d6 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Mon, 31 Aug 2026 14:51:24 +0100 Subject: [PATCH] refactor(maestro): drop per-session colour and pane glow The sidebar row dot, the pane top strip and the mobile pill dot all painted a hashed per-session colour; the focused pane added an outer accent glow on top of its ring. Removes the colour concept entirely along with the glow, leaving the flat accent ring as the only focus mark. --- web/src/catalog.ts | 12 +++-------- web/src/multiview.ts | 18 +++-------------- web/src/sessioncolor.ts | 23 --------------------- web/src/styles.css | 45 ++++------------------------------------- 4 files changed, 10 insertions(+), 88 deletions(-) delete mode 100644 web/src/sessioncolor.ts diff --git a/web/src/catalog.ts b/web/src/catalog.ts index 2f1a4f2..0d58035 100644 --- a/web/src/catalog.ts +++ b/web/src/catalog.ts @@ -327,12 +327,10 @@ export function renderTopbar(store: CatalogStore, onToggleSidebar?: () => void): } /** Two-tier sidebar highlight state (issue #33): which sessions are open in some - * pane (quiet), which one is focused (loud), and a stable per-session colour so - * a row maps to its pane. */ + * pane (quiet), and which one is focused (loud). */ export interface SidebarHighlights { open: Set; focused: string | null; - colors: Map; } /** Live handle to the persistent sidebar (built once, survives navigation). */ @@ -342,7 +340,7 @@ export interface SidebarHandle { /** Highlight the row for `id` (or clear it with `null`) as the focused session. * Back-compat shim over {@link setHighlights}. */ setActive(id: string | null): void; - /** Apply the full open/focused/colour highlight state. */ + /** Apply the full open/focused highlight state. */ setHighlights(h: SidebarHighlights): void; /** Tear down the store subscription + listeners. */ dispose(): void; @@ -451,7 +449,7 @@ export function renderSidebar(store: CatalogStore, opts: SidebarOptions = {}): S refresh(); }); - let highlights: SidebarHighlights = { open: new Set(), focused: null, colors: new Map() }; + let highlights: SidebarHighlights = { open: new Set(), focused: null }; const applyHighlights = () => { for (const n of treeHost.querySelectorAll(".tree-leaf")) { const id = n.dataset.sessionId; @@ -460,9 +458,6 @@ export function renderSidebar(store: CatalogStore, opts: SidebarOptions = {}): S const open = highlights.open.has(id); n.classList.toggle("is-active", focused); n.classList.toggle("is-open", open && !focused); - const color = highlights.colors.get(id); - if (color && (open || focused)) n.style.setProperty("--mv-color", color); - else n.style.removeProperty("--mv-color"); } }; @@ -515,7 +510,6 @@ export function renderSidebar(store: CatalogStore, opts: SidebarOptions = {}): S highlights = { open: id ? new Set([id]) : new Set(), focused: id, - colors: new Map(), }; applyHighlights(); }, diff --git a/web/src/multiview.ts b/web/src/multiview.ts index f19de89..3da26a8 100644 --- a/web/src/multiview.ts +++ b/web/src/multiview.ts @@ -22,7 +22,6 @@ import { removeLeaf, splitLeaf, } from "./layout.js"; -import { sessionColor } from "./sessioncolor.js"; import type { AttachInfo } from "./attach.js"; import { createSpawnForm, type SpawnFormHandle } from "./spawnForm.js"; @@ -97,12 +96,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { // ---- highlight helpers ---- - function colorMap(): Map { - const m = new Map(); - for (const id of openSessions(layout)) m.set(id, sessionColor(id)); - return m; - } - function focusedLeafSession(): string | null { const tab = activeTab(layout); const fl = tab.focusedLeafId ? findLeaf(tab.root, tab.focusedLeafId) : null; @@ -120,7 +113,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { sidebar.setHighlights({ open: openSessions(layout), focused: focusedLeafSession(), - colors: colorMap(), }); } @@ -142,10 +134,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView { const pane = document.createElement("div"); pane.className = "mv-pane"; pane.dataset.leafId = leaf.id; - if (leaf.sessionId) { - pane.dataset.sessionId = leaf.sessionId; - pane.style.setProperty("--mv-color", sessionColor(leaf.sessionId)); - } + if (leaf.sessionId) pane.dataset.sessionId = leaf.sessionId; const host = document.createElement("div"); host.className = "mv-pane-host"; @@ -482,7 +471,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView { pool.setVisible([]); pool.setFocus(null); canvas.appendChild(renderWelcome()); - sidebar.setHighlights({ open: openSessions(layout), focused: null, colors: colorMap() }); + sidebar.setHighlights({ open: openSessions(layout), focused: null }); persist(); return; } @@ -523,7 +512,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { pill.type = "button"; pill.className = "mv-pill" + (l.id === focused.id ? " is-active" : ""); pill.textContent = l.sessionId ? (infoFor(l.sessionId)?.name ?? l.sessionId.slice(0, 8)) : "empty"; - if (l.sessionId) pill.style.setProperty("--mv-color", sessionColor(l.sessionId)); pill.addEventListener("click", () => { tab.focusedLeafId = l.id; render(); @@ -543,7 +531,7 @@ export function createMultiView(opts: MultiViewOptions): MultiView { focused.sessionId ? [{ id: focused.sessionId, pane: pane.host, info: infoFor(focused.sessionId) }] : [], ); pool.setFocus(focused.sessionId ?? null); - sidebar.setHighlights({ open: openSessions(layout), focused: focused.sessionId ?? null, colors: colorMap() }); + sidebar.setHighlights({ open: openSessions(layout), focused: focused.sessionId ?? null }); } function closeSession(sessionId: string): void { diff --git a/web/src/sessioncolor.ts b/web/src/sessioncolor.ts deleted file mode 100644 index a61caab..0000000 --- a/web/src/sessioncolor.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Stable per-session accent colour, used to map a sidebar row to the pane -// showing that session (issue #33). Hash the session id into a fixed OKLCH -// palette tuned to the maestro tokens; collisions are tolerated when there are -// more open sessions than hues — the colour is a hint, not an identity. - -import type { Uuid } from "./types.js"; - -const PALETTE = [ - "oklch(0.80 0.13 152)", // green (the house accent) - "oklch(0.80 0.12 90)", // amber - "oklch(0.76 0.13 30)", // coral - "oklch(0.78 0.11 210)", // teal - "oklch(0.74 0.13 265)", // blue - "oklch(0.76 0.14 320)", // magenta - "oklch(0.80 0.11 60)", // gold - "oklch(0.78 0.12 185)", // cyan -]; - -export function sessionColor(id: Uuid): string { - let h = 0; - for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0; - return PALETTE[h % PALETTE.length]; -} diff --git a/web/src/styles.css b/web/src/styles.css index ddb2e04..0f729a4 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -2301,20 +2301,10 @@ input.leaf-rename:focus { min-width: 0; min-height: 0; } -/* per-session colour strip — maps a pane to its sidebar row */ -.mv-pane::before { - content: ""; - position: absolute; - inset: 0 0 auto 0; - height: 2px; - background: var(--mv-color, transparent); - z-index: 3; - pointer-events: none; -} -/* focused pane: accent ring + glow, full strength */ +/* focused pane: accent ring, full strength */ .mv-pane.is-focused { border-color: var(--accent); - box-shadow: inset 0 0 0 1px var(--accent), 0 0 22px -8px var(--accent-ring); + box-shadow: inset 0 0 0 1px var(--accent); } /* unfocused panes recede so the eye finds the live one */ .mv-pane:not(.is-focused) { @@ -2417,31 +2407,12 @@ input.leaf-rename:focus { border-radius: var(--r-1); } -/* sidebar two-tier highlight + colour dot (issue #33). +/* sidebar two-tier highlight (issue #33). .is-active = focused pane (loud, from existing rule); .is-open = open - elsewhere (quiet). The dot uses the session's colour so a row maps to a pane. */ + elsewhere (quiet). */ .tree-leaf.is-open { background: color-mix(in oklab, var(--accent) 6%, transparent); } -.tree-leaf.is-open::after, -.tree-leaf.is-active::after { - content: ""; - position: absolute; - right: 9px; - top: 50%; - width: 7px; - height: 7px; - margin-top: -3.5px; - border-radius: 50%; - background: var(--mv-color, var(--accent)); - pointer-events: none; -} -.tree-leaf.is-open::after { - opacity: 0.7; -} -.tree-leaf.is-active::after { - box-shadow: 0 0 8px var(--mv-color, var(--accent-ring)); -} /* ========================================================================= multi-view mobile (#35): below 860px the split tree projects to a pill strip @@ -2486,14 +2457,6 @@ input.leaf-rename:focus { cursor: pointer; border: 1px solid transparent; } -.mv-pill::before { - content: ""; - width: 7px; - height: 7px; - border-radius: 50%; - background: var(--mv-color, var(--faint)); - flex: none; -} .mv-pill.is-active { background: var(--accent-tint); color: var(--accent-strong);