From 714c2357982286f570d27ac2f89587ad3f11ff86 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 15 Apr 2026 19:41:50 +0200 Subject: [PATCH] feat(workbench): scene description field, drop scene icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schema + store preparation for the new scene header on the homepage (next commit). Scenes get an optional free-text description stamped as its own field — LWW through the existing mana-sync pipeline, no new sync contract. The unused icon field is removed everywhere: - types/workbench-scenes.ts: description?: string | null replaces icon - stores/workbench-scenes.svelte.ts: createScene, renameScene, duplicateScene, toScene, patchScene all updated. New method setSceneDescription(id, value) mirrors renameScene so the caller can change just the description without re-submitting the name. - components/workbench/scenes/SceneTabs.svelte: the tab-bar rendered {#if scene.icon} before the name — scene.name is unique enough to identify a scene, and the UI direction is away from emoji chrome. Existing scene rows in Dexie simply omit description (undefined → null on read); the icon field on old rows is ignored and will age out of the schema the next time the row is written. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../workbench/scenes/SceneTabs.svelte | 7 ------ .../src/lib/stores/workbench-scenes.svelte.ts | 23 +++++++++++++------ .../web/src/lib/types/workbench-scenes.ts | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneTabs.svelte b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneTabs.svelte index 59233f49d..bb358bad9 100644 --- a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneTabs.svelte +++ b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneTabs.svelte @@ -113,9 +113,6 @@ oncontextmenu={(e) => openMenu(e, scene)} title={scene.name} > - {#if scene.icon} - {scene.icon} - {/if} {scene.name} {/each} @@ -182,10 +179,6 @@ .scene-pill.dragging { opacity: 0.4; } - .scene-icon { - font-size: 0.95rem; - line-height: 1; - } .scene-name { overflow: hidden; text-overflow: ellipsis; diff --git a/apps/mana/apps/web/src/lib/stores/workbench-scenes.svelte.ts b/apps/mana/apps/web/src/lib/stores/workbench-scenes.svelte.ts index b620b9b77..e2e476bcc 100644 --- a/apps/mana/apps/web/src/lib/stores/workbench-scenes.svelte.ts +++ b/apps/mana/apps/web/src/lib/stores/workbench-scenes.svelte.ts @@ -62,7 +62,7 @@ function toScene(local: LocalWorkbenchScene): WorkbenchScene { return { id: local.id, name: local.name, - icon: local.icon, + description: local.description ?? null, openApps: local.openApps ?? [], order: local.order, wallpaper: local.wallpaper, @@ -98,7 +98,9 @@ function pickActiveId(scenes: WorkbenchScene[], current: string | null): string async function patchScene( id: string, - patch: Partial> + patch: Partial< + Pick + > ) { // Strip Svelte 5 $state proxies — IndexedDB's structured clone can't serialize them. const clean = $state.snapshot({ ...patch, updatedAt: nowIso() }); @@ -182,7 +184,7 @@ export const workbenchScenesStore = { async createScene(opts: { name: string; - icon?: string; + description?: string | null; seedApps?: WorkbenchSceneApp[]; setActive?: boolean; }): Promise { @@ -192,7 +194,7 @@ export const workbenchScenesStore = { const row: LocalWorkbenchScene = { id, name: opts.name.trim() || 'Neue Szene', - icon: opts.icon, + description: opts.description ?? null, openApps: opts.seedApps ? ($state.snapshot(opts.seedApps) as WorkbenchSceneApp[]) : [], order: maxOrder + 1, createdAt: now, @@ -206,10 +208,17 @@ export const workbenchScenesStore = { return id; }, - async renameScene(id: string, name: string, icon?: string) { + async renameScene(id: string, name: string, description?: string | null) { const trimmed = name.trim(); if (!trimmed) return; - await patchScene(id, { name: trimmed, ...(icon !== undefined ? { icon } : {}) }); + await patchScene(id, { + name: trimmed, + ...(description !== undefined ? { description } : {}), + }); + }, + + async setSceneDescription(id: string, description: string | null) { + await patchScene(id, { description }); }, async duplicateScene(id: string) { @@ -217,7 +226,7 @@ export const workbenchScenesStore = { if (!src) return; await this.createScene({ name: `${src.name} Kopie`, - icon: src.icon, + description: src.description ?? null, seedApps: src.openApps, setActive: true, }); diff --git a/apps/mana/apps/web/src/lib/types/workbench-scenes.ts b/apps/mana/apps/web/src/lib/types/workbench-scenes.ts index d73d9a0da..564c4d021 100644 --- a/apps/mana/apps/web/src/lib/types/workbench-scenes.ts +++ b/apps/mana/apps/web/src/lib/types/workbench-scenes.ts @@ -25,8 +25,8 @@ export interface WorkbenchSceneApp { export interface WorkbenchScene { id: string; name: string; - /** Optional emoji shown in the scene tab. */ - icon?: string; + /** Short free-text description shown under the name in the scene header. */ + description?: string | null; openApps: WorkbenchSceneApp[]; /** Sort order in the scene tab bar. */ order: number;