import { create } from 'zustand'; import { persist } from 'zustand/middleware'; export type Theme = 'light' | 'dark' | 'system'; function resolveTheme(theme: Theme): 'light' | 'dark' { if (theme !== 'system') return theme; if (typeof window === 'undefined') return 'dark'; return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } function applyTheme(theme: Theme) { if (typeof document === 'undefined') return; document.documentElement.classList.toggle('dark', resolveTheme(theme) === 'dark'); } // Draft state for the create voice profile form export interface ProfileFormDraft { name: string; description: string; language: string; personality: string; referenceText: string; sampleMode: 'upload' | 'record' | 'system'; // Note: File objects can't be persisted, so we store metadata sampleFileName?: string; sampleFileType?: string; sampleFileData?: string; // Base64 encoded } interface UIStore { // Sidebar sidebarOpen: boolean; setSidebarOpen: (open: boolean) => void; // Modals profileDialogOpen: boolean; setProfileDialogOpen: (open: boolean) => void; editingProfileId: string | null; setEditingProfileId: (id: string | null) => void; generationDialogOpen: boolean; setGenerationDialogOpen: (open: boolean) => void; // Selected profile for generation selectedProfileId: string | null; setSelectedProfileId: (id: string | null) => void; // Currently selected engine (synced from generation form) selectedEngine: string; setSelectedEngine: (engine: string) => void; // Selected voice in Voices tab inspector selectedVoiceId: string | null; setSelectedVoiceId: (id: string | null) => void; // Profile form draft (for persisting create voice modal state) profileFormDraft: ProfileFormDraft | null; setProfileFormDraft: (draft: ProfileFormDraft | null) => void; // Theme theme: Theme; setTheme: (theme: Theme) => void; } 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 }), generationDialogOpen: false, setGenerationDialogOpen: (open) => set({ generationDialogOpen: open }), selectedProfileId: null, setSelectedProfileId: (id) => set({ selectedProfileId: id }), selectedEngine: 'qwen', setSelectedEngine: (engine) => set({ selectedEngine: engine }), selectedVoiceId: null, setSelectedVoiceId: (id) => set({ selectedVoiceId: id }), profileFormDraft: null, setProfileFormDraft: (draft) => set({ profileFormDraft: draft }), theme: 'system', setTheme: (theme) => { set({ theme }); applyTheme(theme); }, }), { name: 'talkbox-ui', partialize: (state) => ({ selectedProfileId: state.selectedProfileId, theme: state.theme, }), onRehydrateStorage: () => (state) => { if (state) applyTheme(state.theme); }, }, ), );