mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
Cmd/Ctrl+K or the search control at the end of the top bar opens a combobox over a client-side index built from the lists the navigation already renders: pages, Insights pages, every Settings section and card (deep-linked by a new anchor prop on SettingsCardHeader), the Appearance sub-pages, module switches and a few actions. Entries follow the module map, the Coach capability, the admin role and a shared record's grant; inside somebody else's record no cards, switches or backup are offered. Ranking is prefix, then word start, then substring, then a small edit distance, then subsequence, with a short multilingual synonym list. The empty state shows recent places (per account, in localStorage) and the main actions. The palette is its own lazily loaded chunk; the top bar shows a search field where it has room and a magnifier otherwise. The module switch mutation moves into a shared hook used by the Modules hub and the palette.
87 lines
3.3 KiB
TypeScript
87 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { Search } from "lucide-react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
import { useMounted } from "@/hooks/use-mounted";
|
|
import { useTranslations } from "@/lib/i18n/context";
|
|
import { isApplePlatform } from "@/lib/keyboard/global-shortcuts";
|
|
|
|
import { openCommandPalette, preloadCommandPalette } from "./palette-store";
|
|
|
|
/**
|
|
* The way into the command palette, at the trailing end of the top bar on
|
|
* every signed-in page. Where the bar has room it looks like a search field
|
|
* ("Search…" and the key that opens it); where it has not (a phone, or a
|
|
* desktop bar narrowed by the sidebar and a docked panel) it is a magnifier
|
|
* with a tooltip. The switch reads the bar's own width (`@container/topbar`
|
|
* on the header), not the window's, because a docked panel takes the room
|
|
* without the window changing.
|
|
*/
|
|
export function CommandPaletteTrigger() {
|
|
const { t } = useTranslations();
|
|
// The key hint depends on the platform, which the server cannot know.
|
|
const mounted = useMounted();
|
|
const apple = mounted && isApplePlatform();
|
|
const label = t("palette.openLabel");
|
|
const keyHint = apple ? "⌘K" : "Ctrl K";
|
|
const shortcut = apple ? "Meta+K" : "Control+K";
|
|
|
|
return (
|
|
<div className="ml-auto flex shrink-0 items-center">
|
|
<button
|
|
type="button"
|
|
data-slot="command-palette-trigger"
|
|
data-variant="field"
|
|
aria-label={label}
|
|
aria-keyshortcuts={mounted ? shortcut : undefined}
|
|
aria-haspopup="dialog"
|
|
onClick={openCommandPalette}
|
|
onPointerEnter={preloadCommandPalette}
|
|
onFocus={preloadCommandPalette}
|
|
className="border-border bg-background text-muted-foreground hover:text-foreground hover:bg-accent focus-visible:ring-ring/50 hidden h-9 w-56 items-center gap-2 rounded-md border px-3 text-sm transition-colors outline-none focus-visible:ring-[3px] @2xl/topbar:flex"
|
|
>
|
|
<Search className="size-4 shrink-0" aria-hidden="true" />
|
|
<span className="flex-1 truncate text-left">{t("palette.open")}</span>
|
|
{mounted ? (
|
|
<kbd
|
|
aria-hidden="true"
|
|
className="border-border bg-muted text-foreground rounded border px-1.5 font-mono text-xs"
|
|
>
|
|
{keyHint}
|
|
</kbd>
|
|
) : null}
|
|
</button>
|
|
<TooltipProvider delayDuration={300}>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
data-slot="command-palette-trigger"
|
|
data-variant="icon"
|
|
aria-label={label}
|
|
aria-keyshortcuts={mounted ? shortcut : undefined}
|
|
aria-haspopup="dialog"
|
|
onClick={openCommandPalette}
|
|
onPointerEnter={preloadCommandPalette}
|
|
onFocus={preloadCommandPalette}
|
|
className="text-muted-foreground hover:text-foreground min-h-11 min-w-11 @2xl/topbar:hidden"
|
|
>
|
|
<Search className="size-5" aria-hidden="true" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom">{label}</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
</div>
|
|
);
|
|
}
|