import { useState, useMemo } from 'react' import { useTimeout } from '../utils/useTimeout' import { Icon } from './Icon' import { iconRegistry, type IconRegistryEntry } from './icon-registry' import { Kbd } from './ui/Kbd' import { Badge } from './ui/Badge' type IconItem = IconRegistryEntry /* The curated showcase set — components come straight from the shared registry in Icon.tsx, so there is no second icon list to drift. */ const ICONS: IconItem[] = iconRegistry const CATEGORIES = ['All', 'Navigation', 'Interface', 'System', 'Status'] as const type Category = (typeof CATEGORIES)[number] export function IconMatrix() { const [activeCategory, setActiveCategory] = useState('All') const [search, setSearch] = useState('') const [size, setSize] = useState(20) const [copiedName, setCopiedName] = useState(null) const { schedule } = useTimeout() const filteredIcons = useMemo(() => { return ICONS.filter(icon => { const matchesCategory = activeCategory === 'All' || icon.category === activeCategory const matchesSearch = icon.name.toLowerCase().includes(search.toLowerCase()) || icon.pascalName.toLowerCase().includes(search.toLowerCase()) return matchesCategory && matchesSearch }) }, [activeCategory, search]) const copyUsage = (icon: IconItem) => { const code = `<${icon.pascalName} size={${size}} />` navigator.clipboard?.writeText(code) setCopiedName(icon.name) schedule(() => setCopiedName(null), 2000) } return (
{/* Header controls */}
setSearch(e.target.value)} className="icon-search-input" /> {search && ( )}
Size: {[16, 20, 24].map(s => ( ))}
{/* Category tabs */}
{CATEGORIES.map(cat => ( ))}
{/* Grid of icons */}
{filteredIcons.map(icon => { const isCopied = copiedName === icon.name return ( ) })}
{filteredIcons.length === 0 && (

No icons found

No icon matches "{search}". You can use any of Lucide's 1,400+ icons directly via{' '} lucide-react.

)} {/* Footer usage tip */}
lucide-react Over 1,400+ SVG icons available. Fully tree-shaken and styled via currentColor.
) }