diff --git a/frontend/src/components/FileExplorer.tsx b/frontend/src/components/FileExplorer.tsx index d0a6e83..a35ea6d 100644 --- a/frontend/src/components/FileExplorer.tsx +++ b/frontend/src/components/FileExplorer.tsx @@ -89,9 +89,28 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { const [movingFiles, setMovingFiles] = useState([]); const [moveModalPath, setMoveModalPath] = useState('.'); const [moveFolders, setMoveFolders] = useState([]); + const [dragOverFolder, setDragOverFolder] = useState(null); const searchTimeoutRef = useRef(undefined); const fileInputRef = useRef(null); + useEffect(() => { + api.getSettings().then((data) => { + const theme = data?.settings?.theme || data?.theme; + if (theme) { + if (theme === 'light') { + document.documentElement.setAttribute('data-theme', 'light'); + document.documentElement.classList.remove('dark'); + document.documentElement.style.setProperty('color-scheme', 'light'); + } else { + document.documentElement.setAttribute('data-theme', 'dark'); + document.documentElement.classList.add('dark'); + document.documentElement.style.setProperty('color-scheme', 'dark'); + } + localStorage.setItem('theme', theme); + } + }).catch(console.error); + }, []); + // Load files on path change const loadFiles = useCallback(async (path?: string) => { const targetPath = path ?? currentPath; @@ -339,10 +358,20 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { if (!file.is_dir) return; if (draggedFile === file.path) return; e.preventDefault(); + if (dragOverFolder !== file.path) { + setDragOverFolder(file.path); + } + } + + function handleItemDragLeave(e: React.DragEvent, file: FileItem) { + if (dragOverFolder === file.path) { + setDragOverFolder(null); + } } async function handleItemDrop(e: React.DragEvent, file: FileItem) { if (!file.is_dir) return; + setDragOverFolder(null); const sourcePath = e.dataTransfer.getData('text/plain'); if (!sourcePath || sourcePath === file.path) return; @@ -829,6 +858,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { draggable onDragStart={(e: any) => handleItemDragStart(e, file.path)} onDragOver={(e: any) => handleItemDragOver(e, file)} + onDragLeave={(e: any) => handleItemDragLeave(e, file)} onDrop={(e: any) => handleItemDrop(e, file)} initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} @@ -837,8 +867,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { onContextMenu={(e) => handleContextMenu(e, file)} className={`group relative p-4 rounded-xl cursor-pointer transition-all duration-150 border-2 ${draggedFile === file.path ? 'opacity-50' : ''}`} style={{ - backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', - border: `1px solid ${selectedFiles.has(file.path) ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`, + backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', + border: `1px solid ${selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`, }} >
handleItemDragStart(e, file.path)} onDragOver={(e: any) => handleItemDragOver(e, file)} + onDragLeave={(e: any) => handleItemDragLeave(e, file)} onDrop={(e: any) => handleItemDrop(e, file)} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} @@ -915,8 +946,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { onContextMenu={(e) => handleContextMenu(e, file)} className={`group relative p-4 rounded-xl cursor-pointer transition-all duration-150 ${draggedFile === file.path ? 'opacity-50' : ''}`} style={{ - backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', - border: `1px solid ${selectedFiles.has(file.path) ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`, + backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', + border: `1px solid ${selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`, }} >
handleItemDragStart(e, file.path)} onDragOver={(e: any) => handleItemDragOver(e, file)} + onDragLeave={(e: any) => handleItemDragLeave(e, file)} onDrop={(e: any) => handleItemDrop(e, file)} initial={{ opacity: 0 }} animate={{ opacity: 1 }} @@ -993,7 +1025,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { onClick={(e) => handleFileClick(file, e)} onContextMenu={(e) => handleContextMenu(e, file)} className={`grid grid-cols-[1fr_100px_140px_40px] gap-4 items-center px-4 py-2.5 rounded-lg cursor-pointer transition-all duration-100 group ${draggedFile === file.path ? 'opacity-50' : ''}`} - style={{ backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'transparent' }} + style={{ backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'transparent' }} >
handleItemDragStart(e, file.path)} onDragOver={(e: any) => handleItemDragOver(e, file)} + onDragLeave={(e: any) => handleItemDragLeave(e, file)} onDrop={(e: any) => handleItemDrop(e, file)} initial={{ opacity: 0 }} animate={{ opacity: 1 }} @@ -1059,7 +1092,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { onClick={(e) => handleFileClick(file, e)} onContextMenu={(e) => handleContextMenu(e, file)} className={`grid grid-cols-[1fr_100px_140px_40px] gap-4 items-center px-4 py-2.5 rounded-lg cursor-pointer transition-all duration-100 group ${draggedFile === file.path ? 'opacity-50' : ''}`} - style={{ backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'transparent' }} + style={{ backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'transparent' }} >