| import { useState } from 'react'; |
| import * as HugeIcons from 'hugeicons-react'; |
| import iconNames from '../../utils/icon_names.json'; |
|
|
| interface IconPickerProps { |
| onSelect: (iconName: string, color?: string) => void; |
| onClose: () => void; |
| } |
|
|
| export default function IconPicker({ onSelect, onClose }: IconPickerProps) { |
| const [search, setSearch] = useState(''); |
| const [selectedColor, setSelectedColor] = useState<string | undefined>(undefined); |
| |
| const COLORS = [ |
| '#2e6ff2', '#e11d48', '#d97706', '#16a34a', |
| '#9333ea', '#db2777', '#0891b2', '#475569', |
| '#111111' |
| ]; |
|
|
| const filteredIcons = iconNames.filter(name => |
| name.toLowerCase().includes(search.toLowerCase()) |
| ).slice(0, 100); |
|
|
| return ( |
| <div className="icon-picker-overlay" onClick={onClose} style={{ |
| position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, |
| zIndex: 2000, display: 'flex', alignItems: 'center', justifyContent: 'center', |
| backgroundColor: 'rgba(0,0,0,0.2)' |
| }}> |
| <div className="icon-picker" onClick={e => e.stopPropagation()} style={{ |
| background: 'var(--bg-panel)', padding: '16px', borderRadius: '8px', |
| boxShadow: '0 8px 32px rgba(0,0,0,0.15)', width: '400px', maxHeight: '500px', |
| display: 'flex', flexDirection: 'column', border: '1px solid var(--border-color)' |
| }}> |
| <input |
| autoFocus |
| placeholder="Search icons..." |
| value={search} |
| onChange={e => setSearch(e.target.value)} |
| style={{ |
| width: '100%', padding: '10px', marginBottom: '12px', |
| border: '1px solid var(--border-color)', borderRadius: '4px', |
| outline: 'none', fontSize: '14px' |
| }} |
| /> |
| |
| <div className="icon-grid" style={{ |
| display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', |
| gap: '8px', overflowY: 'auto', flex: 1, padding: '4px' |
| }}> |
| {filteredIcons.map(name => { |
| const Icon = (HugeIcons as any)[name]; |
| if (!Icon) return null; |
| return ( |
| <button |
| key={name} |
| onClick={() => { onSelect(name, selectedColor); onClose(); }} |
| title={name} |
| style={{ |
| display: 'flex', alignItems: 'center', justifyContent: 'center', |
| padding: '8px', borderRadius: '4px', background: 'transparent', |
| border: '1px solid transparent', cursor: 'pointer', transition: 'var(--transition-smooth)' |
| }} |
| onMouseEnter={e => e.currentTarget.style.background = 'rgba(0,0,0,0.05)'} |
| onMouseLeave={e => e.currentTarget.style.background = 'transparent'} |
| > |
| <Icon size={20} color={selectedColor || "var(--text-primary)"} /> |
| </button> |
| ); |
| })} |
| </div> |
| |
| <div style={{ marginTop: '12px', borderTop: '1px solid var(--border-color)', paddingTop: '12px', display: 'flex', gap: '8px', justifyContent: 'center' }}> |
| {COLORS.map(c => ( |
| <div |
| key={c} |
| onClick={() => setSelectedColor(c)} |
| style={{ |
| width: '20px', height: '20px', borderRadius: '50%', backgroundColor: c, |
| cursor: 'pointer', border: selectedColor === c ? '2px solid var(--text-primary)' : '2px solid transparent', |
| boxShadow: '0 2px 4px rgba(0,0,0,0.1)' |
| }} |
| /> |
| ))} |
| <div |
| onClick={() => setSelectedColor(undefined)} |
| style={{ |
| width: '20px', height: '20px', borderRadius: '50%', border: '1px dashed var(--text-secondary)', |
| cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '10px' |
| }} |
| > |
| x |
| </div> |
| </div> |
| |
| {filteredIcons.length === 0 && ( |
| <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)' }}> |
| No icons found |
| </div> |
| )} |
| </div> |
| </div> |
| ); |
| } |
|
|