From c043e621bd578f5a1ee59efb39464bbe9d898e2b Mon Sep 17 00:00:00 2001 From: Aavash Date: Sun, 18 Oct 2026 18:17:05 +0545 Subject: [PATCH] fix: preserve contexts order on first create or rename --- src/lib/state/settings.svelte.ts | 25 +++++++++++++++++++++++++ src/lib/state/settings.test.ts | 18 ++++++++++++++++++ src/lib/state/workspace.svelte.ts | 2 ++ 3 files changed, 45 insertions(+) diff --git a/src/lib/state/settings.svelte.ts b/src/lib/state/settings.svelte.ts index 2ec219f..8040cf0 100644 --- a/src/lib/state/settings.svelte.ts +++ b/src/lib/state/settings.svelte.ts @@ -892,6 +892,31 @@ class Settings { this.commit(); } + /** A new context goes last, so the ones before it keep their shortcuts. */ + contextCreated(existing: { name: string }[], name: string): void { + const order = this.pinnedOrder(existing).filter((n) => n !== name); + this.setContextOrder([...order, name]); + } + + /** A renamed context keeps its place, and its shortcut. */ + contextRenamed(existing: { name: string }[], from: string, to: string): void { + const order = this.pinnedOrder(existing).filter((n) => n !== to); + this.setContextOrder(order.map((n) => (n === from ? to : n))); + } + + /** + * The order as shown now, written out in full. Names of deleted contexts stay, so one + * restored from Trash returns to its old place. + */ + private pinnedOrder(existing: { name: string }[]): string[] { + const order = [...this.contextOrder]; + const ranked = new Set(order); + for (const c of this.orderContexts(existing)) { + if (!ranked.has(c.name)) order.push(c.name); + } + return order; + } + orderContexts(contexts: T[]): T[] { const rank = new Map(this.contextOrder.map((name, i) => [name, i])); return [...contexts].sort((a, b) => { diff --git a/src/lib/state/settings.test.ts b/src/lib/state/settings.test.ts index 69ae4bd..63071ae 100644 --- a/src/lib/state/settings.test.ts +++ b/src/lib/state/settings.test.ts @@ -73,3 +73,21 @@ describe("settings loaded from storage", () => { /** The blue preset's light value, the first entry of `SURFACE_TINTS`. */ const SURFACE_TINTS_COLOR = "oklch(52% 0.21 266)"; + +describe("context order", () => { + const named = (...names: string[]) => names.map((name) => ({ name })); + + it("puts a new context last, even before any reordering", async () => { + const { settings } = await loadSettings({}); + settings.contextCreated(named("Work", "Personal"), "Archive"); + const shown = settings.orderContexts(named("Work", "Personal", "Archive")); + expect(shown.map((c) => c.name)).toEqual(["Personal", "Work", "Archive"]); + }); + + it("keeps a renamed context in its place before any reordering", async () => { + const { settings } = await loadSettings({}); + settings.contextRenamed(named("Apple", "Banana", "Cherry"), "Apple", "Zebra"); + const shown = settings.orderContexts(named("Zebra", "Banana", "Cherry")); + expect(shown.map((c) => c.name)).toEqual(["Zebra", "Banana", "Cherry"]); + }); +}); diff --git a/src/lib/state/workspace.svelte.ts b/src/lib/state/workspace.svelte.ts index a950285..bac2a1a 100644 --- a/src/lib/state/workspace.svelte.ts +++ b/src/lib/state/workspace.svelte.ts @@ -598,6 +598,7 @@ class Workspace { toasts.error(checkFolder(`Couldn't create the context “${name}”.`)); return null; } + settings.contextCreated(this.contexts, created); await this.refresh(); await this.switchContext(created); return created; @@ -614,6 +615,7 @@ class Workspace { } viewState.renameContext(from, renamed); + settings.contextRenamed(this.contexts, from, renamed); const here = this.activeContext === from; if (here) this.setContext(renamed); await this.refresh();