refactor: remove tab bar — single note open at a time

Replace the multi-tab model with single-note navigation. One note is
open at a time; clicking any note (sidebar, wikilink, relationship)
replaces the current note in the editor. Back/Forward history still
works via Cmd+[/].

Removed: TabBar component, useClosedTabHistory, tab reorder/close/
reopen logic, Cmd+W/Cmd+Shift+T shortcuts, Close Tab and Reopen
Closed Tab menu items, tabLayout utility, and all related tests.

Simplified: useTabManagement (single-note), useAppNavigation (no tab
lookup), useKeyboardNavigation (note nav only), useNoteCreation (no
close-tab cleanup), useDeleteActions (deselect instead of close tab),
Editor (no TabBar render), Rust menu (removed 2 menu items).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Test
2026-03-24 17:24:49 +01:00
parent 8b723b36d9
commit c4136d69b4
30 changed files with 173 additions and 2018 deletions

View File

@@ -1,19 +1,11 @@
import { useEffect, useMemo, useRef } from 'react'
import { isTauri } from '../mock-tauri'
import { filterEntries, sortByModified, buildRelationshipGroups } from '../utils/noteListHelpers'
import type { VaultEntry, SidebarSelection } from '../types'
interface Tab {
entry: VaultEntry
content: string
}
interface KeyboardNavigationOptions {
tabs: Tab[]
activeTabPath: string | null
entries: VaultEntry[]
selection: SidebarSelection
onSwitchTab: (path: string) => void
onReplaceActiveTab: (entry: VaultEntry) => void
onSelectNote: (entry: VaultEntry) => void
}
@@ -29,21 +21,6 @@ function computeVisibleNotes(
return [...filterEntries(entries, selection)].sort(sortByModified)
}
function navigateTab(
tabsRef: React.RefObject<Tab[]>,
activeTabPathRef: React.RefObject<string | null>,
onSwitchTab: React.RefObject<(path: string) => void>,
direction: 1 | -1,
) {
const currentTabs = tabsRef.current!
if (currentTabs.length === 0) return
const currentPath = activeTabPathRef.current
const currentIndex = currentTabs.findIndex((t) => t.entry.path === currentPath)
const nextIndex = (currentIndex + direction + currentTabs.length) % currentTabs.length
onSwitchTab.current!(currentTabs[nextIndex].entry.path)
}
function navigateNote(
visibleNotesRef: React.RefObject<VaultEntry[]>,
activeTabPathRef: React.RefObject<string | null>,
@@ -69,21 +46,6 @@ function navigateNote(
}
}
type ShortcutKind = 'tab' | 'note' | null
function classifyShortcut(e: KeyboardEvent, inTauri: boolean): ShortcutKind {
const mod = e.metaKey || e.ctrlKey
if (!mod) return null
const isTabShortcut = inTauri ? (e.altKey && !e.shiftKey) : (e.shiftKey && !e.altKey)
if (isTabShortcut && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) return 'tab'
if (e.altKey && !e.shiftKey && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) return 'note'
return null
}
function arrowDirection(key: string): 1 | -1 {
return (key === 'ArrowRight' || key === 'ArrowDown') ? 1 : -1
}
function useLatestRef<T>(value: T): React.RefObject<T> {
const ref = useRef(value)
useEffect(() => { ref.current = value })
@@ -91,31 +53,31 @@ function useLatestRef<T>(value: T): React.RefObject<T> {
}
export function useKeyboardNavigation({
tabs, activeTabPath, entries, selection,
onSwitchTab, onReplaceActiveTab, onSelectNote,
activeTabPath, entries, selection,
onReplaceActiveTab, onSelectNote,
}: KeyboardNavigationOptions) {
const visibleNotes = useMemo(
() => computeVisibleNotes(entries, selection),
[entries, selection],
)
const tabsRef = useLatestRef(tabs)
const activeTabPathRef = useLatestRef(activeTabPath)
const visibleNotesRef = useLatestRef(visibleNotes)
const onSwitchTabRef = useLatestRef(onSwitchTab)
const onReplaceRef = useLatestRef(onReplaceActiveTab)
const onSelectNoteRef = useLatestRef(onSelectNote)
useEffect(() => {
const inTauri = isTauri()
const handleKeyDown = (e: KeyboardEvent) => {
const kind = classifyShortcut(e, inTauri)
if (!kind) return
e.preventDefault()
if (kind === 'tab') navigateTab(tabsRef, activeTabPathRef, onSwitchTabRef, arrowDirection(e.key))
else navigateNote(visibleNotesRef, activeTabPathRef, onReplaceRef, onSelectNoteRef, arrowDirection(e.key))
const mod = e.metaKey || e.ctrlKey
if (!mod) return
// Cmd+Alt+ArrowUp/Down: navigate notes in the current list
if (e.altKey && !e.shiftKey && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
e.preventDefault()
const direction: 1 | -1 = e.key === 'ArrowDown' ? 1 : -1
navigateNote(visibleNotesRef, activeTabPathRef, onReplaceRef, onSelectNoteRef, direction)
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [tabsRef, activeTabPathRef, visibleNotesRef, onSwitchTabRef, onReplaceRef, onSelectNoteRef])
}, [activeTabPathRef, visibleNotesRef, onReplaceRef, onSelectNoteRef])
}