2026-10-08 16:20:15 +09:00
|
|
|
import { create } from "zustand"
|
|
|
|
|
|
2026-10-08 18:10:07 +09:00
|
|
|
export type SettingsTab = "models" | "general" | "drawing" | "about"
|
|
|
|
|
/** The models tab: its provider list, the provider picker or a provider */
|
|
|
|
|
export type ModelsPage = "list" | "picker" | { providerId: string }
|
2026-10-08 16:20:15 +09:00
|
|
|
export type MobileView = "canvas" | "chat"
|
|
|
|
|
|
|
|
|
|
interface UiState {
|
|
|
|
|
/** Desktop: the floating chat panel is open */
|
|
|
|
|
panelOpen: boolean
|
|
|
|
|
/** The start screen was put away (drawing by hand, an opened file) */
|
|
|
|
|
heroDismissed: boolean
|
|
|
|
|
/** Phones: which half of the app is visible */
|
|
|
|
|
mobileView: MobileView
|
|
|
|
|
settingsOpen: boolean
|
|
|
|
|
settingsTab: SettingsTab
|
2026-10-08 18:10:07 +09:00
|
|
|
modelsPage: ModelsPage
|
2026-10-08 16:20:15 +09:00
|
|
|
/** Version shown in the compare dialog, or null when closed */
|
|
|
|
|
compareVersionId: string | null
|
|
|
|
|
saveDialogOpen: boolean
|
|
|
|
|
/** Bumped to ask the composer to take focus */
|
|
|
|
|
focusComposerToken: number
|
|
|
|
|
setPanelOpen: (open: boolean) => void
|
|
|
|
|
setHeroDismissed: (dismissed: boolean) => void
|
|
|
|
|
togglePanel: () => void
|
|
|
|
|
setMobileView: (view: MobileView) => void
|
2026-10-08 18:10:07 +09:00
|
|
|
/** Opens on the given tab (else the last one); the models tab on its
|
|
|
|
|
* list unless a page is given */
|
|
|
|
|
openSettings: (tab?: SettingsTab, modelsPage?: ModelsPage) => void
|
2026-10-08 16:20:15 +09:00
|
|
|
setSettingsOpen: (open: boolean) => void
|
|
|
|
|
setSettingsTab: (tab: SettingsTab) => void
|
2026-10-08 18:10:07 +09:00
|
|
|
setModelsPage: (page: ModelsPage) => void
|
2026-10-08 16:20:15 +09:00
|
|
|
openCompare: (versionId: string) => void
|
|
|
|
|
closeCompare: () => void
|
|
|
|
|
setSaveDialogOpen: (open: boolean) => void
|
|
|
|
|
focusComposer: () => void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const useUiStore = create<UiState>((set) => ({
|
|
|
|
|
panelOpen: true,
|
|
|
|
|
heroDismissed: false,
|
|
|
|
|
mobileView: "chat",
|
|
|
|
|
settingsOpen: false,
|
|
|
|
|
settingsTab: "models",
|
2026-10-08 18:10:07 +09:00
|
|
|
modelsPage: "list",
|
2026-10-08 16:20:15 +09:00
|
|
|
compareVersionId: null,
|
|
|
|
|
saveDialogOpen: false,
|
|
|
|
|
focusComposerToken: 0,
|
|
|
|
|
setPanelOpen: (open) => set({ panelOpen: open }),
|
|
|
|
|
setHeroDismissed: (dismissed) => set({ heroDismissed: dismissed }),
|
|
|
|
|
togglePanel: () => set((state) => ({ panelOpen: !state.panelOpen })),
|
|
|
|
|
setMobileView: (view) => set({ mobileView: view }),
|
2026-10-08 18:10:07 +09:00
|
|
|
openSettings: (tab, modelsPage = "list") =>
|
2026-10-08 16:20:15 +09:00
|
|
|
set((state) => ({
|
|
|
|
|
settingsOpen: true,
|
|
|
|
|
settingsTab: tab ?? state.settingsTab,
|
2026-10-08 18:10:07 +09:00
|
|
|
modelsPage,
|
2026-10-08 16:20:15 +09:00
|
|
|
})),
|
|
|
|
|
setSettingsOpen: (open) => set({ settingsOpen: open }),
|
|
|
|
|
setSettingsTab: (tab) => set({ settingsTab: tab }),
|
2026-10-08 18:10:07 +09:00
|
|
|
setModelsPage: (page) => set({ modelsPage: page }),
|
2026-10-08 16:20:15 +09:00
|
|
|
openCompare: (versionId) => set({ compareVersionId: versionId }),
|
|
|
|
|
closeCompare: () => set({ compareVersionId: null }),
|
|
|
|
|
setSaveDialogOpen: (open) => set({ saveDialogOpen: open }),
|
|
|
|
|
focusComposer: () =>
|
|
|
|
|
set((state) => ({
|
|
|
|
|
panelOpen: true,
|
|
|
|
|
mobileView: "chat",
|
|
|
|
|
focusComposerToken: state.focusComposerToken + 1,
|
|
|
|
|
})),
|
|
|
|
|
}))
|