import { defineStore } from 'pinia'; type PanelMode = 'files' | 'todo' | 'subAgents'; type ResizingPanel = 'left' | 'right' | null; type MobileOverlayTarget = 'conversation' | 'workspace' | 'focus' | null; interface QuotaToast { message: string; type?: string; } interface ToastItem { id: number; title?: string; message: string; type?: string; closable: boolean; timeoutId: ReturnType | null; } interface ToastOptions { title?: string; message?: string; type?: string; closable?: boolean; duration?: number | null; } interface ConfirmDialogOptions { title?: string; message?: string; confirmText?: string; cancelText?: string; } interface ConfirmDialogState extends ConfirmDialogOptions { visible: boolean; } interface EasterEggState { active: boolean; effect: string | null; payload: any; instance: any; cleanupTimer: ReturnType | null; destroying: boolean; destroyPromise: Promise | null; } interface UiState { sidebarCollapsed: boolean; workspaceCollapsed: boolean; chatDisplayMode: 'chat' | 'monitor'; panelMode: PanelMode; panelMenuOpen: boolean; leftWidth: number; rightWidth: number; rightCollapsed: boolean; isResizing: boolean; resizingPanel: ResizingPanel; minPanelWidth: number; maxPanelWidth: number; quotaToast: QuotaToast | null; quotaToastTimer: ReturnType | null; toastQueue: ToastItem[]; nextToastId: number; confirmDialog: ConfirmDialogState | null; pendingConfirmResolver: ((value: boolean) => void) | null; easterEgg: EasterEggState; isMobileViewport: boolean; mobileOverlayMenuOpen: boolean; activeMobileOverlay: MobileOverlayTarget; } export const useUiStore = defineStore('ui', { state: (): UiState => ({ sidebarCollapsed: true, workspaceCollapsed: false, chatDisplayMode: 'chat', panelMode: 'files', panelMenuOpen: false, leftWidth: 350, rightWidth: 420, rightCollapsed: true, isResizing: false, resizingPanel: null, minPanelWidth: 350, maxPanelWidth: 600, quotaToast: null, quotaToastTimer: null, toastQueue: [], nextToastId: 1, confirmDialog: null, pendingConfirmResolver: null, easterEgg: { active: false, effect: null, payload: null, instance: null, cleanupTimer: null, destroying: false, destroyPromise: null }, isMobileViewport: false, mobileOverlayMenuOpen: false, activeMobileOverlay: null }), actions: { setSidebarCollapsed(collapsed: boolean) { this.sidebarCollapsed = collapsed; }, toggleSidebar() { this.sidebarCollapsed = !this.sidebarCollapsed; }, setWorkspaceCollapsed(collapsed: boolean) { this.workspaceCollapsed = collapsed; }, setChatDisplayMode(mode: 'chat' | 'monitor') { this.chatDisplayMode = mode; }, toggleChatDisplayMode() { this.chatDisplayMode = this.chatDisplayMode === 'chat' ? 'monitor' : 'chat'; }, toggleWorkspaceCollapsed() { this.workspaceCollapsed = !this.workspaceCollapsed; }, setPanelMode(mode: PanelMode) { this.panelMode = mode; }, setPanelMenuOpen(open: boolean) { this.panelMenuOpen = open; }, togglePanelMenu() { this.panelMenuOpen = !this.panelMenuOpen; }, setLeftWidth(width: number) { this.leftWidth = width; }, setRightWidth(width: number) { this.rightWidth = width; }, setRightCollapsed(collapsed: boolean) { this.rightCollapsed = collapsed; }, setResizing(state: boolean, panel: ResizingPanel = null) { this.isResizing = state; this.resizingPanel = state ? panel : null; }, setPanelBounds(min: number, max: number) { this.minPanelWidth = min; this.maxPanelWidth = max; }, setIsMobileViewport(isMobile: boolean) { this.isMobileViewport = isMobile; if (!isMobile) { this.mobileOverlayMenuOpen = false; this.activeMobileOverlay = null; } }, setMobileOverlayMenuOpen(open: boolean) { this.mobileOverlayMenuOpen = open; }, toggleMobileOverlayMenu() { this.mobileOverlayMenuOpen = !this.mobileOverlayMenuOpen; }, setActiveMobileOverlay(target: MobileOverlayTarget) { this.activeMobileOverlay = target; }, closeMobileOverlay() { this.activeMobileOverlay = null; }, showQuotaToastMessage(message: string, type: string = 'fast', duration = 5000) { this.quotaToast = { message, type }; if (this.quotaToastTimer) { clearTimeout(this.quotaToastTimer); } this.quotaToastTimer = setTimeout(() => { this.dismissQuotaToast(); }, duration); }, dismissQuotaToast() { if (this.quotaToastTimer) { clearTimeout(this.quotaToastTimer); this.quotaToastTimer = null; } this.quotaToast = null; }, pushToast(options: ToastOptions = {}) { const title = options.title || ''; const message = options.message || ''; if (!title && !message) { return 0; } const id = this.nextToastId++; const entry: ToastItem = { id, title, message, type: options.type || 'info', closable: options.closable !== false, timeoutId: null }; const duration = Object.prototype.hasOwnProperty.call(options, 'duration') ? options.duration : 4000; if (duration !== null) { entry.timeoutId = setTimeout(() => this.dismissToast(id), duration); } this.toastQueue.push(entry); return id; }, updateToast(id: number, patch: ToastOptions = {}) { const entry = this.toastQueue.find(item => item.id === id); if (!entry) { return; } if (patch.title !== undefined) { entry.title = patch.title; } if (patch.message !== undefined) { entry.message = patch.message; } if (patch.type !== undefined) { entry.type = patch.type; } if (patch.closable !== undefined) { entry.closable = patch.closable; } if (Object.prototype.hasOwnProperty.call(patch, 'duration')) { if (entry.timeoutId) { clearTimeout(entry.timeoutId); entry.timeoutId = null; } if (patch.duration !== null && typeof patch.duration === 'number') { entry.timeoutId = setTimeout(() => this.dismissToast(id), patch.duration); } } }, dismissToast(id: number) { const index = this.toastQueue.findIndex(item => item.id === id); if (index === -1) { return; } const [entry] = this.toastQueue.splice(index, 1); if (entry && entry.timeoutId) { clearTimeout(entry.timeoutId); } }, requestConfirm(options: ConfirmDialogOptions = {}) { return new Promise((resolve) => { if (this.pendingConfirmResolver) { const previous = this.pendingConfirmResolver; this.pendingConfirmResolver = null; previous(false); } this.confirmDialog = { visible: true, title: options.title || '确认操作', message: options.message || '请确认本次操作', confirmText: options.confirmText || '确认', cancelText: options.cancelText || '取消' }; this.pendingConfirmResolver = resolve; }); }, resolveConfirm(choice: boolean) { if (this.confirmDialog) { this.confirmDialog.visible = false; } const resolver = this.pendingConfirmResolver; this.pendingConfirmResolver = null; this.confirmDialog = null; if (resolver) { resolver(!!choice); } }, setEasterEggState(patch: Partial) { this.easterEgg = { ...this.easterEgg, ...patch }; }, clearEasterEgg() { this.easterEgg = { active: false, effect: null, payload: null, instance: null, cleanupTimer: null, destroying: false, destroyPromise: null }; } } });