"use client";
import { useState, useMemo } from "react";
import { Search, Command } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area";
const shortcuts = {
General: [
{ keys: ["⌘", "K"], action: "Open command palette" },
{ keys: ["⌘", "S"], action: "Save changes" },
{ keys: ["⌘", "Z"], action: "Undo" },
{ keys: ["⌘", "⇧", "Z"], action: "Redo" },
{ keys: ["⌘", "/"], action: "Toggle shortcuts" },
],
Navigation: [
{ keys: ["⌘", "↑"], action: "Go to top" },
{ keys: ["⌘", "↓"], action: "Go to bottom" },
{ keys: ["⌘", "←"], action: "Go back" },
{ keys: ["⌘", "→"], action: "Go forward" },
{ keys: ["G", "H"], action: "Go to home" },
{ keys: ["G", "S"], action: "Go to settings" },
],
Editing: [
{ keys: ["⌘", "B"], action: "Bold text" },
{ keys: ["⌘", "I"], action: "Italic text" },
{ keys: ["⌘", "U"], action: "Underline text" },
{ keys: ["⌘", "⇧", "K"], action: "Delete line" },
{ keys: ["⌘", "D"], action: "Duplicate line" },
{ keys: ["⌘", "Enter"], action: "Submit form" },
],
View: [
{ keys: ["⌘", "+"], action: "Zoom in" },
{ keys: ["⌘", "-"], action: "Zoom out" },
{ keys: ["⌘", "0"], action: "Reset zoom" },
{ keys: ["⌘", "\\"], action: "Toggle sidebar" },
{ keys: ["F11"], action: "Toggle fullscreen" },
],
};
export const title = "React Dialog Block Keyboard Shortcuts";
export default function DialogKeyboardShortcuts() {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
const filteredShortcuts = useMemo(() => {
if (!search.trim()) return shortcuts;
const searchLower = search.toLowerCase();
const filtered: typeof shortcuts = {} as typeof shortcuts;
Object.entries(shortcuts).forEach(([category, items]) => {
const matchingItems = items.filter(
(item) =>
item.action.toLowerCase().includes(searchLower) ||
item.keys.join("").toLowerCase().includes(searchLower)
);
if (matchingItems.length > 0) {
filtered[category as keyof typeof shortcuts] = matchingItems;
}
});
return filtered;
}, [search]);
const hasResults = Object.keys(filteredShortcuts).length > 0;
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Command className="mr-2 h-4 w-4" />
Keyboard Shortcuts
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-lg p-0 gap-0">
<DialogHeader className="px-6 pt-6 pb-4">
<DialogTitle>Keyboard Shortcuts</DialogTitle>
</DialogHeader>
<div className="px-6 pb-4">
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search shortcuts..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="pl-9"
/>
</div>
</div>
<ScrollArea className="max-h-[400px] px-6 pb-6">
{hasResults ? (
<div className="space-y-6">
{Object.entries(filteredShortcuts).map(([category, items]) => (
<div key={category}>
<h3 className="text-sm font-medium text-muted-foreground mb-3">
{category}
</h3>
<div className="space-y-2">
{items.map((shortcut, index) => (
<div
key={index}
className="flex items-center justify-between py-2"
>
<span className="text-sm">{shortcut.action}</span>
<div className="flex items-center gap-1">
{shortcut.keys.map((key, keyIndex) => (
<kbd
key={keyIndex}
className="inline-flex h-6 min-w-6 items-center justify-center rounded border bg-muted px-1.5 text-xs font-medium"
>
{key}
</kbd>
))}
</div>
</div>
))}
</div>
</div>
))}
</div>
) : (
<div className="py-8 text-center">
<p className="text-sm text-muted-foreground">
No shortcuts found for "{search}"
</p>
</div>
)}
</ScrollArea>
</DialogContent>
</Dialog>
);
}