Fix appearance persistence and add drag over folder highlighting
All checks were successful
Automated Container Build / build-and-push (push) Successful in 32s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 32s
This commit is contained in:
parent
d532f8d064
commit
425598c278
1 changed files with 39 additions and 6 deletions
|
|
@ -89,9 +89,28 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
const [movingFiles, setMovingFiles] = useState<string[]>([]);
|
const [movingFiles, setMovingFiles] = useState<string[]>([]);
|
||||||
const [moveModalPath, setMoveModalPath] = useState('.');
|
const [moveModalPath, setMoveModalPath] = useState('.');
|
||||||
const [moveFolders, setMoveFolders] = useState<FileItem[]>([]);
|
const [moveFolders, setMoveFolders] = useState<FileItem[]>([]);
|
||||||
|
const [dragOverFolder, setDragOverFolder] = useState<string | null>(null);
|
||||||
const searchTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
const searchTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(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
|
// Load files on path change
|
||||||
const loadFiles = useCallback(async (path?: string) => {
|
const loadFiles = useCallback(async (path?: string) => {
|
||||||
const targetPath = path ?? currentPath;
|
const targetPath = path ?? currentPath;
|
||||||
|
|
@ -339,10 +358,20 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
if (!file.is_dir) return;
|
if (!file.is_dir) return;
|
||||||
if (draggedFile === file.path) return;
|
if (draggedFile === file.path) return;
|
||||||
e.preventDefault();
|
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) {
|
async function handleItemDrop(e: React.DragEvent, file: FileItem) {
|
||||||
if (!file.is_dir) return;
|
if (!file.is_dir) return;
|
||||||
|
setDragOverFolder(null);
|
||||||
const sourcePath = e.dataTransfer.getData('text/plain');
|
const sourcePath = e.dataTransfer.getData('text/plain');
|
||||||
if (!sourcePath || sourcePath === file.path) return;
|
if (!sourcePath || sourcePath === file.path) return;
|
||||||
|
|
||||||
|
|
@ -829,6 +858,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
draggable
|
draggable
|
||||||
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
||||||
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
||||||
|
onDragLeave={(e: any) => handleItemDragLeave(e, file)}
|
||||||
onDrop={(e: any) => handleItemDrop(e, file)}
|
onDrop={(e: any) => handleItemDrop(e, file)}
|
||||||
initial={{ opacity: 0, scale: 0.95 }}
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
|
@ -837,8 +867,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
onContextMenu={(e) => handleContextMenu(e, file)}
|
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' : ''}`}
|
className={`group relative p-4 rounded-xl cursor-pointer transition-all duration-150 border-2 ${draggedFile === file.path ? 'opacity-50' : ''}`}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)',
|
backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)',
|
||||||
border: `1px solid ${selectedFiles.has(file.path) ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`,
|
border: `1px solid ${selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -907,6 +937,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
draggable
|
draggable
|
||||||
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
||||||
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
||||||
|
onDragLeave={(e: any) => handleItemDragLeave(e, file)}
|
||||||
onDrop={(e: any) => handleItemDrop(e, file)}
|
onDrop={(e: any) => handleItemDrop(e, file)}
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
|
@ -915,8 +946,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
onContextMenu={(e) => handleContextMenu(e, file)}
|
onContextMenu={(e) => handleContextMenu(e, file)}
|
||||||
className={`group relative p-4 rounded-xl cursor-pointer transition-all duration-150 ${draggedFile === file.path ? 'opacity-50' : ''}`}
|
className={`group relative p-4 rounded-xl cursor-pointer transition-all duration-150 ${draggedFile === file.path ? 'opacity-50' : ''}`}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: selectedFiles.has(file.path) ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)',
|
backgroundColor: selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)',
|
||||||
border: `1px solid ${selectedFiles.has(file.path) ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`,
|
border: `1px solid ${selectedFiles.has(file.path) || dragOverFolder === file.path ? 'var(--color-accent)' : 'var(--color-border-subtle)'}`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -986,6 +1017,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
draggable
|
draggable
|
||||||
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
||||||
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
||||||
|
onDragLeave={(e: any) => handleItemDragLeave(e, file)}
|
||||||
onDrop={(e: any) => handleItemDrop(e, file)}
|
onDrop={(e: any) => handleItemDrop(e, file)}
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
|
|
@ -993,7 +1025,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
onClick={(e) => handleFileClick(file, e)}
|
onClick={(e) => handleFileClick(file, e)}
|
||||||
onContextMenu={(e) => handleContextMenu(e, file)}
|
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' : ''}`}
|
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' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<input
|
<input
|
||||||
|
|
@ -1052,6 +1084,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
draggable
|
draggable
|
||||||
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
onDragStart={(e: any) => handleItemDragStart(e, file.path)}
|
||||||
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
onDragOver={(e: any) => handleItemDragOver(e, file)}
|
||||||
|
onDragLeave={(e: any) => handleItemDragLeave(e, file)}
|
||||||
onDrop={(e: any) => handleItemDrop(e, file)}
|
onDrop={(e: any) => handleItemDrop(e, file)}
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
|
|
@ -1059,7 +1092,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
|
||||||
onClick={(e) => handleFileClick(file, e)}
|
onClick={(e) => handleFileClick(file, e)}
|
||||||
onContextMenu={(e) => handleContextMenu(e, file)}
|
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' : ''}`}
|
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' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
Reference in a new issue