cc-haha/desktop/src/stores/uiStore.ts
程序员阿江(Relakkes) 9b74e064c7 refactor: move task tracking from standalone page into session bottom bar
Remove the separate Tasks sidebar page (wrong concept — was showing
scheduled tasks). Instead, display CLI task progress as a sticky bar
at the bottom of the active session, matching the official desktop app
behavior. Tasks are refreshed in real-time by detecting TaskCreate/
TaskUpdate tool_result messages over WebSocket.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:00:45 +08:00

72 lines
1.9 KiB
TypeScript

import { create } from 'zustand'
export type Toast = {
id: string
type: 'success' | 'error' | 'warning' | 'info'
message: string
duration?: number
}
type ActiveView = 'code' | 'scheduled' | 'terminal' | 'history' | 'settings'
type UIStore = {
theme: 'light' | 'dark'
sidebarOpen: boolean
activeView: ActiveView
activeModal: string | null
toasts: Toast[]
setTheme: (theme: 'light' | 'dark') => void
toggleTheme: () => void
toggleSidebar: () => void
setSidebarOpen: (open: boolean) => void
setActiveView: (view: ActiveView) => void
openModal: (id: string) => void
closeModal: () => void
addToast: (toast: Omit<Toast, 'id'>) => void
removeToast: (id: string) => void
}
let toastCounter = 0
export const useUIStore = create<UIStore>((set) => ({
theme: 'light',
sidebarOpen: true,
activeView: 'code',
activeModal: null,
toasts: [],
setTheme: (theme) => {
document.documentElement.setAttribute('data-theme', theme)
set({ theme })
},
toggleTheme: () => {
set((state) => {
const next = state.theme === 'light' ? 'dark' : 'light'
document.documentElement.setAttribute('data-theme', next)
return { theme: next }
})
},
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
setSidebarOpen: (open) => set({ sidebarOpen: open }),
setActiveView: (view) => set({ activeView: view }),
openModal: (id) => set({ activeModal: id }),
closeModal: () => set({ activeModal: null }),
addToast: (toast) => {
const id = `toast-${++toastCounter}`
set((s) => ({ toasts: [...s.toasts, { ...toast, id }] }))
// Auto-remove after duration
const duration = toast.duration ?? 4000
if (duration > 0) {
setTimeout(() => {
set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) }))
}, duration)
}
},
removeToast: (id) => set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })),
}))