"use client";
import { useState, useEffect } from "react";
import {
Command as CommandIcon,
Search,
Plus,
Settings,
User,
FileText,
FolderPlus,
Download,
Upload,
Share2,
Clock,
Star,
Keyboard,
Moon,
LogOut,
HelpCircle,
Zap,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
type QuickAction = {
id: string;
label: string;
icon: React.ElementType;
shortcut?: string;
description?: string;
category: string;
};
const quickActions: QuickAction[] = [
// Create
{ id: "new-file", label: "New File", icon: FileText, shortcut: "⌘N", category: "Create" },
{ id: "new-folder", label: "New Folder", icon: FolderPlus, shortcut: "⇧⌘N", category: "Create" },
{ id: "new-project", label: "New Project", icon: Plus, category: "Create" },
// Actions
{ id: "upload", label: "Upload File", icon: Upload, shortcut: "⌘U", category: "Actions" },
{ id: "download", label: "Download", icon: Download, shortcut: "⌘D", category: "Actions" },
{ id: "share", label: "Share", icon: Share2, shortcut: "⌘⇧S", category: "Actions" },
// Navigation
{ id: "settings", label: "Settings", icon: Settings, shortcut: "⌘,", category: "Navigation" },
{ id: "profile", label: "Profile", icon: User, category: "Navigation" },
{ id: "shortcuts", label: "Keyboard Shortcuts", icon: Keyboard, shortcut: "⌘/", category: "Navigation" },
// Preferences
{ id: "dark-mode", label: "Toggle Dark Mode", icon: Moon, shortcut: "⌘⇧D", category: "Preferences" },
// Account
{ id: "help", label: "Help & Support", icon: HelpCircle, category: "Account" },
{ id: "logout", label: "Log Out", icon: LogOut, category: "Account" },
];
const recentActions = [
{ id: "new-file", label: "New File", icon: FileText },
{ id: "upload", label: "Upload File", icon: Upload },
{ id: "share", label: "Share", icon: Share2 },
];
export const title = "React Dialog Block Quick Actions";
export default function DialogQuickActions() {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
// Open with keyboard shortcut
useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((open) => !open);
}
};
document.addEventListener("keydown", down);
return () => document.removeEventListener("keydown", down);
}, []);
const handleSelect = (actionId: string) => {
// In real app: execute the action
console.log("Selected action:", actionId);
setOpen(false);
setSearch("");
};
const groupedActions = quickActions.reduce(
(acc, action) => {
if (!acc[action.category]) acc[action.category] = [];
acc[action.category].push(action);
return acc;
},
{} as Record<string, QuickAction[]>
);
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<CommandIcon className="mr-2 h-4 w-4" />
Quick Actions
<Badge variant="secondary" className="ml-2 text-xs">
⌘K
</Badge>
</Button>
</DialogTrigger>
</div>
<DialogContent className="p-0 sm:max-w-md overflow-hidden">
<DialogTitle className="sr-only">Quick Actions</DialogTitle>
<Command className="rounded-lg border-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandInput
placeholder="Search actions..."
value={search}
onValueChange={setSearch}
className="border-0 focus:ring-0"
/>
</div>
<CommandList className="max-h-[400px]">
<CommandEmpty>No actions found.</CommandEmpty>
{/* Recent Actions */}
{!search && (
<>
<CommandGroup heading="Recent">
{recentActions.map((action) => {
const Icon = action.icon;
return (
<CommandItem
key={`recent-${action.id}`}
onSelect={() => handleSelect(action.id)}
className="cursor-pointer"
>
<Clock className="mr-2 h-4 w-4 text-muted-foreground" />
<Icon className="mr-2 h-4 w-4" />
<span>{action.label}</span>
</CommandItem>
);
})}
</CommandGroup>
<CommandSeparator />
</>
)}
{/* Categorized Actions */}
{Object.entries(groupedActions).map(([category, actions]) => (
<CommandGroup key={category} heading={category}>
{actions.map((action) => {
const Icon = action.icon;
return (
<CommandItem
key={action.id}
onSelect={() => handleSelect(action.id)}
className="cursor-pointer"
>
<Icon className="mr-2 h-4 w-4" />
<span>{action.label}</span>
{action.shortcut && (
<CommandShortcut>{action.shortcut}</CommandShortcut>
)}
</CommandItem>
);
})}
</CommandGroup>
))}
</CommandList>
{/* Footer */}
<div className="flex items-center justify-between border-t px-3 py-2">
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Zap className="h-3 w-3" />
<span>Quick Actions</span>
</div>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<kbd className="rounded border px-1.5 py-0.5 text-[10px] font-medium">
↑↓
</kbd>
<span>to navigate</span>
<kbd className="ml-2 rounded border px-1.5 py-0.5 text-[10px] font-medium">
↵
</kbd>
<span>to select</span>
<kbd className="ml-2 rounded border px-1.5 py-0.5 text-[10px] font-medium">
esc
</kbd>
<span>to close</span>
</div>
</div>
</Command>
</DialogContent>
</Dialog>
);
}