Spaces:
Runtime error
Runtime error
| import { useState } from 'react' | |
| import { theme } from '../theme.ts' | |
| import { isImageSymbol, imageSymbolUrl } from '../binAssets' | |
| interface Props { | |
| current: string | |
| onSelect: (symbol: string) => void | |
| onClose: () => void | |
| } | |
| type Category = 'classic' | 'hearts' | 'emojis' | 'letters' | 'dragons' | |
| const CATEGORIES: { id: Category; label: string }[] = [ | |
| { id: 'classic', label: 'Classic' }, | |
| { id: 'hearts', label: 'Hearts' }, | |
| { id: 'emojis', label: 'Emojis' }, | |
| { id: 'letters', label: 'Letters' }, | |
| { id: 'dragons', label: 'Dragons' }, | |
| ] | |
| const SYMBOLS: Record<Category, string[]> = { | |
| classic: ['X', 'O', 'โ', 'โ', 'โ ', 'โ', 'โ ', 'โฅ', 'โฆ', 'โฃ', 'โซ', 'โช', '๐ต', '๐ด'], | |
| hearts: ['โค๏ธ', '๐งก', '๐', '๐', '๐', '๐', '๐ค', '๐ค', '๐ค', '๐', '๐', '๐'], | |
| emojis: [ | |
| '๐', '๐', '๐คฉ', '๐', '๐', '๐ฅณ', '๐คฏ', '๐', '๐ป', '๐ฝ', | |
| '๐บ', '๐ป', '๐ค', '๐ฅท', '๐ง', '๐ง', '๐ง', '๐ฆธ', '๐ฆน', '๐ง', | |
| '๐', 'โญ', '๐', '๐ฏ', '๐ฅ', '๐', '๐', '๐', '๐ฎ', '๐ฒ', | |
| '๐ธ', '๐ฐ๏ธ', '๐', '๐ช', 'โ๏ธ', '๐ ', '๐', '๐ญ', '๐งญ', 'โ๏ธ', | |
| '๐ฑ', '๐ถ', '๐ฆ', '๐ผ', '๐ฆ', '๐ธ', '๐จ', '๐ฒ', '๐ฌ', '๐ฆ', | |
| '๐', '๐ฆ', '๐ฏ', '๐บ', '๐ฆ ', '๐ฆ', '๐ข', '๐ฆ', '๐ฆ', '๐', | |
| '๐', 'โก', '๐', '๐บ', '๐ธ', '๐ป', '๐', '๐', 'โ๏ธ', 'โ๏ธ', | |
| '๐ฒ', '๐ณ', '๐', '๐ฟ', '๐', '๐', '๐ง', '๐ชจ', '๐ชต', '๐ชท', | |
| '๐', '๐', '๐ฎ', '๐ฉ', '๐ช', '๐', '๐', '๐', | |
| '๐', '๐', '๐', '๐ฅ', '๐ฅจ', '๐', '๐ฃ', '๐', | |
| 'โฝ', '๐', '๐ธ', '๐น', '๐จ', '๐ญ', '๐ท', '๐ก', | |
| '๐น', '๐ฅ', '๐บ', '๐ง', '๐ช', '๐ฌ', '๐น๏ธ', '๐งธ', | |
| 'โ ๏ธ', 'โฅ๏ธ', 'โฆ๏ธ', 'โฃ๏ธ', 'โ๏ธ', '๐ฐ', '๐ฎ', '๐๏ธ', | |
| '๐ก๏ธ', '๐ก๏ธ', '๐ฐ', '๐ฃ', '๐งจ', '๐ช', '๐ต๏ธ', '๐๏ธ', | |
| '๐ช', '๐ง ', '๐', '๐ซถ', '๐ค', '๐', '๐งฉ', '๐ช', | |
| 'โจ', '๐ซ', '๐ฅ', '๐ค', '๐', '๐งฟ', 'โพ๏ธ', 'โ ', | |
| ], | |
| letters: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'], | |
| dragons: Array.from({ length: 20 }, (_, i) => `img:dragon-icons/dragon${i + 1}.png`), | |
| } | |
| export default function SymbolPicker({ current, onSelect, onClose }: Props) { | |
| const [category, setCategory] = useState<Category>('classic') | |
| const symbols = SYMBOLS[category] | |
| return ( | |
| <div | |
| style={{ | |
| position: 'fixed', inset: 0, zIndex: 100, | |
| display: 'flex', alignItems: 'center', justifyContent: 'center', | |
| background: 'rgba(0,0,0,0.5)', | |
| animation: 'fadeIn 0.15s ease', | |
| }} | |
| onClick={onClose} | |
| > | |
| <div | |
| style={{ | |
| background: theme.bgStr, | |
| border: `1px solid ${theme.border}`, | |
| borderRadius: 12, | |
| padding: '1.25rem', | |
| width: 'min(340px, 85vw)', | |
| }} | |
| onClick={(e) => e.stopPropagation()} | |
| > | |
| <span style={{ | |
| color: theme.text, fontWeight: 600, fontSize: '1rem', | |
| display: 'block', marginBottom: '0.75rem', | |
| }}> | |
| Choose Your Symbol | |
| </span> | |
| <div style={{ | |
| display: 'flex', gap: '0.4rem', marginBottom: '0.75rem', | |
| }}> | |
| {CATEGORIES.map((cat) => ( | |
| <button | |
| key={cat.id} | |
| onClick={() => setCategory(cat.id)} | |
| style={{ | |
| flex: 1, | |
| padding: '0.35rem 0.25rem', | |
| fontSize: '0.75rem', | |
| fontWeight: 600, | |
| cursor: 'pointer', | |
| background: category === cat.id ? theme.player1Str : theme.bgPanel, | |
| color: category === cat.id ? '#fff' : theme.textMuted, | |
| border: category === cat.id ? `1px solid ${theme.player1Str}` : `1px solid ${theme.border}`, | |
| borderRadius: 6, | |
| transition: 'all 0.15s ease', | |
| whiteSpace: 'nowrap', | |
| }} | |
| > | |
| {cat.label} | |
| </button> | |
| ))} | |
| </div> | |
| <div style={{ | |
| display: 'flex', flexWrap: 'wrap', gap: '0.6rem', | |
| justifyContent: 'center', | |
| maxHeight: 220, | |
| overflowY: 'auto', | |
| }}> | |
| {symbols.map((s) => { | |
| const isImg = isImageSymbol(s) | |
| return ( | |
| <button | |
| key={s} | |
| onClick={() => { onSelect(s); onClose() }} | |
| style={{ | |
| display: 'flex', alignItems: 'center', justifyContent: 'center', | |
| width: 48, height: 48, | |
| background: s === current ? theme.player1Str : theme.bgPanel, | |
| border: s === current ? `2px solid ${theme.player1Str}` : `1px solid ${theme.border}`, | |
| borderRadius: 8, | |
| cursor: 'pointer', | |
| fontSize: category === 'letters' ? '1.1rem' : '1.3rem', | |
| color: s === current ? '#fff' : theme.text, | |
| transition: 'all 0.15s ease', | |
| flexShrink: 0, | |
| padding: isImg ? 4 : 0, | |
| }} | |
| title={s} | |
| > | |
| {isImg ? ( | |
| <img | |
| src={imageSymbolUrl(s)} | |
| alt="" | |
| style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} | |
| /> | |
| ) : s} | |
| </button> | |
| ) | |
| })} | |
| </div> | |
| </div> | |
| </div> | |
| ) | |
| } | |