Skip to content

Commit 163bff0

Browse files
committed
feat: implement Search component with dropdown menu and keyboard shortcut
1 parent 5e54b22 commit 163bff0

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

app/desktop/search.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client"
2+
import { SearchIcon } from "@/components/icons/search";
3+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
4+
import { useEffect, useState } from "react";
5+
import { WindowsCommand } from "./windows-command";
6+
import { Input } from "@/components/ui/input";
7+
import { SkeletonCard } from "@/components/ui/skeleton-card";
8+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
9+
import { appConfig } from "@/configs/app";
10+
import { useRouter } from "next/navigation";
11+
import { PowerIcon } from "lucide-react";
12+
13+
export default function Search() {
14+
15+
const [openWindows, setOpenWindows] = useState(false);
16+
17+
// Ctrl + k show setOpenWindows(true)
18+
useEffect(() => {
19+
const handleKeyDown = (e: KeyboardEvent) => {
20+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
21+
e.preventDefault();
22+
setOpenWindows(true);
23+
}
24+
};
25+
window.addEventListener('keydown', handleKeyDown);
26+
return () => window.removeEventListener('keydown', handleKeyDown);
27+
}, []);
28+
29+
const router = useRouter();
30+
const logout = () => {
31+
setTimeout(() => { router.push('/'); }, 1000);
32+
}
33+
34+
return (
35+
<>
36+
<DropdownMenu>
37+
<DropdownMenuTrigger asChild>
38+
<button type="button" className="relative flex cursor-pointer items-center justify-center size-9 rounded-lg hover:bg-white hover:shadow-lg duration-400 shadow-black/10 transition-colors">
39+
<SearchIcon className="text-gray-500 size-6" />
40+
</button>
41+
</DropdownMenuTrigger>
42+
<DropdownMenuContent side="top" align="center" className="w-xl rounded-t-3xl p-0 mb-2">
43+
44+
<div className="p-4 mt-2">
45+
<Input type="search" placeholder="Search..." />
46+
</div>
47+
48+
<div className="flex gap-0 h-96">
49+
<div className="w-40 shrink-0 overflow-y-auto overflow-x-hidden h-full p-2">
50+
<DropdownMenuItem onClick={() => console.log('Settings clicked')}>
51+
⚙️ Settings
52+
</DropdownMenuItem>
53+
<DropdownMenuItem onClick={() => console.log('File Explorer clicked')}>
54+
📁 File Explorer
55+
</DropdownMenuItem>
56+
<DropdownMenuSeparator />
57+
<DropdownMenuItem onClick={() => console.log('Power Options clicked')}>
58+
⚡ Power Options
59+
</DropdownMenuItem>
60+
<DropdownMenuItem onClick={() => console.log('Sign out clicked')}>
61+
👤 Sign out
62+
</DropdownMenuItem>
63+
</div>
64+
65+
<div className="w-full grid sm:grid-cols-3 gap-3 overflow-y-auto p-3">
66+
<SkeletonCard />
67+
<SkeletonCard />
68+
<SkeletonCard />
69+
</div>
70+
</div>
71+
72+
<div className="px-4 py-2 border-t flex gap-5 justify-between items-center">
73+
<DropdownMenuItem className="px-2" onClick={() => console.log('Sign out clicked')}>
74+
<div className="flex gap-2 items-center">
75+
<Avatar>
76+
<AvatarImage src="/profile.png" />
77+
<AvatarFallback>SL</AvatarFallback>
78+
</Avatar>
79+
<div className="text-sm font-medium font-sans">{appConfig.name}</div>
80+
</div>
81+
</DropdownMenuItem>
82+
83+
<DropdownMenuItem className="p-2" onClick={logout}>
84+
<PowerIcon className="size-4.5 text-foreground/60" />
85+
</DropdownMenuItem>
86+
</div>
87+
</DropdownMenuContent>
88+
</DropdownMenu>
89+
<WindowsCommand open={openWindows} onOpenChange={setOpenWindows} />
90+
</>
91+
);
92+
}

0 commit comments

Comments
 (0)