import React, { useState, useEffect, useRef } from 'react'; import { Inbox, Zap, CheckCircle2, CircleDashed, Film, Music, FileText, Box, Image as ImageIcon, Archive, FileQuestion, List, CalendarClock, Gauge, Bug, Settings, Plus, Play, Pause, Edit2, Trash2, PanelLeft, type LucideIcon } from 'lucide-react'; import { useDownloadStore, DownloadCategory, Queue } from '../store/useDownloadStore'; import { ActiveView, useSettingsStore } from '../store/useSettingsStore'; import { WindowDragRegion } from './WindowDragRegion'; import { useToast } from '../contexts/ToastContext'; export type SidebarFilter = 'all' | 'active' | 'completed' | 'unfinished' | DownloadCategory | 'settings' | string; interface SidebarProps { selectedFilter: SidebarFilter; onSelectFilter: (filter: SidebarFilter) => void; } export const Sidebar: React.FC = (props) => { const { selectedFilter, onSelectFilter } = props; const { downloads, queues, addQueue, renameQueue, removeQueue, startQueue, pauseQueue } = useDownloadStore(); const { activeView, setActiveView, toggleSidebar } = useSettingsStore(); const { addToast } = useToast(); const [isAddingQueue, setIsAddingQueue] = useState(false); const [newQueueName, setNewQueueName] = useState(''); const [renamingQueueId, setRenamingQueueId] = useState(null); const [editingQueueName, setEditingQueueName] = useState(''); const [contextMenu, setContextMenu] = useState<{ x: number; y: number; id: string } | null>(null); const addInputRef = useRef(null); const renameInputRef = useRef(null); useEffect(() => { const handleCloseMenu = () => setContextMenu(null); const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') setContextMenu(null); }; window.addEventListener('click', handleCloseMenu); window.addEventListener('keydown', handleEscape); return () => { window.removeEventListener('click', handleCloseMenu); window.removeEventListener('keydown', handleEscape); }; }, []); useEffect(() => { if (isAddingQueue) addInputRef.current?.focus(); }, [isAddingQueue]); useEffect(() => { if (renamingQueueId) renameInputRef.current?.focus(); }, [renamingQueueId]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (document.querySelector('.app-modal-backdrop') || document.querySelector('.app-modal')) return; const activeEl = document.activeElement as HTMLElement | null; const isInput = activeEl && (activeEl.tagName === 'INPUT' || activeEl.tagName === 'TEXTAREA' || activeEl.isContentEditable); if (!isInput && (e.key === 'Delete' || e.key === 'Backspace')) { if (activeEl && activeEl.closest('.sidebar-inner')) { if (activeView === 'downloads' && selectedFilter.startsWith('queue:')) { const queueId = selectedFilter.replace('queue:', ''); const q = queues.find(q => q.id === queueId); if (q && !q.isMain) { void removeQueue(queueId).catch(error => { addToast({ message: `Could not delete queue: ${String(error)}`, variant: 'error', isActionable: true }); }); } } } } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [selectedFilter, activeView, queues]); const getCount = (filter: SidebarFilter) => { if (filter.startsWith('queue:')) { const qid = filter.replace('queue:', ''); return downloads.filter(d => d.queueId === qid && d.status !== 'completed').length; } switch (filter) { case 'all': return downloads.length; case 'active': return downloads.filter(d => d.status === 'downloading').length; case 'completed': return downloads.filter(d => d.status === 'completed').length; case 'unfinished': return downloads.filter(d => d.status !== 'completed').length; default: return downloads.filter(d => d.category === filter as DownloadCategory).length; } }; const NavItem = ({ icon: Icon, label, filter }: { icon: LucideIcon, label: string, filter: SidebarFilter }) => { const isSelected = activeView === 'downloads' && selectedFilter === filter; return ( ); }; const handleQueueContextMenu = (e: React.MouseEvent, id: string) => { e.preventDefault(); e.stopPropagation(); setContextMenu({ x: e.clientX, y: e.clientY, id }); }; const handleAddQueueSubmit = () => { if (newQueueName.trim()) addQueue(newQueueName.trim()); setNewQueueName(''); setIsAddingQueue(false); }; const handleRenameQueueSubmit = () => { if (renamingQueueId && editingQueueName.trim()) { renameQueue(renamingQueueId, editingQueueName.trim()); } setRenamingQueueId(null); }; const QueueItem = ({ queue }: { queue: Queue }) => { const filterId = `queue:${queue.id}`; const isSelected = activeView === 'downloads' && selectedFilter === filterId; const isRenaming = renamingQueueId === queue.id; if (isRenaming) { return (
setEditingQueueName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleRenameQueueSubmit(); if (e.key === 'Escape') setRenamingQueueId(null); }} onBlur={handleRenameQueueSubmit} />
); } return ( ); }; const ToolItem = ({ icon: Icon, label, view }: { icon: LucideIcon; label: string; view: ActiveView }) => { const isSelected = activeView === view; return ( ); }; return ( ); };