From 4f76d3926ea439cb8eb89e5f026dc9bfbcccb4c2 Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 16 Apr 2026 01:10:10 +0200 Subject: [PATCH] feat(workbench): ?app= deep-links into the active scene MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After consolidating Settings into a workbench app, links from the command menu, pill-nav, AI-tier dropdown, onboarding CTAs, and the sub-route back-buttons had nowhere specific to go — they pointed at `/` and dumped users at their home scene with no way to auto-open the settings app. - Home (+page.svelte) reads ?app= on mount. If the id is a registered workbench app and not already in the active scene, addApp() it. Then scroll the carousel to that page. Strip the query out of history.replaceState so refresh doesn't re-open. - Update all settings redirects (command menu, onboarding, AI-settings dropdown, settings/sync + settings/my-data back-links and breadcrumbs) to `/?app=settings`. Unlocks: future deep-links to any app (profile, themes, spiral, credits, …) without needing a standalone route. `?app=X§ion=Y` is the natural next step — left for when an app needs it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../layout/use-ai-tier-items.svelte.ts | 2 +- .../onboarding/steps/CompleteStep.svelte | 2 +- .../apps/web/src/routes/(app)/+layout.svelte | 2 +- .../apps/web/src/routes/(app)/+page.svelte | 22 +++++++++++++++++-- .../(app)/settings/my-data/+page.svelte | 2 +- .../routes/(app)/settings/sync/+page.svelte | 6 ++--- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/apps/mana/apps/web/src/lib/components/layout/use-ai-tier-items.svelte.ts b/apps/mana/apps/web/src/lib/components/layout/use-ai-tier-items.svelte.ts index cec892082..3c4cac69c 100644 --- a/apps/mana/apps/web/src/lib/components/layout/use-ai-tier-items.svelte.ts +++ b/apps/mana/apps/web/src/lib/components/layout/use-ai-tier-items.svelte.ts @@ -184,7 +184,7 @@ export function useAiTierItems() { id: 'ai-settings', label: 'KI-Einstellungen', icon: 'settings', - onClick: () => goto('/'), + onClick: () => goto('/?app=settings'), }, ]); diff --git a/apps/mana/apps/web/src/lib/components/onboarding/steps/CompleteStep.svelte b/apps/mana/apps/web/src/lib/components/onboarding/steps/CompleteStep.svelte index 04e446ba0..6cb38a10b 100644 --- a/apps/mana/apps/web/src/lib/components/onboarding/steps/CompleteStep.svelte +++ b/apps/mana/apps/web/src/lib/components/onboarding/steps/CompleteStep.svelte @@ -84,7 +84,7 @@
diff --git a/apps/mana/apps/web/src/routes/(app)/+layout.svelte b/apps/mana/apps/web/src/routes/(app)/+layout.svelte index dbfdf5269..be6969550 100644 --- a/apps/mana/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/mana/apps/web/src/routes/(app)/+layout.svelte @@ -746,7 +746,7 @@ id: 'settings', label: 'Einstellungen', category: 'Navigation', - onExecute: () => goto('/'), + onExecute: () => goto('/?app=settings'), }, ]; diff --git a/apps/mana/apps/web/src/routes/(app)/+page.svelte b/apps/mana/apps/web/src/routes/(app)/+page.svelte index f19d195df..0d3ed346d 100644 --- a/apps/mana/apps/web/src/routes/(app)/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/+page.svelte @@ -16,6 +16,8 @@ import { ContextMenu, type ContextMenuItem } from '@mana/shared-ui'; import { Pencil, Copy, Trash, Image, Sparkle } from '@mana/shared-icons'; import { goto } from '$app/navigation'; + import { page } from '$app/stores'; + import { tick } from 'svelte'; import { _, locale } from 'svelte-i18n'; import { buildContextMenuItems, createWorkbenchContextMenu } from '$lib/context-menu'; import type { WorkbenchScene } from '$lib/types/workbench-scenes'; @@ -61,8 +63,24 @@ }); // ── Scene store wiring ────────────────────────────────── - onMount(() => { - workbenchScenesStore.initialize(); + onMount(async () => { + await workbenchScenesStore.initialize(); + // Deep-link: `/?app=settings` (or any registered appId) opens the + // app in the active scene (or focuses it if already open) and + // scrolls it into view. Used by command menu, pill-nav settings + // link, onboarding CTAs, sync-status banner — anywhere we used + // to navigate to `/settings` before the route was removed. + const target = $page.url.searchParams.get('app'); + if (target && getApp(target)) { + const already = workbenchScenesStore.openApps.find((a) => a.appId === target); + if (!already) await workbenchScenesStore.addApp(target); + await tick(); + scrollToPage(target); + // Clean the query out of the URL so refresh doesn't re-trigger. + const clean = new URL($page.url); + clean.searchParams.delete('app'); + history.replaceState({}, '', clean); + } }); onDestroy(() => { workbenchScenesStore.dispose(); diff --git a/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte b/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte index 16630bf06..7ef3ecf4e 100644 --- a/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte @@ -186,7 +186,7 @@