"use client"; import { useAppStore } from "@/components/state-provider"; import type { CommandPanelMode } from "@/lib/commands/types"; import type { ConfigurableShortcutId } from "@/lib/keyboard/shortcut-overrides"; import { getShortcut } from "@/lib/keyboard/shortcut-overrides"; import { formatShortcut } from "@/lib/keyboard/utils"; import { cn } from "@/lib/utils"; import { useTranslation } from "react-i18next"; export type CommandPanelScopeMode = "commands" | "search-tasks" | "search-files" | "search-content"; type ScopeOption = { mode: CommandPanelScopeMode; /** * Catalog key, resolved at render. `mode` stays the untranslated * discriminant — it is compared with `===` in `isCommandPanelScopeMode` and * threaded through the command-panel state. */ labelKey: string; /** Omitted for scopes that are reachable by click and Tab but unbound. */ shortcutId?: ConfigurableShortcutId; /** Scopes that read a checked-out worktree, so they need an open session. */ requiresWorkspace?: boolean; }; const SCOPE_OPTIONS: ScopeOption[] = [ { mode: "commands", labelKey: "common:scopeCommands", shortcutId: "SEARCH" }, { mode: "search-tasks", labelKey: "common:scopeTasks" }, { mode: "search-files", labelKey: "common:scopeFiles", shortcutId: "FILE_SEARCH", requiresWorkspace: true, }, { mode: "search-content", labelKey: "common:scopeContents", shortcutId: "CONTENT_SEARCH", requiresWorkspace: true, }, ]; export function isCommandPanelScopeMode(mode: CommandPanelMode): mode is CommandPanelScopeMode { return SCOPE_OPTIONS.some((scope) => scope.mode === mode); } function availableScopes(workspaceSearchAvailable: boolean): ScopeOption[] { return SCOPE_OPTIONS.filter((scope) => workspaceSearchAvailable || !scope.requiresWorkspace); } /** Commands and Tasks are always reachable, so the switcher always has tabs. */ export function getAvailableCommandPanelScopes( workspaceSearchAvailable: boolean, ): CommandPanelScopeMode[] { return availableScopes(workspaceSearchAvailable).map((scope) => scope.mode); } export function getAdjacentCommandPanelScope( mode: CommandPanelScopeMode, reverse = false, workspaceSearchAvailable = true, ): CommandPanelScopeMode { const scopes = availableScopes(workspaceSearchAvailable); const currentIndex = scopes.findIndex((scope) => scope.mode === mode); const offset = reverse ? -1 : 1; const nextIndex = (currentIndex + offset + scopes.length) % scopes.length; return scopes[nextIndex].mode; } export function CommandPanelScopeSwitcher({ mode, onScopeChange, workspaceSearchAvailable, }: { mode: CommandPanelScopeMode; onScopeChange: (mode: CommandPanelScopeMode) => void; workspaceSearchAvailable: boolean; }) { const { t } = useTranslation(); const keyboardShortcuts = useAppStore((state) => state.userSettings.keyboardShortcuts); return (
{availableScopes(workspaceSearchAvailable).map((scope) => { const active = mode === scope.mode; const shortcut = scope.shortcutId ? formatShortcut(getShortcut(scope.shortcutId, keyboardShortcuts)) : null; const label = t(scope.labelKey); return ( ); })}
); }