Skip to content
File

Blob: src/client/components/icon-picker.tsx

typescript82 lines
1import { useState, useRef } from "react";
2import { SmilePlus, X } from "lucide-react";
3import { Button } from "@/client/components/ui/button";
4import { DropdownPortal } from "@/client/components/ui/dropdown-portal";
5import { EmojiPicker } from "@/client/components/ui/emoji-picker";
6import { EmojiIcon } from "@/client/components/ui/emoji-icon";
7 
8export function IconPicker({
9 currentIcon,
10 onSelect,
11 disabled = false,
12 title,
13}: {
14 currentIcon: string | null;
15 onSelect: (icon: string | null) => void;
16 disabled?: boolean;
17 title?: string;
18}) {
19 const [open, setOpen] = useState(false);
20 const triggerRef = useRef<HTMLButtonElement>(null);
21 
22 return (
23 <>
24 {currentIcon ? (
25 <div className="group/icon flex items-center gap-0.5">
26 <button
27 ref={triggerRef}
28 onClick={() => setOpen((o) => !o)}
29 disabled={disabled}
30 title={title}
31 className="flex items-center rounded-md px-2 py-1 transition-colors hover:bg-zinc-800 disabled:cursor-not-allowed disabled:opacity-50"
32 aria-label="Change icon"
33 >
34 <EmojiIcon emoji={currentIcon} size={28} />
35 </button>
36 <button
37 onClick={() => {
38 onSelect(null);
39 setOpen(false);
40 }}
41 disabled={disabled}
42 title={title}
43 className="flex h-6 w-6 items-center justify-center rounded-md text-zinc-500 opacity-0 transition hover:bg-zinc-700 hover:text-zinc-100 group-hover/icon:opacity-100 disabled:cursor-not-allowed disabled:opacity-50"
44 aria-label="Remove icon"
45 >
46 <X className="h-3.5 w-3.5" />
47 </button>
48 </div>
49 ) : (
50 <Button
51 ref={triggerRef}
52 variant="subtle"
53 size="xs"
54 onClick={() => setOpen((o) => !o)}
55 disabled={disabled}
56 title={title}
57 icon={<SmilePlus className="h-4 w-4" />}
58 >
59 Add icon
60 </Button>
61 )}
62
63 {open && !disabled && (
64 <DropdownPortal
65 triggerRef={triggerRef}
66 align="left"
67 width={360}
68 onClose={() => setOpen(false)}
69 className="border-0 bg-transparent shadow-none"
70 >
71 <EmojiPicker
72 onSelect={(emoji) => {
73 onSelect(emoji);
74 setOpen(false);
75 }}
76 />
77 </DropdownPortal>
78 )}
79 </>
80 );
81}