diff --git a/src/components/Editor.test.tsx b/src/components/Editor.test.tsx index 2ebaa1b0..5cc9ae51 100644 --- a/src/components/Editor.test.tsx +++ b/src/components/Editor.test.tsx @@ -300,7 +300,7 @@ describe('Editor', () => { const trashedTab = { entry: trashedEntry, content: mockContent } function renderTrashed(overrides: Partial[0]> = {}) { - return render() + return render() } it('shows banner and read-only editor when note is trashed', () => { @@ -336,9 +336,10 @@ describe('Editor', () => { ) expect(screen.queryByTestId('trashed-note-banner')).not.toBeInTheDocument() - const updatedTab = { entry: { ...mockEntry, trashed: true, trashedAt: Date.now() / 1000 }, content: mockContent } + const trashedEntryUpdated = { ...mockEntry, trashed: true, trashedAt: Date.now() / 1000 } + const updatedTab = { entry: trashedEntryUpdated, content: mockContent } rerender( - + ) expect(screen.getByTestId('trashed-note-banner')).toBeInTheDocument() expect(screen.getByTestId('blocknote-view')).toHaveAttribute('data-editable', 'false') @@ -346,13 +347,14 @@ describe('Editor', () => { it('removes trash banner immediately when entry is restored (reactive)', () => { const { rerender } = render( - + ) expect(screen.getByTestId('trashed-note-banner')).toBeInTheDocument() - const restoredTab = { entry: { ...trashedEntry, trashed: false, trashedAt: null }, content: mockContent } + const restoredEntry = { ...trashedEntry, trashed: false, trashedAt: null } + const restoredTab = { entry: restoredEntry, content: mockContent } rerender( - + ) expect(screen.queryByTestId('trashed-note-banner')).not.toBeInTheDocument() expect(screen.getByTestId('blocknote-view')).toHaveAttribute('data-editable', 'true') @@ -408,6 +410,7 @@ describe('click empty editor space', () => { render( @@ -429,9 +432,10 @@ describe('archived note behavior', () => { ) expect(screen.queryByTestId('archived-note-banner')).not.toBeInTheDocument() - const archivedTab = { entry: { ...mockEntry, archived: true }, content: mockContent } + const archivedEntry = { ...mockEntry, archived: true } + const archivedTab = { entry: archivedEntry, content: mockContent } rerender( - + ) expect(screen.getByTestId('archived-note-banner')).toBeInTheDocument() }) @@ -440,13 +444,14 @@ describe('archived note behavior', () => { const archivedEntry: VaultEntry = { ...mockEntry, archived: true } const archivedTab = { entry: archivedEntry, content: mockContent } const { rerender } = render( - + ) expect(screen.getByTestId('archived-note-banner')).toBeInTheDocument() - const unarchivedTab = { entry: { ...archivedEntry, archived: false }, content: mockContent } + const unarchivedEntry = { ...archivedEntry, archived: false } + const unarchivedTab = { entry: unarchivedEntry, content: mockContent } rerender( - + ) expect(screen.queryByTestId('archived-note-banner')).not.toBeInTheDocument() }) diff --git a/src/components/EditorContent.tsx b/src/components/EditorContent.tsx index edd4d324..aacc9647 100644 --- a/src/components/EditorContent.tsx +++ b/src/components/EditorContent.tsx @@ -161,7 +161,11 @@ export function EditorContent({ isConflicted, onKeepMine, onKeepTheirs, ...breadcrumbProps }: EditorContentProps) { - const isTrashed = activeTab?.entry.trashed ?? false + // Look up trashed/archived from the latest vault entries, not the tab snapshot, + // so the banner appears regardless of navigation context. + const freshEntry = activeTab ? entries.find(e => e.path === activeTab.entry.path) : undefined + const isTrashed = freshEntry?.trashed ?? activeTab?.entry.trashed ?? false + const isArchived = freshEntry?.archived ?? activeTab?.entry.archived ?? false const showEditor = !diffMode && !rawMode const entryIcon = activeTab?.entry.icon ?? null const emojiIcon = entryIcon && isEmoji(entryIcon) ? entryIcon : null @@ -188,7 +192,7 @@ export function EditorContent({ onDeletePermanently={() => onDeleteNote?.(activeTab.entry.path)} /> )} - {activeTab?.entry.archived && breadcrumbProps.onUnarchiveNote && ( + {activeTab && isArchived && breadcrumbProps.onUnarchiveNote && ( breadcrumbProps.onUnarchiveNote!(activeTab.entry.path)} /> )} {activeTab && isConflicted && ( diff --git a/src/components/Sidebar.test.tsx b/src/components/Sidebar.test.tsx index 9269d82f..37adccf7 100644 --- a/src/components/Sidebar.test.tsx +++ b/src/components/Sidebar.test.tsx @@ -1038,4 +1038,24 @@ describe('Sidebar', () => { const mondaySections = screen.getAllByText(/Monday Ideas/i) expect(mondaySections).toHaveLength(1) }) + + it('renders Inbox as the first item in the top nav', () => { + render( {}} inboxCount={5} />) + const topNav = screen.getByTestId('sidebar-top-nav') + const items = topNav.children + expect(items[0].textContent).toContain('Inbox') + expect(items[1].textContent).toContain('All Notes') + }) + + it('displays inbox count badge', () => { + render( {}} inboxCount={12} />) + expect(screen.getByText('12')).toBeInTheDocument() + }) + + it('calls onSelect with inbox filter when clicking Inbox', () => { + const onSelect = vi.fn() + render() + fireEvent.click(screen.getByText('Inbox')) + expect(onSelect).toHaveBeenCalledWith({ kind: 'filter', filter: 'inbox' }) + }) }) diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 6230cf5e..6be6f01b 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -306,10 +306,10 @@ export const Sidebar = memo(function Sidebar({