diff --git a/packages/studio/src/utils/studioUiPreferences.test.ts b/packages/studio/src/utils/studioUiPreferences.test.ts index 5e335cf5d..56563aa97 100644 --- a/packages/studio/src/utils/studioUiPreferences.test.ts +++ b/packages/studio/src/utils/studioUiPreferences.test.ts @@ -88,3 +88,48 @@ describe("timeline zoom pin persistence", () => { expect(prefs.timelineManualZoomPercent).toBeUndefined(); }); }); + +function fakeStorage(): Storage { + const map = new Map(); + return { + getItem: (k) => map.get(k) ?? null, + setItem: (k, v) => void map.set(k, v), + removeItem: (k) => void map.delete(k), + clear: () => map.clear(), + key: () => null, + get length() { + return map.size; + }, + } as Storage; +} + +describe("pinnedGroupsByElementType", () => { + it("round-trips a per-element-type pin map", () => { + const storage = fakeStorage(); + writeStudioUiPreferences( + { pinnedGroupsByElementType: { text: ["motion"], media: ["grade"] } }, + storage, + ); + const read = readStudioUiPreferences(storage); + expect(read.pinnedGroupsByElementType).toEqual({ text: ["motion"], media: ["grade"] }); + }); + + it("ignores a malformed pinnedGroupsByElementType (non-object, or non-string-array values)", () => { + const storage = fakeStorage(); + storage.setItem( + "hf-studio-ui-preferences", + JSON.stringify({ pinnedGroupsByElementType: { text: "not-an-array", media: [1, 2] } }), + ); + const read = readStudioUiPreferences(storage); + expect(read.pinnedGroupsByElementType).toEqual({ media: [] }); + }); + + it("merges a pin-map patch without clobbering other preferences", () => { + const storage = fakeStorage(); + writeStudioUiPreferences({ audioMuted: true }, storage); + writeStudioUiPreferences({ pinnedGroupsByElementType: { text: ["style"] } }, storage); + const read = readStudioUiPreferences(storage); + expect(read.audioMuted).toBe(true); + expect(read.pinnedGroupsByElementType).toEqual({ text: ["style"] }); + }); +}); diff --git a/packages/studio/src/utils/studioUiPreferences.ts b/packages/studio/src/utils/studioUiPreferences.ts index 6548a58eb..951b7830f 100644 --- a/packages/studio/src/utils/studioUiPreferences.ts +++ b/packages/studio/src/utils/studioUiPreferences.ts @@ -28,6 +28,7 @@ export interface StudioUiPreferences { timelineZoomMode?: "fit" | "manual"; /** Manual timeline zoom percent, paired with `timelineZoomMode: "manual"`. */ timelineManualZoomPercent?: number; + pinnedGroupsByElementType?: Record; } const STUDIO_UI_PREFERENCES_KEY = "hf-studio-ui-preferences"; @@ -115,6 +116,15 @@ function readStorage(storage: Storage | null): StudioUiPreferences { ) { preferences.timelineManualZoomPercent = parsed.timelineManualZoomPercent; } + if (isRecord(parsed.pinnedGroupsByElementType)) { + const map: Record = {}; + for (const [kind, ids] of Object.entries(parsed.pinnedGroupsByElementType)) { + if (Array.isArray(ids)) { + map[kind] = ids.filter((id): id is string => typeof id === "string"); + } + } + preferences.pinnedGroupsByElementType = map; + } return preferences; } catch { return {};