mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
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>
72 lines
1.9 KiB
TypeScript
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) })),
|
|
}))
|