From d475143e8a1e6839eca8d12cd55c1dc1c28b5784 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Sat, 21 Feb 2026 17:37:15 +0100 Subject: [PATCH] feat: breadcrumb trash/restore buttons and cmd+del shortcut - Added trash icon button in breadcrumb bar for non-trashed notes - Added restore (arrow counter-clockwise) button for trashed notes - Trash button sets trashed=true and trashed_at in frontmatter - Restore button removes trashed/trashed_at from frontmatter - Added Cmd+Delete keyboard shortcut to trash active note - Wired handlers through Editor -> App with vault entry updates - Toast notifications for trash/restore actions Co-Authored-By: Claude Opus 4.6 --- src/App.tsx | 18 ++++++++++++++++++ src/components/BreadcrumbBar.tsx | 22 ++++++++++++++++++++++ src/components/Editor.tsx | 5 +++++ src/hooks/useAppKeyboard.ts | 12 ++++++++++-- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 10265e39..d830731f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -112,10 +112,26 @@ function App() { vault.updateEntry(typeEntry.path, { icon, color }) }, [vault, notes]) + const handleTrashNote = useCallback(async (path: string) => { + const now = new Date().toISOString().slice(0, 10) + await notes.handleUpdateFrontmatter(path, 'trashed', true) + await notes.handleUpdateFrontmatter(path, 'trashed_at', now) + vault.updateEntry(path, { trashed: true, trashedAt: Date.now() / 1000 }) + setToastMessage('Note moved to trash') + }, [notes, vault, setToastMessage]) + + const handleRestoreNote = useCallback(async (path: string) => { + await notes.handleUpdateFrontmatter(path, 'trashed', false) + await notes.handleDeleteProperty(path, 'trashed_at') + vault.updateEntry(path, { trashed: false, trashedAt: null }) + setToastMessage('Note restored from trash') + }, [notes, vault, setToastMessage]) + useAppKeyboard({ onQuickOpen: () => setShowQuickOpen(true), onCreateNote: openCreateDialog, onSave: () => setToastMessage('Saved'), + onTrashNote: handleTrashNote, activeTabPathRef: notes.activeTabPathRef, handleCloseTabRef: notes.handleCloseTabRef, }) @@ -193,6 +209,8 @@ function App() { showAIChat={showAIChat} onToggleAIChat={() => setShowAIChat(c => !c)} vaultPath={vaultPath} + onTrashNote={handleTrashNote} + onRestoreNote={handleRestoreNote} /> diff --git a/src/components/BreadcrumbBar.tsx b/src/components/BreadcrumbBar.tsx index 89f128c6..c05b2418 100644 --- a/src/components/BreadcrumbBar.tsx +++ b/src/components/BreadcrumbBar.tsx @@ -8,6 +8,8 @@ import { Sparkle, SlidersHorizontal, DotsThree, + Trash, + ArrowCounterClockwise, } from '@phosphor-icons/react' interface BreadcrumbBarProps { @@ -22,6 +24,8 @@ interface BreadcrumbBarProps { onToggleAIChat?: () => void inspectorCollapsed?: boolean onToggleInspector?: () => void + onTrash?: () => void + onRestore?: () => void } const DISABLED_ICON_STYLE = { opacity: 0.4, cursor: 'not-allowed' } as const @@ -29,6 +33,7 @@ const DISABLED_ICON_STYLE = { opacity: 0.4, cursor: 'not-allowed' } as const export const BreadcrumbBar = memo(function BreadcrumbBar({ entry, wordCount, isModified, showDiffToggle, diffMode, diffLoading, onToggleDiff, showAIChat, onToggleAIChat, inspectorCollapsed, onToggleInspector, + onTrash, onRestore, }: BreadcrumbBarProps) { return (
+ {entry.trashed ? ( + + ) : ( + + )} {inspectorCollapsed && (