Files
sofa/components/keyboard-help-dialog.tsx
T
jake dcb48eaf37 Add /dashboard route, mark-all-watched on complete, keyboard fixes
- Move dashboard page to app/(pages)/dashboard, redirect / to /dashboard
  for authenticated users, update all nav/breadcrumb/auth hrefs
- Mark all episodes watched when a TV show status is set to "completed"
  (markAllEpisodesWatched skips already-watched episodes)
- Refactor KeyboardProvider to store shortcuts in a ref instead of
  state, eliminating unnecessary re-renders; use react-hotkeys-hook for
  Cmd+K so it works reliably in form inputs
- Fix useRegisterShortcut: re-register on every render (stable ref read)
  with a separate cleanup effect, removing brittle key memoization
- Search page: silently navigate to title detail on import instead of
  showing "Added to library" toast
2026-03-01 11:06:26 -05:00

78 lines
2.5 KiB
TypeScript

"use client";
import { useKeyboard } from "@/components/keyboard-provider";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Kbd } from "@/components/ui/kbd";
export function KeyboardHelpDialog() {
const { shortcutsRef, helpOpen, setHelpOpen } = useKeyboard();
// Group shortcuts by scope
const grouped: Record<string, { description: string; keys: string[] }[]> = {};
for (const def of shortcutsRef.current.values()) {
const scope = def.scope ?? "Global";
if (!grouped[scope]) grouped[scope] = [];
grouped[scope].push({ description: def.description, keys: def.keys });
}
return (
<Dialog open={helpOpen} onOpenChange={setHelpOpen}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Keyboard Shortcuts</DialogTitle>
</DialogHeader>
<div className="space-y-5 py-2">
{Object.entries(grouped).map(([scope, items]) => (
<div key={scope} className="space-y-2">
<h3 className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
{scope}
</h3>
<div className="space-y-1">
{items.map((item) => (
<div
key={item.description}
className="flex items-center justify-between rounded-md px-2 py-1.5"
>
<span className="text-xs text-foreground">
{item.description}
</span>
<div className="flex items-center gap-1">
{item.keys.map((key, i) => (
<span key={key} className="flex items-center gap-1">
{i > 0 && (
<span className="text-[10px] text-muted-foreground">
then
</span>
)}
<Kbd>{formatKey(key)}</Kbd>
</span>
))}
</div>
</div>
))}
</div>
</div>
))}
</div>
</DialogContent>
</Dialog>
);
}
function formatKey(key: string): string {
const map: Record<string, string> = {
" ": "Space",
Escape: "Esc",
ArrowUp: "↑",
ArrowDown: "↓",
ArrowLeft: "←",
ArrowRight: "→",
};
return map[key] ?? key.toUpperCase();
}