diff --git a/apps/web/src/app/games/matching/components/EmojiPicker.tsx b/apps/web/src/app/games/matching/components/EmojiPicker.tsx index 85a10521..d6fc72d1 100644 --- a/apps/web/src/app/games/matching/components/EmojiPicker.tsx +++ b/apps/web/src/app/games/matching/components/EmojiPicker.tsx @@ -27,8 +27,20 @@ interface EmojiPickerProps { playerNumber: 1 | 2 | 3 | 4 } -// Create a map of emoji to their searchable data -const emojiMap = new Map() +// Emoji group categories from emojibase +const EMOJI_GROUPS = { + 0: { name: 'Smileys & People', icon: '😀' }, + 1: { name: 'Animals & Nature', icon: '🐶' }, + 2: { name: 'Food & Drink', icon: '🍎' }, + 3: { name: 'Activities', icon: '⚽' }, + 4: { name: 'Travel & Places', icon: '🚗' }, + 5: { name: 'Objects', icon: '💡' }, + 6: { name: 'Symbols', icon: '❤️' }, + 7: { name: 'Flags', icon: '🏁' } +} as const + +// Create a map of emoji to their searchable data and group +const emojiMap = new Map() ;(emojiData as EmojibaseEmoji[]).forEach((emoji) => { if (emoji.emoji) { // Handle emoticon field which can be string, array, or undefined @@ -46,7 +58,8 @@ const emojiMap = new Map() emoji.label?.toLowerCase(), ...(emoji.tags || []).map((tag: string) => tag.toLowerCase()), ...emoticons - ].filter(Boolean) + ].filter(Boolean), + group: emoji.group }) } }) @@ -71,13 +84,27 @@ function getEmojiKeywords(emoji: string): string[] { export function EmojiPicker({ currentEmoji, onEmojiSelect, onClose, playerNumber }: EmojiPickerProps) { const [searchFilter, setSearchFilter] = useState('') + const [selectedCategory, setSelectedCategory] = useState(null) // Enhanced search functionality - clear separation between default and search const isSearching = searchFilter.trim().length > 0 + const isCategoryFiltered = selectedCategory !== null && !isSearching const displayEmojis = useMemo(() => { + // Start with all emojis + let emojis = PLAYER_EMOJIS + + // Apply category filter first (unless searching) + if (isCategoryFiltered) { + emojis = emojis.filter(emoji => { + const data = emojiMap.get(emoji) + return data && data.group === selectedCategory + }) + } + + // Then apply search filter if (!isSearching) { - return PLAYER_EMOJIS + return emojis } const searchTerm = searchFilter.toLowerCase().trim() @@ -116,7 +143,7 @@ export function EmojiPicker({ currentEmoji, onEmojiSelect, onClose, playerNumber }) return sortedResults - }, [searchFilter, isSearching]) + }, [searchFilter, isSearching, selectedCategory, isCategoryFiltered]) return (
+ {/* Category Tabs */} + {!isSearching && ( +
+ + {Object.entries(EMOJI_GROUPS).map(([groupId, group]) => ( + + ))} +
+ )} + {/* Search Mode Header */} {isSearching && displayEmojis.length > 0 && (
- 📝 All Available Characters + {selectedCategory !== null + ? `${EMOJI_GROUPS[selectedCategory as keyof typeof EMOJI_GROUPS].icon} ${EMOJI_GROUPS[selectedCategory as keyof typeof EMOJI_GROUPS].name}` + : '📝 All Available Characters'}
- {PLAYER_EMOJIS.length} characters available • Use search to find specific emojis + {displayEmojis.length} emojis {selectedCategory !== null ? 'in category' : 'available'} • Use search to find specific emojis
)} @@ -311,23 +405,41 @@ export function EmojiPicker({ currentEmoji, onEmojiSelect, onClose, playerNumber {displayEmojis.length > 0 && (
+
{displayEmojis.map(emoji => { const isSelected = emoji === currentEmoji const getSelectedBg = () => { @@ -381,6 +493,7 @@ export function EmojiPicker({ currentEmoji, onEmojiSelect, onClose, playerNumber ) })} +
)}