import { useState, useMemo, useCallback, useRef, useEffect } from 'react' import { MagnifyingGlass } from '@phosphor-icons/react' import { ICON_OPTIONS, type IconEntry } from '../utils/iconRegistry' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Textarea } from '@/components/ui/textarea' import { translate, type AppLocale } from '../lib/i18n' import { AccentColorPicker } from './AccentColorPicker' function filterIcons(icons: IconEntry[], query: string): IconEntry[] { if (!query) return icons const lower = query.toLowerCase() return icons.filter((o) => o.name.includes(lower)) } interface TypeCustomizePopoverProps { currentIcon: string | null currentColor: string | null currentTemplate: string | null onChangeIcon: (icon: string) => void onChangeColor: (color: string) => void onChangeTemplate: (template: string) => void onClose: () => void showTemplate?: boolean showDone?: boolean surface?: 'popover' | 'inline' locale?: AppLocale } interface ColorSectionProps { selectedColor: string | null locale: AppLocale onSelectColor: (key: string) => void } interface IconSectionProps { selectedIcon: string | null search: string filteredIcons: IconEntry[] locale: AppLocale onSearchChange: (query: string) => void onSelectIcon: (name: string) => void } interface TemplateSectionProps { templateText: string locale: AppLocale onTemplateChange: (value: string) => void } const ICON_PICKER_ICON_SIZE = 18 const ICON_PICKER_ICON_CLASS_NAME = 'size-[18px]' /** Debounce a callback by `delay` ms. Returns a stable ref-based wrapper. */ function useDebouncedCallback(fn: (v: string) => void, delay: number): (v: string) => void { const timerRef = useRef | undefined>(undefined) const fnRef = useRef(fn) useEffect(() => { fnRef.current = fn }) useEffect(() => () => { clearTimeout(timerRef.current) }, []) return useCallback((v: string) => { clearTimeout(timerRef.current) timerRef.current = setTimeout(() => fnRef.current(v), delay) }, [delay]) } function ColorSection({ selectedColor, locale, onSelectColor }: ColorSectionProps) { return ( <>
{translate(locale, 'customize.color')}
) } function IconSection({ selectedIcon, search, filteredIcons, locale, onSearchChange, onSelectIcon, }: IconSectionProps) { return ( <>
{translate(locale, 'customize.icon')}
onSearchChange(event.target.value)} placeholder={translate(locale, 'customize.searchIcons')} className="h-7 pl-7 pr-2 py-1 text-[12px]" />
{filteredIcons.length === 0 ? (
{translate(locale, 'customize.noIconsFound')}
) : ( filteredIcons.map(({ name, Icon }) => ( )) )}
) } function TemplateSection({ templateText, locale, onTemplateChange }: TemplateSectionProps) { return ( <>
{translate(locale, 'customize.template')}