Files
tolaria/src/hooks/useCommandRegistry.ts

302 lines
12 KiB
TypeScript
Raw Normal View History

import { useMemo } from 'react'
2026-04-14 11:55:48 +02:00
import type { AiAgentId, AiAgentsStatus } from '../lib/aiAgents'
2026-04-26 08:18:47 +02:00
import type { AppLocale, UiLanguagePreference } from '../lib/i18n'
2026-04-29 02:35:52 +02:00
import type { ThemeMode } from '../lib/themeMode'
import type { VaultAiGuidanceStatus } from '../lib/vaultAiGuidance'
2026-04-29 19:26:24 +02:00
import type { NoteWidthMode, SidebarSelection, VaultEntry } from '../types'
import type { NoteListFilter } from '../utils/noteListHelpers'
import type { ViewMode } from './useViewMode'
import { buildNavigationCommands } from './commands/navigationCommands'
import { buildNoteCommands } from './commands/noteCommands'
import { buildGitCommands } from './commands/gitCommands'
import { buildViewCommands } from './commands/viewCommands'
import { buildSettingsCommands } from './commands/settingsCommands'
2026-04-13 19:37:59 +02:00
import { buildAiAgentCommands } from './commands/aiAgentCommands'
import { buildTypeCommands } from './commands/typeCommands'
import { buildFilterCommands } from './commands/filterCommands'
2026-04-26 19:37:21 +02:00
import { localizeCommandActions } from './commands/localizeCommands'
import { extractVaultTypes } from '../utils/vaultTypes'
import type { GitRepositoryOption } from '../utils/gitRepositories'
// Re-export types and helpers for backward compatibility
export type { CommandAction, CommandGroup } from './commands/types'
export { groupSortKey } from './commands/types'
export { pluralizeType, buildTypeCommands } from './commands/typeCommands'
export { extractVaultTypes } from '../utils/vaultTypes'
export { buildViewCommands } from './commands/viewCommands'
interface CommandRegistryConfig {
activeTabPath: string | null
entries: VaultEntry[]
modifiedCount: number
activeNoteHasIcon?: boolean
mcpStatus?: string
onInstallMcp?: () => void
2026-05-12 22:30:24 +02:00
aiFeaturesEnabled?: boolean
2026-04-14 11:55:48 +02:00
aiAgentsStatus?: AiAgentsStatus
vaultAiGuidanceStatus?: VaultAiGuidanceStatus
2026-04-13 19:37:59 +02:00
onOpenAiAgents?: () => void
onRestoreVaultAiGuidance?: () => void
2026-04-14 11:55:48 +02:00
onSetDefaultAiAgent?: (agent: AiAgentId) => void
selectedAiAgent?: AiAgentId
2026-04-13 19:37:59 +02:00
onCycleDefaultAiAgent?: () => void
selectedAiAgentLabel?: string
onReloadVault?: () => void
onRepairVault?: () => void
onSetNoteIcon?: () => void
onRemoveNoteIcon?: () => void
2026-04-26 08:18:47 +02:00
locale?: AppLocale
systemLocale?: AppLocale
selectedUiLanguage?: UiLanguagePreference
onSetUiLanguage?: (language: UiLanguagePreference) => void
2026-04-29 02:35:52 +02:00
onSetThemeMode?: (mode: ThemeMode) => void
onChangeNoteType?: () => void
onMoveNoteToFolder?: () => void
canMoveNoteToFolder?: boolean
onOpenInNewWindow?: () => void
2026-04-27 01:45:16 +02:00
onRevealActiveFile?: (path: string) => void
onCopyActiveFilePath?: (path: string) => void
onOpenActiveFileExternal?: (path: string) => void
onToggleFavorite?: (path: string) => void
onToggleOrganized?: (path: string) => void
onCustomizeNoteListColumns?: () => void
canCustomizeNoteListColumns?: boolean
2026-04-18 20:31:25 +02:00
noteListColumnsLabel?: string
onRestoreDeletedNote?: () => void
canRestoreDeletedNote?: boolean
onQuickOpen: () => void
onCreateNote: () => void
onCreateNoteOfType: (type: string) => void
onSave: () => void
onPastePlainText: () => void
onOpenSettings: () => void
2026-04-10 12:45:37 +02:00
onOpenFeedback?: () => void
onOpenVault?: () => void
2026-04-19 01:06:40 +02:00
onCreateEmptyVault?: () => void
onAddRemote?: () => void
canAddRemote?: boolean
2026-05-16 12:13:20 +02:00
gitFeaturesEnabled?: boolean
2026-04-26 17:08:14 +02:00
isGitVault?: boolean
gitRepositories?: GitRepositoryOption[]
2026-04-26 17:08:14 +02:00
onInitializeGit?: () => void
onCreateType?: () => void
onDeleteNote: (path: string) => void
onArchiveNote: (path: string) => void
onUnarchiveNote: (path: string) => void
onCommitPush: () => void
onPull?: () => void
onPullRepository?: (path: string) => void
onResolveConflicts?: () => void
onSetViewMode: (mode: ViewMode) => void
onToggleInspector: () => void
onToggleDiff?: () => void
onToggleRawEditor?: () => void
2026-04-28 20:41:07 +02:00
selectedViewName?: string
onMoveSelectedViewUp?: () => void
onMoveSelectedViewDown?: () => void
canMoveSelectedViewUp?: boolean
canMoveSelectedViewDown?: boolean
2026-04-27 10:12:13 +02:00
onFindInNote?: () => void
onReplaceInNote?: () => void
2026-04-29 19:26:24 +02:00
noteWidth?: NoteWidthMode
defaultNoteWidth?: NoteWidthMode
onSetNoteWidth?: (mode: NoteWidthMode) => void
onSetDefaultNoteWidth?: (mode: NoteWidthMode) => void
onToggleAIChat?: () => void
2026-05-06 16:45:18 +02:00
onToggleTableOfContents?: () => void
activeNoteModified: boolean
onCheckForUpdates?: () => void
onZoomIn: () => void
onZoomOut: () => void
onZoomReset: () => void
zoomLevel: number
onSelect: (sel: SidebarSelection) => void
onRenameFolder?: () => void
onDeleteFolder?: () => void
2026-04-27 01:45:16 +02:00
onRevealSelectedFolder?: () => void
onCopySelectedFolderPath?: () => void
showInbox?: boolean
feat: back/forward navigation between opened notes (#75) * feat: add useNavigationHistory hook for browser-style back/forward Pure state management hook that tracks a navigation stack of note paths with cursor-based back/forward traversal. Handles edge cases: duplicate pushes (no-op), forward stack cleared on new push, invalid path skipping, and path removal when tabs close. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: integrate back/forward navigation into UI and keyboard shortcuts - Add Back/Forward arrow buttons to TabBar (left of tabs) - Wire useNavigationHistory through App → Editor → TabBar - Add Cmd+[ and Cmd+] keyboard shortcuts via useAppKeyboard - Register Go Back/Go Forward in command palette - History tracks active tab changes, skips closed tabs gracefully - Navigation from history doesn't re-push to stack (ref guard) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add mouse button 3/4 and trackpad swipe for back/forward - Mouse buttons 3 (back) and 4 (forward) trigger navigation - macOS trackpad two-finger horizontal swipe triggers back/forward using accumulated wheel deltaX with a 120px threshold - Debounced reset after 300ms of inactivity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * design: add back-forward-nav.pen with 3 state frames Shows: default (both disabled), one note visited (back disabled), two notes visited (back enabled). Matches tab bar button placement. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:39:12 +01:00
onGoBack?: () => void
onGoForward?: () => void
canGoBack?: boolean
canGoForward?: boolean
onRemoveActiveVault?: () => void
onRestoreGettingStarted?: () => void
isGettingStartedHidden?: boolean
vaultCount?: number
selection?: SidebarSelection
noteListFilter?: NoteListFilter
onSetNoteListFilter?: (filter: NoteListFilter) => void
}
export function useCommandRegistry(config: CommandRegistryConfig): import('./commands/types').CommandAction[] {
const {
activeTabPath, entries, modifiedCount,
onQuickOpen, onCreateNote, onCreateNoteOfType, onSave, onPastePlainText, onOpenSettings, onOpenFeedback,
onDeleteNote, onArchiveNote, onUnarchiveNote,
2026-04-29 19:26:24 +02:00
onCommitPush, onPull, onResolveConflicts, onSetViewMode, onToggleInspector, onToggleDiff, onToggleRawEditor, onFindInNote, onReplaceInNote,
2026-05-06 16:45:18 +02:00
noteWidth, defaultNoteWidth, onSetNoteWidth, onSetDefaultNoteWidth, onToggleAIChat, onToggleTableOfContents, onOpenVault, onCreateEmptyVault,
2026-04-28 20:41:07 +02:00
selectedViewName, onMoveSelectedViewUp, onMoveSelectedViewDown, canMoveSelectedViewUp, canMoveSelectedViewDown,
activeNoteModified,
onZoomIn, onZoomOut, onZoomReset, zoomLevel,
2026-04-27 01:45:16 +02:00
onSelect, onRenameFolder, onDeleteFolder, onRevealSelectedFolder, onCopySelectedFolderPath,
showInbox,
feat: back/forward navigation between opened notes (#75) * feat: add useNavigationHistory hook for browser-style back/forward Pure state management hook that tracks a navigation stack of note paths with cursor-based back/forward traversal. Handles edge cases: duplicate pushes (no-op), forward stack cleared on new push, invalid path skipping, and path removal when tabs close. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: integrate back/forward navigation into UI and keyboard shortcuts - Add Back/Forward arrow buttons to TabBar (left of tabs) - Wire useNavigationHistory through App → Editor → TabBar - Add Cmd+[ and Cmd+] keyboard shortcuts via useAppKeyboard - Register Go Back/Go Forward in command palette - History tracks active tab changes, skips closed tabs gracefully - Navigation from history doesn't re-push to stack (ref guard) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add mouse button 3/4 and trackpad swipe for back/forward - Mouse buttons 3 (back) and 4 (forward) trigger navigation - macOS trackpad two-finger horizontal swipe triggers back/forward using accumulated wheel deltaX with a 120px threshold - Debounced reset after 300ms of inactivity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * design: add back-forward-nav.pen with 3 state frames Shows: default (both disabled), one note visited (back disabled), two notes visited (back enabled). Matches tab bar button placement. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:39:12 +01:00
onGoBack, onGoForward, canGoBack, canGoForward,
onCheckForUpdates, onCreateType,
onRemoveActiveVault, onRestoreGettingStarted, isGettingStartedHidden, vaultCount,
2026-05-12 22:30:24 +02:00
mcpStatus, onInstallMcp, aiFeaturesEnabled,
aiAgentsStatus, vaultAiGuidanceStatus,
onOpenAiAgents, onRestoreVaultAiGuidance, onSetDefaultAiAgent, selectedAiAgent, onCycleDefaultAiAgent, selectedAiAgentLabel,
onReloadVault, onRepairVault,
2026-04-29 02:35:52 +02:00
locale, systemLocale, selectedUiLanguage, onSetUiLanguage, onSetThemeMode,
onSetNoteIcon, onRemoveNoteIcon, activeNoteHasIcon, onChangeNoteType, onMoveNoteToFolder, canMoveNoteToFolder,
2026-04-27 01:45:16 +02:00
onOpenInNewWindow, onRevealActiveFile, onCopyActiveFilePath, onOpenActiveFileExternal, onToggleFavorite, onToggleOrganized,
onCustomizeNoteListColumns, canCustomizeNoteListColumns,
onRestoreDeletedNote, canRestoreDeletedNote,
selection, noteListFilter, onSetNoteListFilter,
gitFeaturesEnabled, isGitVault, gitRepositories, onInitializeGit, onPullRepository,
} = config
const hasActiveNote = activeTabPath !== null
const activeEntry = useMemo(
() => (hasActiveNote ? entries.find(e => e.path === activeTabPath) : undefined),
[entries, activeTabPath, hasActiveNote],
)
const isArchived = activeEntry?.archived ?? false
const isFavorite = activeEntry?.favorite ?? false
const isSectionGroup = selection?.kind === 'sectionGroup'
2026-04-18 20:31:25 +02:00
const noteListColumnsLabel = config.noteListColumnsLabel ?? (
selection?.kind === 'filter' && selection.filter === 'all'
? 'Customize All Notes columns'
: 'Customize Inbox columns'
)
const vaultTypes = useMemo(() => extractVaultTypes(entries), [entries])
2026-04-26 19:37:21 +02:00
const navigationCommands = useMemo(() => buildNavigationCommands({
onQuickOpen,
onSelect,
selection,
2026-04-26 19:37:21 +02:00
onRenameFolder,
onDeleteFolder,
2026-04-27 01:45:16 +02:00
onRevealSelectedFolder,
onCopySelectedFolderPath,
2026-04-26 19:37:21 +02:00
showInbox,
onGoBack,
onGoForward,
canGoBack,
canGoForward,
}), [
onQuickOpen, onSelect, selection, onRenameFolder, onDeleteFolder,
2026-04-27 01:45:16 +02:00
onRevealSelectedFolder, onCopySelectedFolderPath, showInbox,
onGoBack, onGoForward, canGoBack, canGoForward,
2026-04-26 19:37:21 +02:00
])
const noteCommands = useMemo(() => buildNoteCommands({
2026-04-27 01:45:16 +02:00
hasActiveNote, activeTabPath, activeFileKind: activeEntry?.fileKind ?? 'markdown', isArchived,
2026-04-26 19:37:21 +02:00
onCreateNote, onCreateType, onSave,
onFindInNote, onReplaceInNote, onPastePlainText,
2026-04-26 19:37:21 +02:00
onDeleteNote, onArchiveNote, onUnarchiveNote,
onChangeNoteType, onMoveNoteToFolder, canMoveNoteToFolder,
2026-04-27 01:45:16 +02:00
onSetNoteIcon, onRemoveNoteIcon, activeNoteHasIcon, onOpenInNewWindow,
onRevealActiveFile, onCopyActiveFilePath, onOpenActiveFileExternal,
onToggleFavorite, isFavorite,
2026-04-26 19:37:21 +02:00
onToggleOrganized, isOrganized: activeEntry?.organized ?? false,
onRestoreDeletedNote, canRestoreDeletedNote,
}), [
2026-04-27 01:45:16 +02:00
hasActiveNote, activeTabPath, activeEntry?.fileKind, isArchived,
onCreateNote, onCreateType, onSave, onFindInNote, onReplaceInNote, onPastePlainText, onDeleteNote, onArchiveNote, onUnarchiveNote,
2026-04-26 19:37:21 +02:00
onChangeNoteType, onMoveNoteToFolder, canMoveNoteToFolder,
2026-04-27 01:45:16 +02:00
onSetNoteIcon, onRemoveNoteIcon, activeNoteHasIcon, onOpenInNewWindow,
onRevealActiveFile, onCopyActiveFilePath, onOpenActiveFileExternal,
onToggleFavorite, isFavorite,
2026-04-26 19:37:21 +02:00
onToggleOrganized, activeEntry?.organized, onRestoreDeletedNote, canRestoreDeletedNote,
])
2026-04-26 19:37:21 +02:00
const gitCommands = useMemo(() => buildGitCommands({
modifiedCount,
2026-05-16 12:13:20 +02:00
gitFeaturesEnabled,
2026-04-26 19:37:21 +02:00
isGitVault,
repositories: gitRepositories,
2026-04-26 19:37:21 +02:00
canAddRemote: config.canAddRemote ?? false,
onAddRemote: config.onAddRemote,
onCommitPush,
onInitializeGit,
onPull,
onPullRepository,
2026-04-26 19:37:21 +02:00
onResolveConflicts,
onSelect,
}), [
modifiedCount, gitFeaturesEnabled, isGitVault, gitRepositories, config.canAddRemote, config.onAddRemote,
onCommitPush, onInitializeGit, onPull, onPullRepository, onResolveConflicts, onSelect,
2026-04-26 19:37:21 +02:00
])
const viewCommands = useMemo(() => buildViewCommands({
2026-05-12 22:30:24 +02:00
aiFeaturesEnabled,
2026-04-26 19:37:21 +02:00
hasActiveNote, activeNoteModified, onSetViewMode, onToggleInspector,
2026-05-06 16:45:18 +02:00
onToggleDiff, onToggleRawEditor, noteWidth, defaultNoteWidth, onSetNoteWidth, onSetDefaultNoteWidth, onToggleAIChat, onToggleTableOfContents, zoomLevel, onZoomIn, onZoomOut, onZoomReset,
2026-04-26 19:37:21 +02:00
onCustomizeNoteListColumns, canCustomizeNoteListColumns, noteListColumnsLabel,
2026-04-28 20:41:07 +02:00
selectedViewName, onMoveSelectedViewUp, onMoveSelectedViewDown, canMoveSelectedViewUp, canMoveSelectedViewDown,
2026-04-26 19:37:21 +02:00
}), [
2026-05-12 22:30:24 +02:00
aiFeaturesEnabled,
2026-04-26 19:37:21 +02:00
hasActiveNote, activeNoteModified, onSetViewMode, onToggleInspector,
2026-05-06 16:45:18 +02:00
onToggleDiff, onToggleRawEditor, noteWidth, defaultNoteWidth, onSetNoteWidth, onSetDefaultNoteWidth, onToggleAIChat, onToggleTableOfContents,
2026-04-26 19:37:21 +02:00
zoomLevel, onZoomIn, onZoomOut, onZoomReset,
onCustomizeNoteListColumns, canCustomizeNoteListColumns, noteListColumnsLabel,
2026-04-28 20:41:07 +02:00
selectedViewName, onMoveSelectedViewUp, onMoveSelectedViewDown, canMoveSelectedViewUp, canMoveSelectedViewDown,
2026-04-26 19:37:21 +02:00
])
const settingsCommands = useMemo(() => buildSettingsCommands({
mcpStatus, vaultCount, isGettingStartedHidden,
onOpenSettings, onOpenFeedback, onOpenVault, onCreateEmptyVault, onRemoveActiveVault, onRestoreGettingStarted,
onCheckForUpdates, onInstallMcp, onReloadVault, onRepairVault,
2026-04-29 02:35:52 +02:00
locale, systemLocale, selectedUiLanguage, onSetUiLanguage, onSetThemeMode,
2026-04-26 19:37:21 +02:00
}), [
mcpStatus, vaultCount, isGettingStartedHidden, onOpenSettings, onOpenFeedback,
onOpenVault, onCreateEmptyVault, onRemoveActiveVault, onRestoreGettingStarted,
onCheckForUpdates, onInstallMcp, onReloadVault, onRepairVault,
2026-04-29 02:35:52 +02:00
locale, systemLocale, selectedUiLanguage, onSetUiLanguage, onSetThemeMode,
2026-04-26 19:37:21 +02:00
])
const aiCommands = useMemo(() => buildAiAgentCommands({
2026-05-12 22:30:24 +02:00
aiFeaturesEnabled,
2026-04-26 19:37:21 +02:00
aiAgentsStatus,
vaultAiGuidanceStatus,
selectedAiAgent,
selectedAiAgentLabel,
onOpenAiAgents,
onRestoreVaultAiGuidance,
onSetDefaultAiAgent,
onCycleDefaultAiAgent,
}), [
2026-05-12 22:30:24 +02:00
aiFeaturesEnabled,
2026-04-26 19:37:21 +02:00
aiAgentsStatus, vaultAiGuidanceStatus, selectedAiAgent, selectedAiAgentLabel,
onOpenAiAgents, onRestoreVaultAiGuidance, onSetDefaultAiAgent, onCycleDefaultAiAgent,
])
const typeCommands = useMemo(
() => buildTypeCommands(vaultTypes, onCreateNoteOfType, onSelect),
[vaultTypes, onCreateNoteOfType, onSelect],
)
const filterCommands = useMemo(
() => buildFilterCommands({ isSectionGroup, noteListFilter, onSetNoteListFilter }),
[isSectionGroup, noteListFilter, onSetNoteListFilter],
)
const commands = useMemo(() => [
...navigationCommands,
...noteCommands,
...gitCommands,
...viewCommands,
...settingsCommands,
...aiCommands,
...typeCommands,
...filterCommands,
], [
navigationCommands, noteCommands, gitCommands, viewCommands,
settingsCommands, aiCommands, typeCommands, filterCommands,
])
return useMemo(() => localizeCommandActions(commands, locale), [commands, locale])
}