diff --git a/backend/Dockerfile b/backend/Dockerfile index f584588..df9b0f8 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -21,6 +21,7 @@ RUN apk add --no-cache \ ffmpeg \ sqlite \ ca-certificates \ + mailcap \ tzdata # Create non-root user diff --git a/backend/handlers/settings.go b/backend/handlers/settings.go index b550426..56000c9 100644 --- a/backend/handlers/settings.go +++ b/backend/handlers/settings.go @@ -39,10 +39,11 @@ func (h *SettingsHandler) UpdateSettings(c *fiber.Ctx) error { } allowedKeys := map[string]bool{ - "theme": true, - "thumbnail_images": true, - "thumbnail_videos": true, - "trash_auto_purge_days": true, + "theme": true, + "thumbnail_images": true, + "thumbnail_videos": true, + "trash_auto_purge_days": true, + "pinned_sidebar_expanded": true, } for key, value := range body { diff --git a/frontend/src/components/FileExplorer.tsx b/frontend/src/components/FileExplorer.tsx index 7935496..135fd3a 100644 --- a/frontend/src/components/FileExplorer.tsx +++ b/frontend/src/components/FileExplorer.tsx @@ -76,6 +76,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { const [searchResults, setSearchResults] = useState(null); const [selectedFiles, setSelectedFiles] = useState>(new Set()); const [contextMenu, setContextMenu] = useState<{ x: number; y: number; file: FileItem } | null>(null); + const [bgContextMenu, setBgContextMenu] = useState<{ x: number; y: number } | null>(null); const [renaming, setRenaming] = useState(null); const [newName, setNewName] = useState(''); const [showNewFolder, setShowNewFolder] = useState(false); @@ -109,6 +110,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { if (s) { if (s.grid_size) setGridSize(s.grid_size); if (s.trash_auto_purge_days) setTrashAutoPurgeDays(parseInt(s.trash_auto_purge_days, 10)); + if (s.pinned_sidebar_expanded === 'true') setPinnedExpanded(true); if (s.pinned_order) { try { setPinnedOrder(JSON.parse(s.pinned_order)); @@ -214,11 +216,12 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { // Close context menu on click outside useEffect(() => { - function handleClick() { + const handleClickOutside = () => { setContextMenu(null); - } - window.addEventListener('click', handleClick); - return () => window.removeEventListener('click', handleClick); + setBgContextMenu(null); + }; + window.addEventListener('click', handleClickOutside); + return () => window.removeEventListener('click', handleClickOutside); }, []); async function loadPinned() { @@ -339,6 +342,14 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { } } + function handleBgContextMenu(e: React.MouseEvent) { + // Only show if the click was on the container itself, not on a file item + if ((e.target as HTMLElement).closest('[data-file-item]')) return; + e.preventDefault(); + setContextMenu(null); + setBgContextMenu({ x: e.clientX, y: e.clientY }); + } + function handleContextMenu(e: React.MouseEvent, file: FileItem) { e.preventDefault(); setContextMenu({ x: e.clientX, y: e.clientY, file }); @@ -724,7 +735,11 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { {/* Pinned Collapsible Section */}