From 687ab2aa162875fe6e13f9bbe29edcc1f11ed553 Mon Sep 17 00:00:00 2001 From: James Pine Date: Thu, 23 Apr 2026 19:20:42 -0700 Subject: [PATCH] feat(ui): persist selectedProfileId across sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrap useUIStore in zustand/middleware's persist under the key voicebox-ui. partialize only selectedProfileId so volatile UI state (dialog open flags, form drafts, engine/voice pickers, sidebar) stays in-memory as before — but reopening the app no longer loses whichever profile the user was last working with. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/src/stores/uiStore.ts | 55 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/app/src/stores/uiStore.ts b/app/src/stores/uiStore.ts index d5d31b6c..f90fc13d 100644 --- a/app/src/stores/uiStore.ts +++ b/app/src/stores/uiStore.ts @@ -1,4 +1,5 @@ import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; // Draft state for the create voice profile form export interface ProfileFormDraft { @@ -49,33 +50,41 @@ interface UIStore { setTheme: (theme: 'light' | 'dark') => void; } -export const useUIStore = create((set) => ({ - sidebarOpen: true, - setSidebarOpen: (open) => set({ sidebarOpen: open }), +export const useUIStore = create()( + persist( + (set) => ({ + sidebarOpen: true, + setSidebarOpen: (open) => set({ sidebarOpen: open }), - profileDialogOpen: false, - setProfileDialogOpen: (open) => set({ profileDialogOpen: open }), - editingProfileId: null, - setEditingProfileId: (id) => set({ editingProfileId: id }), + profileDialogOpen: false, + setProfileDialogOpen: (open) => set({ profileDialogOpen: open }), + editingProfileId: null, + setEditingProfileId: (id) => set({ editingProfileId: id }), - generationDialogOpen: false, - setGenerationDialogOpen: (open) => set({ generationDialogOpen: open }), + generationDialogOpen: false, + setGenerationDialogOpen: (open) => set({ generationDialogOpen: open }), - selectedProfileId: null, - setSelectedProfileId: (id) => set({ selectedProfileId: id }), + selectedProfileId: null, + setSelectedProfileId: (id) => set({ selectedProfileId: id }), - selectedEngine: 'qwen', - setSelectedEngine: (engine) => set({ selectedEngine: engine }), + selectedEngine: 'qwen', + setSelectedEngine: (engine) => set({ selectedEngine: engine }), - selectedVoiceId: null, - setSelectedVoiceId: (id) => set({ selectedVoiceId: id }), + selectedVoiceId: null, + setSelectedVoiceId: (id) => set({ selectedVoiceId: id }), - profileFormDraft: null, - setProfileFormDraft: (draft) => set({ profileFormDraft: draft }), + profileFormDraft: null, + setProfileFormDraft: (draft) => set({ profileFormDraft: draft }), - theme: 'light', - setTheme: (theme) => { - set({ theme }); - document.documentElement.classList.toggle('dark', theme === 'dark'); - }, -})); + theme: 'light', + setTheme: (theme) => { + set({ theme }); + document.documentElement.classList.toggle('dark', theme === 'dark'); + }, + }), + { + name: 'voicebox-ui', + partialize: (state) => ({ selectedProfileId: state.selectedProfileId }), + }, + ), +);