Files
TalkBox/app/src/stores/uiStore.ts
T
Labyricorn b8815e94ea
CI / frontend-quality (push) Canceled after 0s
rebrand: rename VoiceBox to TalkBox throughout codebase
- All 'voicebox'/'Voicebox'/'VOICEBOX' strings replaced with 'talkbox'/'TalkBox'/'TALKBOX'
- Port changed from 17493 to 17494 (avoids conflict with upstream VoiceBox)
- MCP tool namespace: voicebox.* -> talkbox.*
- App bundle ID: sh.voicebox.app -> com.talkbox.app
- Binary names: voicebox-server -> talkbox-server, voicebox-mcp -> talkbox-mcp
- Docker user/group: voicebox -> talkbox
- Database: voicebox.db -> talkbox.db
- Env vars: VOICEBOX_* -> TALKBOX_*
- Asset files renamed: voicebox-logo.* -> talkbox-logo.*, etc.
- External binaries in tauri.conf.json updated to talkbox-server/talkbox-mcp
2026-08-24 19:45:56 -07:00

110 lines
3.1 KiB
TypeScript

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<UIStore>()(
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);
},
},
),
);