From 1b18f11f7dfd63ced1e6f85155d6422f095a404f Mon Sep 17 00:00:00 2001 From: slvnlrt Date: Wed, 18 Mar 2026 21:57:36 +0100 Subject: [PATCH] feat(explorer): wire DEL and Shift+DEL keybinds for file deletion Register explorer.delete (DEL / Cmd+Backspace) and explorer.permanentDelete (Shift+DEL / Cmd+Alt+Backspace) handlers in useExplorerKeyboard, using the same confirm + mutateAsync pattern as the context menu. Clears selection after successful delete. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../explorer/hooks/useExplorerKeyboard.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts b/packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts index b6e68646c..5422ac996 100644 --- a/packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts +++ b/packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts @@ -8,6 +8,7 @@ import { useKeybind } from "../../../hooks/useKeybind"; import { useKeybindScope } from "../../../hooks/useKeybindScope"; import { useClipboard } from "../../../hooks/useClipboard"; import { useFileOperationDialog } from "../../../components/modals/FileOperationModal"; +import { useLibraryMutation } from "../../../contexts/SpacedriveContext"; import { isInputFocused } from "../../../util/keybinds/platform"; export function useExplorerKeyboard() { @@ -36,6 +37,7 @@ export function useExplorerKeyboard() { } = useSelection(); const clipboard = useClipboard(); const openFileOperation = useFileOperationDialog(); + const deleteFiles = useLibraryMutation("files.delete"); // Activate explorer keybind scope when this hook is active useKeybindScope("explorer"); @@ -160,6 +162,66 @@ export function useExplorerKeyboard() { { enabled: selectedFiles.length === 1 }, ); + // Delete: Move to trash + useKeybind( + "explorer.delete", + async () => { + if (selectedFiles.length === 0) return; + const hasVirtual = selectedFiles.some((f) => !f.sd_path); + if (hasVirtual) return; + + const message = + selectedFiles.length > 1 + ? `Delete ${selectedFiles.length} items?` + : `Delete "${selectedFiles[0].name}"?`; + + if (confirm(message)) { + try { + await deleteFiles.mutateAsync({ + targets: { paths: selectedFiles.map((f) => f.sd_path) }, + permanent: false, + recursive: true, + }); + clearSelection(); + } catch (err) { + console.error("Failed to delete:", err); + alert(`Failed to delete: ${err}`); + } + } + }, + { enabled: selectedFiles.length > 0 }, + ); + + // Permanent Delete: Shift+Delete / Cmd+Alt+Backspace + useKeybind( + "explorer.permanentDelete", + async () => { + if (selectedFiles.length === 0) return; + const hasVirtual = selectedFiles.some((f) => !f.sd_path); + if (hasVirtual) return; + + const message = + selectedFiles.length > 1 + ? `Permanently delete ${selectedFiles.length} items? This cannot be undone.` + : `Permanently delete "${selectedFiles[0].name}"? This cannot be undone.`; + + if (confirm(message)) { + try { + await deleteFiles.mutateAsync({ + targets: { paths: selectedFiles.map((f) => f.sd_path) }, + permanent: true, + recursive: true, + }); + clearSelection(); + } catch (err) { + console.error("Failed to delete:", err); + alert(`Failed to delete: ${err}`); + } + } + }, + { enabled: selectedFiles.length > 0 }, + ); + useEffect(() => { const handleKeyDown = async (e: KeyboardEvent) => { // Skip all keyboard shortcuts if renaming or typing in an input