import type { ProjectIconColor, ProjectIconOverride } from "@t3tools/contracts"; import { DynamicIcon, type IconName } from "lucide-react/dynamic"; import { useEffect, useMemo, useRef, useState } from "react"; import { filterProjectIconNames, firstEmoji, PROJECT_EMOJIS, PROJECT_ICON_COLORS, projectIconColorClassName, } from "../../projectIconOptions"; import { cn } from "~/lib/utils"; import { Button } from "../ui/button"; import { Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, } from "../ui/dialog"; import { Input } from "../ui/input"; import { ScrollArea } from "../ui/scroll-area"; import { Toggle, ToggleGroup } from "../ui/toggle-group"; const DEFAULT_ICON: IconName = "folder-code"; const DEFAULT_COLOR: ProjectIconColor = "blue"; function iconLabel(name: string): string { return name .split("-") .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(" "); } export function ProjectIconPickerDialog({ current, open, onOpenChange, onSelect, }: { readonly current: ProjectIconOverride | null; readonly open: boolean; readonly onOpenChange: (open: boolean) => void; readonly onSelect: (icon: ProjectIconOverride) => void; }) { const [mode, setMode] = useState<"lucide" | "emoji">( current?.kind === "emoji" ? "emoji" : "lucide", ); const [iconName, setIconName] = useState( current?.kind === "lucide" ? (current.name as IconName) : DEFAULT_ICON, ); const [color, setColor] = useState( current?.kind === "lucide" ? current.color : DEFAULT_COLOR, ); const [emoji, setEmoji] = useState(current?.kind === "emoji" ? current.emoji : "💻"); const [query, setQuery] = useState(""); const [customEmoji, setCustomEmoji] = useState(""); const previousOpenRef = useRef(false); useEffect(() => { if (open && !previousOpenRef.current) { setMode(current?.kind === "emoji" ? "emoji" : "lucide"); setIconName(current?.kind === "lucide" ? (current.name as IconName) : DEFAULT_ICON); setColor(current?.kind === "lucide" ? current.color : DEFAULT_COLOR); setEmoji(current?.kind === "emoji" ? current.emoji : "💻"); setQuery(""); setCustomEmoji(""); } previousOpenRef.current = open; }, [current, open]); const icons = useMemo(() => filterProjectIconNames(query), [query]); const selectedColorClassName = projectIconColorClassName(color); const save = () => { onSelect( mode === "lucide" ? { kind: "lucide", name: iconName, color } : { kind: "emoji", emoji }, ); onOpenChange(false); }; return ( Choose project icon Pick any Lucide icon and color, or use an emoji. { const value = next[0]; if (value === "lucide" || value === "emoji") setMode(value); }} > Icons Emoji {mode === "lucide" ? ( <>
Color
{PROJECT_ICON_COLORS.map((option) => ( ))}
setQuery(event.currentTarget.value)} />
{icons.map((name) => ( ))}
{icons.length === 0 ? (

No icons found.

) : null} ) : ( <>
{PROJECT_EMOJIS.map((option) => ( ))}
Or paste any emoji
{ const value = event.currentTarget.value; setCustomEmoji(value); const nextEmoji = firstEmoji(value); if (nextEmoji) setEmoji(nextEmoji); }} />
)}
); }