diff --git a/src/client/index.tsx b/src/client/index.tsx index 6ab7e05..b9ad2a2 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -3,14 +3,13 @@ import { define, Styles } from 'forge' import type { App, AppState } from '../shared/types' import { theme } from './themes' import { Modal, initModal } from './tags/modal' +import { initUpdate } from './update' import { openEmojiPicker } from './tags/emoji-picker' // UI state (survives re-renders) let selectedApp: string | null = localStorage.getItem('selectedApp') let sidebarCollapsed: boolean = localStorage.getItem('sidebarCollapsed') === 'true' -const DEFAULT_EMOJI = '๐Ÿ–ฅ๏ธ' - // Server state (from SSE) let apps: App[] = [] @@ -382,7 +381,7 @@ const AppDetail = ({ app }: { app: App }) => ( <> - {app.icon ?? DEFAULT_EMOJI} + {app.icon}   {app.name} @@ -510,10 +509,10 @@ const Dashboard = () => { title={sidebarCollapsed ? app.name : undefined} > {sidebarCollapsed ? ( - {app.icon ?? DEFAULT_EMOJI} + {app.icon} ) : ( <> - {app.icon ?? DEFAULT_EMOJI} + {app.icon} {app.name} @@ -543,8 +542,9 @@ const render = () => { renderApp(, document.getElementById('app')!) } -// Initialize modal with render function +// Initialize render functions initModal(render) +initUpdate(render) // Set theme based on system preference const setTheme = () => { diff --git a/src/client/tags/emoji-picker.tsx b/src/client/tags/emoji-picker.tsx index 06d34bf..77a3e31 100644 --- a/src/client/tags/emoji-picker.tsx +++ b/src/client/tags/emoji-picker.tsx @@ -1,6 +1,7 @@ import { define } from 'forge' import { theme } from '../themes' -import { openModal, closeModal, rerenderModal } from './modal' +import { openModal, closeModal } from './modal' +import { update } from '../update' type Category = 'People' | 'Gestures' | 'Animals' | 'Food' | 'Activities' | 'Travel' | 'Objects' | 'Symbols' | 'Nature' @@ -16,6 +17,1067 @@ const CATEGORY_ICONS: Record = { 'Nature': '๐ŸŒธ', } +// Keywords for searching emojis +const EMOJI_KEYWORDS: Record = { + // People + '๐Ÿ˜€': ['smile', 'happy', 'grin', 'face'], + '๐Ÿ˜ƒ': ['smile', 'happy', 'grin', 'face', 'open'], + '๐Ÿ˜„': ['smile', 'happy', 'grin', 'face', 'eyes'], + '๐Ÿ˜': ['smile', 'happy', 'grin', 'teeth'], + '๐Ÿ˜†': ['laugh', 'happy', 'haha', 'xd'], + '๐Ÿ˜…': ['sweat', 'nervous', 'laugh', 'awkward'], + '๐Ÿคฃ': ['rofl', 'laugh', 'lol', 'rolling'], + '๐Ÿ˜‚': ['laugh', 'cry', 'tears', 'joy', 'lol', 'funny'], + '๐Ÿ™‚': ['smile', 'slight', 'okay'], + '๐Ÿ™ƒ': ['upside', 'sarcasm', 'irony'], + '๐Ÿ˜‰': ['wink', 'flirt'], + '๐Ÿ˜Š': ['blush', 'smile', 'happy', 'shy'], + '๐Ÿ˜‡': ['angel', 'innocent', 'halo'], + '๐Ÿฅฐ': ['love', 'hearts', 'adore', 'crush'], + '๐Ÿ˜': ['love', 'heart', 'eyes', 'crush', 'adore'], + '๐Ÿคฉ': ['star', 'eyes', 'excited', 'wow', 'amazing'], + '๐Ÿ˜˜': ['kiss', 'love', 'blow'], + '๐Ÿ˜—': ['kiss', 'whistle'], + '๐Ÿ˜š': ['kiss', 'blush'], + '๐Ÿ˜™': ['kiss', 'smile'], + '๐Ÿฅฒ': ['tear', 'smile', 'sad', 'bittersweet'], + '๐Ÿ˜‹': ['yum', 'delicious', 'tongue', 'tasty'], + '๐Ÿ˜›': ['tongue', 'playful', 'silly'], + '๐Ÿ˜œ': ['wink', 'tongue', 'crazy', 'silly'], + '๐Ÿคช': ['crazy', 'wild', 'zany', 'silly'], + '๐Ÿ˜': ['tongue', 'squint', 'playful'], + '๐Ÿค‘': ['money', 'rich', 'dollar', 'greed'], + '๐Ÿค—': ['hug', 'hands', 'embrace'], + '๐Ÿคญ': ['oops', 'giggle', 'hand', 'mouth'], + '๐Ÿคซ': ['shush', 'quiet', 'secret', 'ssh'], + '๐Ÿค”': ['think', 'hmm', 'wonder', 'curious'], + '๐Ÿค': ['zip', 'mouth', 'quiet', 'secret'], + '๐Ÿคจ': ['eyebrow', 'skeptical', 'doubt'], + '๐Ÿ˜': ['neutral', 'meh', 'blank'], + '๐Ÿ˜‘': ['expressionless', 'annoyed', 'meh'], + '๐Ÿ˜ถ': ['silent', 'speechless', 'no mouth'], + '๐Ÿ˜': ['smirk', 'smug', 'flirt'], + '๐Ÿ˜’': ['unamused', 'bored', 'meh'], + '๐Ÿ™„': ['eyeroll', 'annoyed', 'whatever'], + '๐Ÿ˜ฌ': ['grimace', 'awkward', 'nervous', 'teeth'], + '๐Ÿคฅ': ['lie', 'pinocchio', 'nose'], + '๐Ÿ˜Œ': ['relieved', 'peaceful', 'calm'], + '๐Ÿ˜”': ['sad', 'down', 'pensive'], + '๐Ÿ˜ช': ['sleepy', 'tired', 'snot'], + '๐Ÿคค': ['drool', 'hungry', 'want'], + '๐Ÿ˜ด': ['sleep', 'zzz', 'tired', 'snore'], + '๐Ÿ˜ท': ['sick', 'mask', 'covid', 'ill'], + '๐Ÿค’': ['sick', 'fever', 'thermometer', 'ill'], + '๐Ÿค•': ['hurt', 'injured', 'bandage', 'head'], + '๐Ÿคข': ['nausea', 'sick', 'gross', 'green'], + '๐Ÿคฎ': ['vomit', 'puke', 'sick', 'throw up'], + '๐Ÿคง': ['sneeze', 'sick', 'tissue', 'achoo'], + '๐Ÿฅต': ['hot', 'heat', 'sweat', 'fever'], + '๐Ÿฅถ': ['cold', 'freeze', 'ice', 'frozen'], + '๐Ÿฅด': ['woozy', 'drunk', 'dizzy', 'tipsy'], + '๐Ÿ˜ต': ['dizzy', 'dead', 'knocked out'], + '๐Ÿคฏ': ['mind blown', 'explode', 'shocked', 'wow'], + '๐Ÿค ': ['cowboy', 'yeehaw', 'western', 'hat'], + '๐Ÿฅณ': ['party', 'celebrate', 'birthday', 'hat'], + '๐Ÿฅธ': ['disguise', 'glasses', 'nose', 'incognito'], + '๐Ÿ˜Ž': ['cool', 'sunglasses', 'awesome'], + '๐Ÿค“': ['nerd', 'geek', 'glasses', 'smart'], + '๐Ÿง': ['monocle', 'fancy', 'inspect', 'curious'], + '๐Ÿ˜•': ['confused', 'unsure', 'worried'], + '๐Ÿ˜Ÿ': ['worried', 'concerned', 'anxious'], + '๐Ÿ™': ['sad', 'frown', 'unhappy'], + '๐Ÿ˜ฎ': ['wow', 'surprised', 'open mouth'], + '๐Ÿ˜ฏ': ['surprised', 'hushed', 'wow'], + '๐Ÿ˜ฒ': ['astonished', 'shocked', 'wow'], + '๐Ÿ˜ณ': ['flushed', 'embarrassed', 'blush'], + '๐Ÿฅบ': ['pleading', 'puppy eyes', 'please', 'uwu'], + '๐Ÿ˜ฆ': ['frown', 'open mouth', 'worried'], + '๐Ÿ˜ง': ['anguished', 'worried', 'shocked'], + '๐Ÿ˜จ': ['fearful', 'scared', 'afraid'], + '๐Ÿ˜ฐ': ['anxious', 'sweat', 'worried', 'nervous'], + '๐Ÿ˜ฅ': ['sad', 'disappointed', 'relieved'], + '๐Ÿ˜ข': ['cry', 'sad', 'tear'], + '๐Ÿ˜ญ': ['sob', 'cry', 'tears', 'sad', 'bawling'], + '๐Ÿ˜ฑ': ['scream', 'scared', 'horror', 'fear'], + '๐Ÿ˜–': ['confounded', 'frustrated'], + '๐Ÿ˜ฃ': ['persevere', 'struggle', 'frustrated'], + '๐Ÿ˜ž': ['disappointed', 'sad', 'let down'], + '๐Ÿ˜“': ['sweat', 'tired', 'stressed'], + '๐Ÿ˜ฉ': ['weary', 'tired', 'frustrated'], + '๐Ÿ˜ซ': ['tired', 'exhausted', 'frustrated'], + '๐Ÿฅฑ': ['yawn', 'tired', 'bored', 'sleepy'], + '๐Ÿ˜ค': ['angry', 'huff', 'frustrated', 'steam'], + '๐Ÿ˜ก': ['angry', 'mad', 'rage', 'red'], + '๐Ÿ˜ ': ['angry', 'mad', 'annoyed'], + '๐Ÿคฌ': ['swear', 'curse', 'angry', 'symbols'], + '๐Ÿ˜ˆ': ['devil', 'evil', 'mischief', 'purple'], + '๐Ÿ‘ฟ': ['devil', 'angry', 'evil', 'imp'], + '๐Ÿ’€': ['skull', 'dead', 'death', 'skeleton'], + 'โ˜ ๏ธ': ['skull', 'crossbones', 'death', 'danger', 'poison'], + '๐Ÿ’ฉ': ['poop', 'poo', 'shit', 'crap'], + '๐Ÿคก': ['clown', 'circus', 'fool'], + '๐Ÿ‘น': ['ogre', 'monster', 'demon', 'japanese'], + '๐Ÿ‘บ': ['goblin', 'tengu', 'monster', 'japanese'], + '๐Ÿ‘ป': ['ghost', 'boo', 'spooky', 'halloween'], + '๐Ÿ‘ฝ': ['alien', 'ufo', 'extraterrestrial', 'space'], + '๐Ÿ‘พ': ['alien', 'monster', 'game', 'space invader'], + '๐Ÿค–': ['robot', 'bot', 'android', 'machine'], + + // Gestures + '๐Ÿ‘‹': ['wave', 'hello', 'bye', 'hand'], + '๐Ÿคš': ['raised', 'hand', 'stop', 'back'], + '๐Ÿ–๏ธ': ['hand', 'five', 'fingers', 'spread'], + 'โœ‹': ['hand', 'stop', 'high five'], + '๐Ÿ––': ['vulcan', 'spock', 'star trek', 'hand'], + '๐Ÿ‘Œ': ['ok', 'okay', 'perfect', 'hand'], + '๐ŸคŒ': ['pinched', 'italian', 'chef', 'fingers'], + '๐Ÿค': ['pinch', 'small', 'tiny', 'little'], + 'โœŒ๏ธ': ['peace', 'victory', 'two', 'fingers'], + '๐Ÿคž': ['crossed', 'fingers', 'luck', 'hope'], + '๐ŸคŸ': ['love', 'rock', 'hand', 'ily'], + '๐Ÿค˜': ['rock', 'metal', 'horns', 'hand'], + '๐Ÿค™': ['call', 'shaka', 'hang loose', 'phone'], + '๐Ÿ‘ˆ': ['left', 'point', 'finger'], + '๐Ÿ‘‰': ['right', 'point', 'finger'], + '๐Ÿ‘†': ['up', 'point', 'finger'], + '๐Ÿ–•': ['middle finger', 'fuck', 'flip off'], + '๐Ÿ‘‡': ['down', 'point', 'finger'], + 'โ˜๏ธ': ['up', 'point', 'finger', 'one'], + '๐Ÿ‘': ['thumbs up', 'like', 'yes', 'good', 'ok'], + '๐Ÿ‘Ž': ['thumbs down', 'dislike', 'no', 'bad'], + 'โœŠ': ['fist', 'power', 'punch', 'solidarity'], + '๐Ÿ‘Š': ['fist bump', 'punch', 'bro'], + '๐Ÿค›': ['fist', 'left', 'bump'], + '๐Ÿคœ': ['fist', 'right', 'bump'], + '๐Ÿ‘': ['clap', 'applause', 'hands', 'bravo'], + '๐Ÿ™Œ': ['hands', 'raise', 'celebrate', 'praise'], + '๐Ÿ‘': ['hands', 'open', 'hug'], + '๐Ÿคฒ': ['palms', 'up', 'hands', 'prayer'], + '๐Ÿค': ['handshake', 'deal', 'agree', 'meet'], + '๐Ÿ™': ['pray', 'please', 'thanks', 'namaste', 'hands'], + 'โœ๏ธ': ['write', 'hand', 'pen', 'sign'], + '๐Ÿ’…': ['nails', 'polish', 'manicure', 'sassy'], + '๐Ÿคณ': ['selfie', 'phone', 'camera'], + '๐Ÿ’ช': ['muscle', 'strong', 'flex', 'arm', 'bicep'], + '๐Ÿฆพ': ['robot', 'arm', 'prosthetic', 'mechanical'], + '๐Ÿฆฟ': ['leg', 'prosthetic', 'mechanical'], + '๐Ÿฆต': ['leg', 'kick', 'limb'], + '๐Ÿฆถ': ['foot', 'kick', 'stomp'], + '๐Ÿ‘‚': ['ear', 'listen', 'hear'], + '๐Ÿฆป': ['ear', 'hearing aid', 'deaf'], + '๐Ÿ‘ƒ': ['nose', 'smell', 'sniff'], + '๐Ÿง ': ['brain', 'smart', 'think', 'mind'], + '๐Ÿซ€': ['heart', 'organ', 'anatomical'], + '๐Ÿซ': ['lungs', 'breathe', 'organ'], + '๐Ÿฆท': ['tooth', 'teeth', 'dental'], + '๐Ÿฆด': ['bone', 'skeleton', 'dog'], + '๐Ÿ‘€': ['eyes', 'look', 'see', 'watch'], + '๐Ÿ‘๏ธ': ['eye', 'see', 'look', 'watch'], + '๐Ÿ‘…': ['tongue', 'lick', 'taste'], + '๐Ÿ‘„': ['lips', 'mouth', 'kiss'], + + // Animals + '๐Ÿถ': ['dog', 'puppy', 'pet', 'woof'], + '๐Ÿฑ': ['cat', 'kitty', 'pet', 'meow'], + '๐Ÿญ': ['mouse', 'rat', 'rodent'], + '๐Ÿน': ['hamster', 'pet', 'rodent'], + '๐Ÿฐ': ['rabbit', 'bunny', 'pet'], + '๐ŸฆŠ': ['fox', 'animal', 'cute'], + '๐Ÿป': ['bear', 'teddy', 'animal'], + '๐Ÿผ': ['panda', 'bear', 'china'], + '๐Ÿปโ€โ„๏ธ': ['polar bear', 'arctic', 'white'], + '๐Ÿจ': ['koala', 'australia', 'bear'], + '๐Ÿฏ': ['tiger', 'cat', 'stripes'], + '๐Ÿฆ': ['lion', 'king', 'cat', 'mane'], + '๐Ÿฎ': ['cow', 'moo', 'farm'], + '๐Ÿท': ['pig', 'oink', 'farm'], + '๐Ÿธ': ['frog', 'toad', 'ribbit', 'kermit'], + '๐Ÿต': ['monkey', 'ape', 'chimp'], + '๐Ÿ™ˆ': ['monkey', 'see no evil', 'hide'], + '๐Ÿ™‰': ['monkey', 'hear no evil'], + '๐Ÿ™Š': ['monkey', 'speak no evil'], + '๐Ÿ’': ['monkey', 'ape', 'primate'], + '๐Ÿ”': ['chicken', 'hen', 'bird', 'farm'], + '๐Ÿง': ['penguin', 'bird', 'cold', 'arctic'], + '๐Ÿฆ': ['bird', 'tweet', 'fly'], + '๐Ÿค': ['chick', 'bird', 'baby', 'chicken'], + '๐Ÿฃ': ['chick', 'hatching', 'egg', 'bird'], + '๐Ÿฅ': ['chick', 'bird', 'baby'], + '๐Ÿฆ†': ['duck', 'bird', 'quack'], + '๐Ÿฆ…': ['eagle', 'bird', 'america', 'fly'], + '๐Ÿฆ‰': ['owl', 'bird', 'night', 'wise'], + '๐Ÿฆ‡': ['bat', 'vampire', 'night', 'fly'], + '๐Ÿบ': ['wolf', 'howl', 'dog'], + '๐Ÿ—': ['boar', 'pig', 'wild'], + '๐Ÿด': ['horse', 'pony', 'neigh'], + '๐Ÿฆ„': ['unicorn', 'horse', 'magic', 'rainbow'], + '๐Ÿ': ['bee', 'honey', 'buzz', 'insect'], + '๐Ÿชฑ': ['worm', 'bug', 'insect'], + '๐Ÿ›': ['bug', 'caterpillar', 'insect'], + '๐Ÿฆ‹': ['butterfly', 'insect', 'pretty'], + '๐ŸŒ': ['snail', 'slow', 'slug'], + '๐Ÿž': ['ladybug', 'insect', 'bug'], + '๐Ÿœ': ['ant', 'insect', 'bug'], + '๐Ÿชฐ': ['fly', 'insect', 'bug'], + '๐Ÿชฒ': ['beetle', 'bug', 'insect'], + '๐Ÿชณ': ['cockroach', 'bug', 'insect', 'roach'], + '๐ŸฆŸ': ['mosquito', 'bug', 'insect', 'bite'], + '๐Ÿฆ—': ['cricket', 'bug', 'insect'], + '๐Ÿ•ท๏ธ': ['spider', 'bug', 'web', 'creepy'], + '๐Ÿฆ‚': ['scorpion', 'bug', 'sting'], + '๐Ÿข': ['turtle', 'slow', 'shell', 'tortoise'], + '๐Ÿ': ['snake', 'reptile', 'hiss'], + '๐ŸฆŽ': ['lizard', 'reptile', 'gecko'], + '๐Ÿฆ–': ['dinosaur', 't-rex', 'tyrannosaurus'], + '๐Ÿฆ•': ['dinosaur', 'brontosaurus', 'sauropod'], + '๐Ÿ™': ['octopus', 'sea', 'tentacles'], + '๐Ÿฆ‘': ['squid', 'sea', 'tentacles'], + '๐Ÿฆ': ['shrimp', 'seafood', 'prawn'], + '๐Ÿฆž': ['lobster', 'seafood', 'crab'], + '๐Ÿฆ€': ['crab', 'seafood', 'beach'], + '๐Ÿก': ['blowfish', 'puffer', 'fish'], + '๐Ÿ ': ['fish', 'tropical', 'sea'], + '๐ŸŸ': ['fish', 'sea', 'swim'], + '๐Ÿฌ': ['dolphin', 'sea', 'swim', 'flipper'], + '๐Ÿณ': ['whale', 'sea', 'spout'], + '๐Ÿ‹': ['whale', 'sea', 'humpback'], + '๐Ÿฆˆ': ['shark', 'fish', 'sea', 'jaws'], + '๐ŸŠ': ['crocodile', 'alligator', 'reptile'], + '๐Ÿ…': ['tiger', 'cat', 'stripes'], + '๐Ÿ†': ['leopard', 'cat', 'spots'], + '๐Ÿฆ“': ['zebra', 'stripes', 'horse'], + '๐Ÿฆ': ['gorilla', 'ape', 'monkey'], + '๐Ÿฆง': ['orangutan', 'ape', 'monkey'], + '๐Ÿฆฃ': ['mammoth', 'elephant', 'ice age'], + '๐Ÿ˜': ['elephant', 'trunk', 'big'], + '๐Ÿฆ›': ['hippo', 'hippopotamus'], + '๐Ÿฆ': ['rhino', 'rhinoceros', 'horn'], + '๐Ÿช': ['camel', 'desert', 'hump'], + '๐Ÿซ': ['camel', 'desert', 'humps', 'bactrian'], + '๐Ÿฆ’': ['giraffe', 'tall', 'spots'], + '๐Ÿฆ˜': ['kangaroo', 'australia', 'hop'], + '๐Ÿฆฌ': ['bison', 'buffalo'], + '๐Ÿƒ': ['water buffalo', 'ox'], + '๐Ÿ‚': ['ox', 'bull'], + '๐Ÿ„': ['cow', 'farm', 'moo'], + '๐ŸŽ': ['horse', 'race', 'gallop'], + '๐Ÿ–': ['pig', 'farm', 'oink'], + '๐Ÿ': ['ram', 'sheep'], + '๐Ÿ‘': ['sheep', 'lamb', 'wool', 'baa'], + '๐Ÿฆ™': ['llama', 'alpaca'], + '๐Ÿ': ['goat', 'farm'], + '๐ŸฆŒ': ['deer', 'buck', 'antlers'], + '๐Ÿ•': ['dog', 'pet', 'woof'], + '๐Ÿฉ': ['poodle', 'dog', 'fancy'], + '๐Ÿฆฎ': ['guide dog', 'service', 'blind'], + '๐Ÿ•โ€๐Ÿฆบ': ['service dog', 'vest'], + '๐Ÿˆ': ['cat', 'pet', 'meow'], + '๐Ÿˆโ€โฌ›': ['black cat', 'pet', 'halloween'], + '๐Ÿชถ': ['feather', 'bird', 'light'], + '๐Ÿ“': ['rooster', 'chicken', 'cock', 'farm'], + '๐Ÿฆƒ': ['turkey', 'bird', 'thanksgiving'], + '๐Ÿฆค': ['dodo', 'bird', 'extinct'], + '๐Ÿฆš': ['peacock', 'bird', 'feathers'], + '๐Ÿฆœ': ['parrot', 'bird', 'tropical'], + '๐Ÿฆข': ['swan', 'bird', 'elegant'], + '๐Ÿฆฉ': ['flamingo', 'bird', 'pink'], + '๐Ÿ•Š๏ธ': ['dove', 'peace', 'bird'], + '๐Ÿ‡': ['rabbit', 'bunny', 'hop'], + '๐Ÿฆ': ['raccoon', 'animal', 'trash panda'], + '๐Ÿฆจ': ['skunk', 'animal', 'smell'], + '๐Ÿฆก': ['badger', 'animal'], + '๐Ÿฆซ': ['beaver', 'animal', 'dam'], + '๐Ÿฆฆ': ['otter', 'animal', 'cute'], + '๐Ÿฆฅ': ['sloth', 'animal', 'slow', 'lazy'], + '๐Ÿ': ['mouse', 'rodent'], + '๐Ÿ€': ['rat', 'rodent'], + '๐Ÿฟ๏ธ': ['squirrel', 'chipmunk', 'nut'], + '๐Ÿฆ”': ['hedgehog', 'spiky', 'sonic'], + + // Food + '๐ŸŽ': ['apple', 'red', 'fruit'], + '๐Ÿ': ['pear', 'fruit', 'green'], + '๐ŸŠ': ['orange', 'fruit', 'citrus'], + '๐Ÿ‹': ['lemon', 'fruit', 'citrus', 'sour'], + '๐ŸŒ': ['banana', 'fruit', 'yellow'], + '๐Ÿ‰': ['watermelon', 'fruit', 'summer'], + '๐Ÿ‡': ['grapes', 'fruit', 'wine'], + '๐Ÿ“': ['strawberry', 'fruit', 'berry'], + '๐Ÿซ': ['blueberry', 'fruit', 'berry'], + '๐Ÿˆ': ['melon', 'fruit'], + '๐Ÿ’': ['cherry', 'fruit', 'red'], + '๐Ÿ‘': ['peach', 'fruit', 'butt'], + '๐Ÿฅญ': ['mango', 'fruit', 'tropical'], + '๐Ÿ': ['pineapple', 'fruit', 'tropical'], + '๐Ÿฅฅ': ['coconut', 'fruit', 'tropical'], + '๐Ÿฅ': ['kiwi', 'fruit'], + '๐Ÿ…': ['tomato', 'vegetable', 'red'], + '๐Ÿ†': ['eggplant', 'aubergine', 'vegetable'], + '๐Ÿฅ‘': ['avocado', 'vegetable', 'guac'], + '๐Ÿฅฆ': ['broccoli', 'vegetable', 'green'], + '๐Ÿฅฌ': ['lettuce', 'vegetable', 'leafy'], + '๐Ÿฅ’': ['cucumber', 'vegetable', 'pickle'], + '๐ŸŒถ๏ธ': ['pepper', 'hot', 'spicy', 'chili'], + '๐Ÿซ‘': ['pepper', 'bell', 'vegetable'], + '๐ŸŒฝ': ['corn', 'vegetable', 'maize'], + '๐Ÿฅ•': ['carrot', 'vegetable', 'orange'], + '๐Ÿซ’': ['olive', 'vegetable'], + '๐Ÿง„': ['garlic', 'vegetable', 'vampire'], + '๐Ÿง…': ['onion', 'vegetable', 'cry'], + '๐Ÿฅ”': ['potato', 'vegetable'], + '๐Ÿ ': ['sweet potato', 'vegetable'], + '๐Ÿฅ': ['croissant', 'bread', 'french', 'pastry'], + '๐Ÿฅฏ': ['bagel', 'bread', 'breakfast'], + '๐Ÿž': ['bread', 'loaf', 'toast'], + '๐Ÿฅ–': ['baguette', 'bread', 'french'], + '๐Ÿฅจ': ['pretzel', 'bread', 'snack'], + '๐Ÿง€': ['cheese', 'dairy'], + '๐Ÿฅš': ['egg', 'breakfast'], + '๐Ÿณ': ['egg', 'frying', 'breakfast', 'cooking'], + '๐Ÿงˆ': ['butter', 'dairy'], + '๐Ÿฅž': ['pancakes', 'breakfast', 'stack'], + '๐Ÿง‡': ['waffle', 'breakfast'], + '๐Ÿฅ“': ['bacon', 'breakfast', 'meat'], + '๐Ÿฅฉ': ['steak', 'meat', 'beef'], + '๐Ÿ—': ['chicken', 'leg', 'drumstick', 'meat'], + '๐Ÿ–': ['meat', 'bone', 'rib'], + '๐ŸŒญ': ['hot dog', 'sausage', 'fast food'], + '๐Ÿ”': ['burger', 'hamburger', 'fast food'], + '๐ŸŸ': ['fries', 'french fries', 'chips', 'fast food'], + '๐Ÿ•': ['pizza', 'slice', 'fast food'], + '๐Ÿซ“': ['flatbread', 'pita', 'bread'], + '๐Ÿฅช': ['sandwich', 'sub', 'lunch'], + '๐Ÿฅ™': ['pita', 'falafel', 'wrap'], + '๐Ÿง†': ['falafel', 'food'], + '๐ŸŒฎ': ['taco', 'mexican', 'food'], + '๐ŸŒฏ': ['burrito', 'mexican', 'wrap'], + '๐Ÿซ”': ['tamale', 'mexican', 'food'], + '๐Ÿฅ—': ['salad', 'healthy', 'greens'], + '๐Ÿฅ˜': ['paella', 'pan', 'food'], + '๐Ÿซ•': ['fondue', 'cheese', 'food'], + '๐Ÿฅซ': ['can', 'canned', 'food'], + '๐Ÿ': ['spaghetti', 'pasta', 'italian'], + '๐Ÿœ': ['noodles', 'ramen', 'soup', 'asian'], + '๐Ÿฒ': ['stew', 'pot', 'soup'], + '๐Ÿ›': ['curry', 'rice', 'indian'], + '๐Ÿฃ': ['sushi', 'japanese', 'fish'], + '๐Ÿฑ': ['bento', 'box', 'japanese', 'lunch'], + '๐ŸฅŸ': ['dumpling', 'asian', 'food'], + '๐Ÿฆช': ['oyster', 'seafood', 'shell'], + '๐Ÿค': ['shrimp', 'prawn', 'tempura', 'seafood'], + '๐Ÿ™': ['rice ball', 'onigiri', 'japanese'], + '๐Ÿš': ['rice', 'bowl', 'asian'], + '๐Ÿ˜': ['rice cracker', 'japanese', 'snack'], + '๐Ÿฅ': ['fish cake', 'narutomaki', 'japanese'], + '๐Ÿฅ ': ['fortune cookie', 'chinese'], + '๐Ÿฅฎ': ['mooncake', 'chinese', 'festival'], + '๐Ÿข': ['oden', 'skewer', 'japanese'], + '๐Ÿก': ['dango', 'japanese', 'dessert'], + '๐Ÿง': ['shaved ice', 'dessert', 'cold'], + '๐Ÿจ': ['ice cream', 'dessert', 'cold'], + '๐Ÿฆ': ['ice cream', 'cone', 'dessert', 'soft serve'], + '๐Ÿฅง': ['pie', 'dessert', 'thanksgiving'], + '๐Ÿง': ['cupcake', 'dessert', 'cake'], + '๐Ÿฐ': ['cake', 'slice', 'dessert'], + '๐ŸŽ‚': ['birthday', 'cake', 'candles', 'party'], + '๐Ÿฎ': ['pudding', 'flan', 'dessert'], + '๐Ÿญ': ['lollipop', 'candy', 'sweet'], + '๐Ÿฌ': ['candy', 'sweet', 'wrapper'], + '๐Ÿซ': ['chocolate', 'bar', 'candy', 'sweet'], + '๐Ÿฟ': ['popcorn', 'movies', 'snack'], + '๐Ÿฉ': ['donut', 'doughnut', 'dessert'], + '๐Ÿช': ['cookie', 'biscuit', 'dessert'], + '๐ŸŒฐ': ['chestnut', 'nut'], + '๐Ÿฅœ': ['peanut', 'nut'], + '๐Ÿฏ': ['honey', 'jar', 'bee'], + '๐Ÿฅ›': ['milk', 'glass', 'dairy'], + '๐Ÿผ': ['bottle', 'baby', 'milk'], + '๐Ÿซ–': ['teapot', 'tea', 'drink'], + 'โ˜•': ['coffee', 'tea', 'hot', 'drink', 'cafe'], + '๐Ÿต': ['tea', 'green', 'cup', 'matcha'], + '๐Ÿงƒ': ['juice', 'box', 'drink'], + '๐Ÿฅค': ['cup', 'soda', 'drink', 'straw'], + '๐Ÿง‹': ['boba', 'bubble tea', 'drink', 'tapioca'], + '๐Ÿถ': ['sake', 'japanese', 'alcohol'], + '๐Ÿบ': ['beer', 'mug', 'drink', 'alcohol'], + '๐Ÿป': ['beers', 'cheers', 'drink', 'alcohol'], + '๐Ÿฅ‚': ['champagne', 'cheers', 'toast', 'celebrate'], + '๐Ÿท': ['wine', 'red', 'glass', 'alcohol'], + '๐Ÿฅƒ': ['whiskey', 'tumbler', 'drink', 'alcohol'], + '๐Ÿธ': ['cocktail', 'martini', 'drink', 'alcohol'], + '๐Ÿน': ['tropical', 'cocktail', 'drink', 'alcohol'], + '๐Ÿง‰': ['mate', 'drink'], + '๐Ÿพ': ['champagne', 'bottle', 'celebrate', 'pop'], + '๐ŸงŠ': ['ice', 'cube', 'cold'], + + // Activities + 'โšฝ': ['soccer', 'football', 'ball', 'sport'], + '๐Ÿ€': ['basketball', 'ball', 'sport', 'nba'], + '๐Ÿˆ': ['football', 'american', 'ball', 'sport', 'nfl'], + 'โšพ': ['baseball', 'ball', 'sport', 'mlb'], + '๐ŸฅŽ': ['softball', 'ball', 'sport'], + '๐ŸŽพ': ['tennis', 'ball', 'sport', 'racket'], + '๐Ÿ': ['volleyball', 'ball', 'sport'], + '๐Ÿ‰': ['rugby', 'ball', 'sport'], + '๐Ÿฅ': ['frisbee', 'disc', 'ultimate'], + '๐ŸŽฑ': ['pool', 'billiards', '8ball', 'ball'], + '๐Ÿช€': ['yoyo', 'toy', 'play'], + '๐Ÿ“': ['ping pong', 'table tennis', 'paddle'], + '๐Ÿธ': ['badminton', 'shuttlecock', 'racket'], + '๐Ÿ’': ['hockey', 'ice', 'stick', 'puck'], + '๐Ÿ‘': ['field hockey', 'stick'], + '๐Ÿฅ': ['lacrosse', 'stick'], + '๐Ÿ': ['cricket', 'bat', 'sport'], + '๐Ÿชƒ': ['boomerang', 'throw'], + '๐Ÿฅ…': ['goal', 'net', 'sport'], + 'โ›ณ': ['golf', 'flag', 'hole'], + '๐Ÿช': ['kite', 'fly', 'wind'], + '๐Ÿน': ['archery', 'bow', 'arrow'], + '๐ŸŽฃ': ['fishing', 'rod', 'fish'], + '๐Ÿคฟ': ['diving', 'snorkel', 'mask'], + '๐ŸฅŠ': ['boxing', 'glove', 'fight'], + '๐Ÿฅ‹': ['martial arts', 'karate', 'judo'], + '๐ŸŽฝ': ['running', 'shirt', 'jersey'], + '๐Ÿ›น': ['skateboard', 'skate'], + '๐Ÿ›ผ': ['roller skate', 'skating'], + '๐Ÿ›ท': ['sled', 'snow', 'winter'], + 'โ›ธ๏ธ': ['ice skate', 'skating', 'winter'], + '๐ŸฅŒ': ['curling', 'stone', 'winter'], + '๐ŸŽฟ': ['ski', 'skiing', 'winter', 'snow'], + 'โ›ท๏ธ': ['skiing', 'skier', 'winter', 'snow'], + '๐Ÿ‚': ['snowboard', 'winter', 'snow'], + '๐Ÿช‚': ['parachute', 'skydiving'], + '๐Ÿ‹๏ธ': ['weightlifting', 'gym', 'workout'], + '๐Ÿคผ': ['wrestling', 'fight', 'sport'], + '๐Ÿคธ': ['gymnastics', 'cartwheel', 'flip'], + 'โ›น๏ธ': ['basketball', 'dribble', 'sport'], + '๐Ÿคบ': ['fencing', 'sword', 'sport'], + '๐Ÿคพ': ['handball', 'sport'], + '๐ŸŒ๏ธ': ['golf', 'swing', 'sport'], + '๐Ÿ‡': ['horse racing', 'jockey'], + '๐Ÿง˜': ['yoga', 'meditation', 'zen'], + '๐Ÿ„': ['surfing', 'surf', 'wave', 'beach'], + '๐ŸŠ': ['swimming', 'swim', 'pool'], + '๐Ÿคฝ': ['water polo', 'swim', 'sport'], + '๐Ÿšฃ': ['rowing', 'boat', 'canoe'], + '๐Ÿง—': ['climbing', 'rock', 'mountain'], + '๐Ÿšต': ['mountain biking', 'bike', 'cycling'], + '๐Ÿšด': ['cycling', 'bike', 'bicycle'], + '๐Ÿ†': ['trophy', 'winner', 'award', 'champion'], + '๐Ÿฅ‡': ['gold', 'medal', 'first', 'winner'], + '๐Ÿฅˆ': ['silver', 'medal', 'second'], + '๐Ÿฅ‰': ['bronze', 'medal', 'third'], + '๐Ÿ…': ['medal', 'sports', 'award'], + '๐ŸŽ–๏ธ': ['medal', 'military', 'award'], + '๐Ÿต๏ธ': ['rosette', 'award', 'flower'], + '๐ŸŽ—๏ธ': ['ribbon', 'awareness'], + '๐ŸŽซ': ['ticket', 'admission', 'event'], + '๐ŸŽŸ๏ธ': ['ticket', 'admission', 'event'], + '๐ŸŽช': ['circus', 'tent', 'carnival'], + '๐ŸŽญ': ['theater', 'drama', 'masks', 'performing arts'], + '๐ŸŽจ': ['art', 'paint', 'palette', 'artist'], + '๐ŸŽฌ': ['movie', 'film', 'clapperboard', 'cinema', 'action'], + '๐ŸŽค': ['microphone', 'sing', 'karaoke', 'music'], + '๐ŸŽง': ['headphones', 'music', 'listen', 'audio'], + '๐ŸŽผ': ['music', 'notes', 'score', 'sheet'], + '๐ŸŽน': ['piano', 'keyboard', 'music', 'keys'], + '๐Ÿฅ': ['drum', 'music', 'percussion', 'beat'], + '๐Ÿช˜': ['drum', 'djembe', 'music'], + '๐ŸŽท': ['saxophone', 'sax', 'music', 'jazz'], + '๐ŸŽบ': ['trumpet', 'music', 'brass', 'horn'], + '๐Ÿช—': ['accordion', 'music'], + '๐ŸŽธ': ['guitar', 'music', 'rock'], + '๐Ÿช•': ['banjo', 'music', 'country'], + '๐ŸŽป': ['violin', 'music', 'fiddle', 'classical'], + '๐ŸŽฒ': ['dice', 'game', 'roll', 'gambling', 'random', 'chance'], + 'โ™Ÿ๏ธ': ['chess', 'pawn', 'game', 'strategy'], + '๐ŸŽฏ': ['target', 'dart', 'bullseye', 'goal'], + '๐ŸŽณ': ['bowling', 'pins', 'ball', 'strike'], + '๐ŸŽฎ': ['video game', 'controller', 'gaming', 'play'], + '๐ŸŽฐ': ['slot machine', 'casino', 'gambling', 'jackpot'], + '๐Ÿงฉ': ['puzzle', 'piece', 'jigsaw', 'game'], + + // Travel + '๐Ÿš—': ['car', 'vehicle', 'drive', 'automobile'], + '๐Ÿš•': ['taxi', 'cab', 'car', 'yellow'], + '๐Ÿš™': ['suv', 'car', 'vehicle'], + '๐ŸšŒ': ['bus', 'vehicle', 'transit'], + '๐ŸšŽ': ['trolleybus', 'bus', 'transit'], + '๐ŸŽ๏ธ': ['race car', 'fast', 'racing', 'f1'], + '๐Ÿš“': ['police', 'car', 'cop'], + '๐Ÿš‘': ['ambulance', 'emergency', 'medical'], + '๐Ÿš’': ['fire truck', 'emergency', 'firefighter'], + '๐Ÿš': ['minibus', 'van', 'vehicle'], + '๐Ÿ›ป': ['pickup', 'truck', 'vehicle'], + '๐Ÿšš': ['truck', 'delivery', 'moving'], + '๐Ÿš›': ['truck', 'semi', 'trailer'], + '๐Ÿšœ': ['tractor', 'farm', 'vehicle'], + '๐Ÿฆฏ': ['cane', 'blind', 'walking'], + '๐Ÿฆฝ': ['wheelchair', 'manual', 'accessibility'], + '๐Ÿฆผ': ['wheelchair', 'motorized', 'accessibility'], + '๐Ÿ›ด': ['scooter', 'kick', 'vehicle'], + '๐Ÿšฒ': ['bike', 'bicycle', 'cycling'], + '๐Ÿ›ต': ['scooter', 'motor', 'vespa'], + '๐Ÿ๏ธ': ['motorcycle', 'bike', 'vehicle'], + '๐Ÿ›บ': ['rickshaw', 'auto', 'tuk tuk'], + '๐Ÿšจ': ['siren', 'police', 'emergency', 'light'], + '๐Ÿš”': ['police', 'car', 'oncoming'], + '๐Ÿš': ['bus', 'oncoming', 'transit'], + '๐Ÿš˜': ['car', 'oncoming', 'vehicle'], + '๐Ÿš–': ['taxi', 'oncoming', 'cab'], + '๐Ÿšก': ['cable car', 'gondola', 'aerial'], + '๐Ÿš ': ['cable car', 'mountain'], + '๐ŸšŸ': ['suspension railway', 'monorail'], + '๐Ÿšƒ': ['train', 'railway', 'car'], + '๐Ÿš‹': ['tram', 'streetcar', 'trolley'], + '๐Ÿšž': ['train', 'mountain', 'railway'], + '๐Ÿš': ['monorail', 'train'], + '๐Ÿš„': ['train', 'bullet', 'high speed', 'shinkansen'], + '๐Ÿš…': ['train', 'bullet', 'shinkansen'], + '๐Ÿšˆ': ['train', 'light rail'], + '๐Ÿš‚': ['train', 'locomotive', 'steam', 'engine'], + '๐Ÿš†': ['train', 'railway'], + '๐Ÿš‡': ['metro', 'subway', 'underground'], + '๐ŸšŠ': ['tram', 'streetcar'], + '๐Ÿš‰': ['station', 'train', 'platform'], + 'โœˆ๏ธ': ['airplane', 'plane', 'flight', 'travel'], + '๐Ÿ›ซ': ['airplane', 'departure', 'takeoff', 'flight'], + '๐Ÿ›ฌ': ['airplane', 'arrival', 'landing', 'flight'], + '๐Ÿ›ฉ๏ธ': ['airplane', 'small', 'plane'], + '๐Ÿ’บ': ['seat', 'airplane', 'chair'], + '๐Ÿ›ฐ๏ธ': ['satellite', 'space', 'orbit'], + '๐Ÿš€': ['rocket', 'space', 'launch', 'ship'], + '๐Ÿ›ธ': ['ufo', 'flying saucer', 'alien', 'space'], + '๐Ÿš': ['helicopter', 'chopper', 'fly'], + '๐Ÿ›ถ': ['canoe', 'boat', 'paddle', 'kayak'], + 'โ›ต': ['sailboat', 'boat', 'sailing'], + '๐Ÿšค': ['speedboat', 'boat', 'fast'], + '๐Ÿ›ฅ๏ธ': ['boat', 'motor', 'yacht'], + '๐Ÿ›ณ๏ธ': ['cruise', 'ship', 'boat'], + 'โ›ด๏ธ': ['ferry', 'boat', 'ship'], + '๐Ÿšข': ['ship', 'boat', 'cruise'], + 'โš“': ['anchor', 'boat', 'ship', 'nautical'], + '๐Ÿช': ['hook', 'fishing'], + 'โ›ฝ': ['gas', 'fuel', 'pump', 'station'], + '๐Ÿšง': ['construction', 'barrier', 'road'], + '๐Ÿšฆ': ['traffic light', 'signal', 'road'], + '๐Ÿšฅ': ['traffic light', 'horizontal', 'signal'], + '๐Ÿš': ['bus stop', 'station'], + '๐Ÿ—บ๏ธ': ['map', 'world', 'travel'], + '๐Ÿ—ฟ': ['moai', 'easter island', 'statue'], + '๐Ÿ—ฝ': ['statue of liberty', 'new york', 'usa'], + '๐Ÿ—ผ': ['tokyo tower', 'japan', 'landmark'], + '๐Ÿฐ': ['castle', 'european', 'fairy tale'], + '๐Ÿฏ': ['castle', 'japanese', 'palace'], + '๐ŸŸ๏ธ': ['stadium', 'sports', 'arena'], + '๐ŸŽก': ['ferris wheel', 'carnival', 'amusement'], + '๐ŸŽข': ['roller coaster', 'amusement', 'theme park'], + '๐ŸŽ ': ['carousel', 'merry-go-round', 'horse'], + 'โ›ฒ': ['fountain', 'water', 'park'], + 'โ›ฑ๏ธ': ['umbrella', 'beach', 'sun'], + '๐Ÿ–๏ธ': ['beach', 'sand', 'vacation'], + '๐Ÿ๏ธ': ['island', 'tropical', 'desert'], + '๐Ÿœ๏ธ': ['desert', 'sand', 'dry'], + '๐ŸŒ‹': ['volcano', 'mountain', 'eruption'], + 'โ›ฐ๏ธ': ['mountain', 'rock'], + '๐Ÿ”๏ธ': ['mountain', 'snow', 'peak'], + '๐Ÿ—ป': ['mount fuji', 'japan', 'mountain'], + '๐Ÿ•๏ธ': ['camping', 'tent', 'outdoor'], + 'โ›บ': ['tent', 'camping', 'outdoor'], + '๐Ÿ›–': ['hut', 'house'], + '๐Ÿ ': ['house', 'home', 'building'], + '๐Ÿก': ['house', 'garden', 'home'], + '๐Ÿ˜๏ธ': ['houses', 'neighborhood'], + '๐Ÿš๏ธ': ['house', 'abandoned', 'derelict'], + '๐Ÿ—๏ธ': ['construction', 'building', 'crane'], + '๐Ÿญ': ['factory', 'industry', 'building'], + '๐Ÿข': ['office', 'building', 'business'], + '๐Ÿฌ': ['department store', 'mall', 'shopping'], + '๐Ÿฃ': ['post office', 'japanese', 'building'], + '๐Ÿค': ['post office', 'european', 'building'], + '๐Ÿฅ': ['hospital', 'medical', 'building'], + '๐Ÿฆ': ['bank', 'money', 'building'], + '๐Ÿจ': ['hotel', 'building', 'lodging'], + '๐Ÿช': ['store', 'convenience', 'shop'], + '๐Ÿซ': ['school', 'education', 'building'], + '๐Ÿฉ': ['love hotel', 'building'], + '๐Ÿ’’': ['wedding', 'chapel', 'church'], + '๐Ÿ›๏ธ': ['classical', 'building', 'museum'], + 'โ›ช': ['church', 'christian', 'religion'], + '๐Ÿ•Œ': ['mosque', 'islam', 'religion'], + '๐Ÿ•': ['synagogue', 'jewish', 'religion'], + '๐Ÿ›•': ['temple', 'hindu', 'religion'], + '๐Ÿ•‹': ['kaaba', 'mecca', 'islam'], + 'โ›ฉ๏ธ': ['shrine', 'shinto', 'japanese', 'torii'], + + // Objects + 'โŒš': ['watch', 'time', 'wrist'], + '๐Ÿ“ฑ': ['phone', 'mobile', 'smartphone', 'iphone', 'cell'], + '๐Ÿ“ฒ': ['phone', 'mobile', 'arrow', 'call'], + '๐Ÿ’ป': ['laptop', 'computer', 'mac', 'macbook'], + 'โŒจ๏ธ': ['keyboard', 'type', 'computer'], + '๐Ÿ–ฅ๏ธ': ['computer', 'desktop', 'monitor', 'screen'], + '๐Ÿ–จ๏ธ': ['printer', 'print', 'paper'], + '๐Ÿ–ฑ๏ธ': ['mouse', 'computer', 'click'], + '๐Ÿ–ฒ๏ธ': ['trackball', 'computer'], + '๐Ÿ•น๏ธ': ['joystick', 'game', 'arcade'], + '๐Ÿ—œ๏ธ': ['clamp', 'compress', 'tool'], + '๐Ÿ’ฝ': ['minidisc', 'disk', 'computer'], + '๐Ÿ’พ': ['floppy', 'disk', 'save', 'computer'], + '๐Ÿ’ฟ': ['cd', 'disc', 'dvd'], + '๐Ÿ“€': ['dvd', 'disc', 'movie'], + '๐Ÿ“ผ': ['vhs', 'tape', 'video', 'cassette'], + '๐Ÿ“ท': ['camera', 'photo', 'picture'], + '๐Ÿ“ธ': ['camera', 'flash', 'photo'], + '๐Ÿ“น': ['video camera', 'camcorder', 'record'], + '๐ŸŽฅ': ['movie camera', 'film', 'cinema'], + '๐Ÿ“ฝ๏ธ': ['projector', 'film', 'movie'], + '๐ŸŽž๏ธ': ['film', 'frames', 'movie'], + '๐Ÿ“ž': ['phone', 'telephone', 'receiver'], + 'โ˜Ž๏ธ': ['phone', 'telephone', 'landline'], + '๐Ÿ“Ÿ': ['pager', 'beeper'], + '๐Ÿ“ ': ['fax', 'machine', 'document'], + '๐Ÿ“บ': ['tv', 'television', 'screen'], + '๐Ÿ“ป': ['radio', 'music', 'broadcast'], + '๐ŸŽ™๏ธ': ['microphone', 'studio', 'podcast', 'record'], + '๐ŸŽš๏ธ': ['slider', 'level', 'audio'], + '๐ŸŽ›๏ธ': ['knobs', 'dials', 'control'], + '๐Ÿงญ': ['compass', 'navigation', 'direction'], + 'โฑ๏ธ': ['stopwatch', 'timer', 'time'], + 'โฒ๏ธ': ['timer', 'clock', 'kitchen'], + 'โฐ': ['alarm', 'clock', 'wake'], + '๐Ÿ•ฐ๏ธ': ['clock', 'mantelpiece', 'time'], + 'โŒ›': ['hourglass', 'time', 'sand'], + 'โณ': ['hourglass', 'time', 'sand', 'flowing'], + '๐Ÿ“ก': ['satellite', 'dish', 'antenna', 'signal'], + '๐Ÿ”‹': ['battery', 'power', 'charge'], + '๐Ÿ”Œ': ['plug', 'electric', 'power', 'outlet'], + '๐Ÿ’ก': ['light bulb', 'idea', 'bright'], + '๐Ÿ”ฆ': ['flashlight', 'torch', 'light'], + '๐Ÿ•ฏ๏ธ': ['candle', 'light', 'flame'], + '๐Ÿช”': ['lamp', 'diya', 'oil'], + '๐Ÿงฏ': ['fire extinguisher', 'safety'], + '๐Ÿ›ข๏ธ': ['oil', 'drum', 'barrel'], + '๐Ÿ’ธ': ['money', 'flying', 'cash', 'dollar'], + '๐Ÿ’ต': ['money', 'dollar', 'cash', 'bill'], + '๐Ÿ’ด': ['money', 'yen', 'japanese'], + '๐Ÿ’ถ': ['money', 'euro', 'european'], + '๐Ÿ’ท': ['money', 'pound', 'british'], + '๐Ÿช™': ['coin', 'money', 'gold'], + '๐Ÿ’ฐ': ['money', 'bag', 'rich', 'cash'], + '๐Ÿ’ณ': ['credit card', 'payment', 'bank'], + '๐Ÿ’Ž': ['diamond', 'gem', 'jewel', 'precious'], + 'โš–๏ธ': ['scale', 'balance', 'justice', 'law'], + '๐Ÿชœ': ['ladder', 'climb', 'steps'], + '๐Ÿงฐ': ['toolbox', 'tools', 'repair'], + '๐Ÿช›': ['screwdriver', 'tool', 'repair'], + '๐Ÿ”ง': ['wrench', 'tool', 'repair', 'spanner'], + '๐Ÿ”จ': ['hammer', 'tool', 'build'], + 'โš’๏ธ': ['hammer', 'pick', 'tools'], + '๐Ÿ› ๏ธ': ['tools', 'hammer', 'wrench', 'repair'], + 'โ›๏ธ': ['pick', 'mining', 'tool'], + '๐Ÿชš': ['saw', 'tool', 'carpentry'], + '๐Ÿ”ฉ': ['nut', 'bolt', 'screw', 'hardware'], + 'โš™๏ธ': ['gear', 'cog', 'settings', 'mechanical'], + '๐Ÿชค': ['trap', 'mouse', 'catch'], + '๐Ÿงฑ': ['brick', 'wall', 'build'], + 'โ›“๏ธ': ['chain', 'link', 'metal'], + '๐Ÿงฒ': ['magnet', 'attract', 'magnetic'], + '๐Ÿ”ซ': ['gun', 'pistol', 'water', 'weapon'], + '๐Ÿ’ฃ': ['bomb', 'explosive', 'danger'], + '๐Ÿงจ': ['firecracker', 'dynamite', 'explosive'], + '๐Ÿช“': ['axe', 'chop', 'tool'], + '๐Ÿ”ช': ['knife', 'cut', 'kitchen', 'blade'], + '๐Ÿ—ก๏ธ': ['dagger', 'sword', 'knife', 'blade'], + 'โš”๏ธ': ['swords', 'crossed', 'battle', 'fight'], + '๐Ÿ›ก๏ธ': ['shield', 'defense', 'protection'], + '๐Ÿšฌ': ['cigarette', 'smoke', 'smoking'], + 'โšฐ๏ธ': ['coffin', 'death', 'funeral'], + '๐Ÿชฆ': ['headstone', 'grave', 'rip'], + 'โšฑ๏ธ': ['urn', 'funeral', 'ashes'], + '๐Ÿบ': ['amphora', 'vase', 'jar'], + '๐Ÿ”ฎ': ['crystal ball', 'fortune', 'magic', 'predict'], + '๐Ÿ“ฟ': ['beads', 'prayer', 'rosary'], + '๐Ÿงฟ': ['evil eye', 'nazar', 'protection'], + '๐Ÿ’ˆ': ['barber', 'pole', 'haircut'], + 'โš—๏ธ': ['alembic', 'chemistry', 'science'], + '๐Ÿ”ญ': ['telescope', 'astronomy', 'space', 'stars'], + '๐Ÿ”ฌ': ['microscope', 'science', 'biology'], + '๐Ÿ•ณ๏ธ': ['hole', 'black', 'pit'], + '๐Ÿฉน': ['bandage', 'adhesive', 'medical'], + '๐Ÿฉบ': ['stethoscope', 'doctor', 'medical'], + '๐Ÿ’Š': ['pill', 'medicine', 'drug', 'capsule'], + '๐Ÿ’‰': ['syringe', 'needle', 'injection', 'vaccine'], + '๐Ÿฉธ': ['blood', 'drop', 'donate'], + '๐Ÿงฌ': ['dna', 'gene', 'biology', 'science'], + '๐Ÿฆ ': ['microbe', 'germ', 'bacteria', 'virus'], + '๐Ÿงซ': ['petri dish', 'bacteria', 'science'], + '๐Ÿงช': ['test tube', 'science', 'chemistry', 'experiment'], + + // Symbols + 'โค๏ธ': ['heart', 'love', 'red'], + '๐Ÿงก': ['heart', 'orange', 'love'], + '๐Ÿ’›': ['heart', 'yellow', 'love'], + '๐Ÿ’š': ['heart', 'green', 'love'], + '๐Ÿ’™': ['heart', 'blue', 'love'], + '๐Ÿ’œ': ['heart', 'purple', 'love'], + '๐Ÿ–ค': ['heart', 'black', 'love'], + '๐Ÿค': ['heart', 'white', 'love'], + '๐ŸคŽ': ['heart', 'brown', 'love'], + '๐Ÿ’”': ['heart', 'broken', 'sad'], + 'โฃ๏ธ': ['heart', 'exclamation', 'love'], + '๐Ÿ’•': ['hearts', 'two', 'love'], + '๐Ÿ’ž': ['hearts', 'revolving', 'love'], + '๐Ÿ’“': ['heart', 'beating', 'love'], + '๐Ÿ’—': ['heart', 'growing', 'love'], + '๐Ÿ’–': ['heart', 'sparkle', 'love'], + '๐Ÿ’˜': ['heart', 'arrow', 'cupid', 'love'], + '๐Ÿ’': ['heart', 'ribbon', 'gift', 'love'], + '๐Ÿ’Ÿ': ['heart', 'decoration', 'love'], + 'โ˜ฎ๏ธ': ['peace', 'symbol', 'sign'], + 'โœ๏ธ': ['cross', 'christian', 'religion'], + 'โ˜ช๏ธ': ['islam', 'crescent', 'moon', 'star'], + '๐Ÿ•‰๏ธ': ['om', 'hindu', 'religion'], + 'โ˜ธ๏ธ': ['dharma', 'wheel', 'buddhist'], + 'โœก๏ธ': ['star of david', 'jewish', 'religion'], + '๐Ÿ”ฏ': ['star of david', 'hexagram'], + '๐Ÿ•Ž': ['menorah', 'jewish', 'hanukkah'], + 'โ˜ฏ๏ธ': ['yin yang', 'balance', 'taoism'], + 'โ˜ฆ๏ธ': ['orthodox cross', 'christian'], + '๐Ÿ›': ['place of worship', 'pray', 'religion'], + 'โ›Ž': ['ophiuchus', 'zodiac'], + 'โ™ˆ': ['aries', 'zodiac', 'astrology'], + 'โ™‰': ['taurus', 'zodiac', 'astrology'], + 'โ™Š': ['gemini', 'zodiac', 'astrology'], + 'โ™‹': ['cancer', 'zodiac', 'astrology'], + 'โ™Œ': ['leo', 'zodiac', 'astrology'], + 'โ™': ['virgo', 'zodiac', 'astrology'], + 'โ™Ž': ['libra', 'zodiac', 'astrology'], + 'โ™': ['scorpio', 'zodiac', 'astrology'], + 'โ™': ['sagittarius', 'zodiac', 'astrology'], + 'โ™‘': ['capricorn', 'zodiac', 'astrology'], + 'โ™’': ['aquarius', 'zodiac', 'astrology'], + 'โ™“': ['pisces', 'zodiac', 'astrology'], + '๐Ÿ†”': ['id', 'identity', 'badge'], + 'โš›๏ธ': ['atom', 'science', 'nuclear'], + '๐Ÿ‰‘': ['accept', 'chinese', 'kanji'], + 'โ˜ข๏ธ': ['radioactive', 'nuclear', 'hazard'], + 'โ˜ฃ๏ธ': ['biohazard', 'danger', 'toxic'], + '๐Ÿ“ด': ['phone off', 'mobile', 'silent'], + '๐Ÿ“ณ': ['vibration', 'phone', 'mobile'], + '๐Ÿˆถ': ['have', 'japanese', 'kanji'], + '๐Ÿˆš': ['free', 'japanese', 'kanji'], + '๐Ÿˆธ': ['apply', 'japanese', 'kanji'], + '๐Ÿˆบ': ['open', 'japanese', 'kanji'], + '๐Ÿˆท๏ธ': ['monthly', 'japanese', 'kanji'], + 'โœด๏ธ': ['star', 'eight pointed'], + '๐Ÿ†š': ['vs', 'versus', 'against'], + '๐Ÿ’ฎ': ['flower', 'white', 'japanese'], + '๐Ÿ‰': ['bargain', 'japanese', 'kanji'], + 'ใŠ™๏ธ': ['secret', 'japanese', 'kanji'], + 'ใŠ—๏ธ': ['congratulations', 'japanese', 'kanji'], + '๐Ÿˆด': ['passing', 'japanese', 'kanji'], + '๐Ÿˆต': ['full', 'japanese', 'kanji'], + '๐Ÿˆน': ['discount', 'japanese', 'kanji'], + '๐Ÿˆฒ': ['prohibited', 'japanese', 'kanji'], + '๐Ÿ…ฐ๏ธ': ['a', 'blood type', 'letter'], + '๐Ÿ…ฑ๏ธ': ['b', 'blood type', 'letter'], + '๐Ÿ†Ž': ['ab', 'blood type'], + '๐Ÿ†‘': ['cl', 'clear'], + '๐Ÿ…พ๏ธ': ['o', 'blood type', 'letter'], + '๐Ÿ†˜': ['sos', 'help', 'emergency'], + 'โŒ': ['x', 'cross', 'no', 'wrong', 'delete'], + 'โญ•': ['circle', 'o', 'ring'], + '๐Ÿ›‘': ['stop', 'sign', 'octagon'], + 'โ›”': ['no entry', 'prohibited', 'forbidden'], + '๐Ÿ“›': ['name badge', 'tag'], + '๐Ÿšซ': ['prohibited', 'no', 'forbidden'], + '๐Ÿ’ฏ': ['100', 'hundred', 'perfect', 'score'], + '๐Ÿ’ข': ['anger', 'symbol', 'mad'], + 'โ™จ๏ธ': ['hot springs', 'steam', 'onsen'], + '๐Ÿšท': ['no pedestrians', 'prohibited'], + '๐Ÿšฏ': ['no littering', 'prohibited'], + '๐Ÿšณ': ['no bicycles', 'prohibited'], + '๐Ÿšฑ': ['no drinking water', 'prohibited'], + '๐Ÿ”ž': ['18', 'adult', 'underage', 'nsfw'], + '๐Ÿ“ต': ['no phones', 'mobile', 'prohibited'], + '๐Ÿšญ': ['no smoking', 'prohibited'], + 'โ—': ['exclamation', 'important', 'alert'], + 'โ•': ['exclamation', 'white', 'important'], + 'โ“': ['question', 'what', 'help'], + 'โ”': ['question', 'white', 'what'], + 'โ€ผ๏ธ': ['double exclamation', 'important'], + 'โ‰๏ธ': ['exclamation question', 'interrobang'], + '๐Ÿ”…': ['dim', 'brightness', 'low'], + '๐Ÿ”†': ['bright', 'brightness', 'high'], + 'ใ€ฝ๏ธ': ['part alternation', 'mark'], + 'โš ๏ธ': ['warning', 'caution', 'alert'], + '๐Ÿšธ': ['children crossing', 'school', 'caution'], + '๐Ÿ”ฑ': ['trident', 'emblem'], + 'โšœ๏ธ': ['fleur de lis', 'scout'], + '๐Ÿ”ฐ': ['beginner', 'japanese', 'symbol'], + 'โ™ป๏ธ': ['recycle', 'environment', 'green'], + 'โœ…': ['check', 'yes', 'done', 'correct'], + '๐Ÿˆฏ': ['reserved', 'japanese', 'kanji'], + '๐Ÿ’น': ['chart', 'upward', 'yen', 'stock'], + 'โ‡๏ธ': ['sparkle', 'star'], + 'โœณ๏ธ': ['star', 'eight spoked'], + 'โŽ': ['x', 'cross', 'mark', 'no'], + '๐ŸŒ': ['globe', 'world', 'internet', 'web'], + '๐Ÿ’ ': ['diamond', 'cute', 'flower'], + 'โ“‚๏ธ': ['m', 'metro', 'circle'], + '๐ŸŒ€': ['cyclone', 'spiral', 'dizzy', 'typhoon'], + '๐Ÿ’ค': ['sleep', 'zzz', 'tired', 'snore'], + '๐Ÿง': ['atm', 'bank', 'money'], + '๐Ÿšพ': ['wc', 'restroom', 'toilet', 'bathroom'], + 'โ™ฟ': ['wheelchair', 'accessible', 'disability'], + '๐Ÿ…ฟ๏ธ': ['parking', 'sign', 'p'], + '๐Ÿ›—': ['elevator', 'lift'], + '๐Ÿˆณ': ['vacant', 'japanese', 'kanji'], + '๐Ÿˆ‚๏ธ': ['service charge', 'japanese', 'kanji'], + '๐Ÿ›‚': ['passport control', 'customs'], + '๐Ÿ›ƒ': ['customs', 'border'], + '๐Ÿ›„': ['baggage claim', 'luggage'], + '๐Ÿ›…': ['left luggage', 'locker'], + '๐Ÿšน': ['mens', 'restroom', 'male'], + '๐Ÿšบ': ['womens', 'restroom', 'female'], + '๐Ÿšผ': ['baby', 'symbol', 'child'], + 'โšง๏ธ': ['transgender', 'symbol', 'gender'], + '๐Ÿšป': ['restroom', 'toilet', 'wc'], + '๐Ÿšฎ': ['litter', 'trash', 'bin'], + '๐ŸŽฆ': ['cinema', 'film', 'movie'], + '๐Ÿ“ถ': ['signal', 'bars', 'antenna', 'wifi'], + '๐Ÿˆ': ['here', 'japanese', 'katakana'], + '๐Ÿ”ฃ': ['symbols', 'input'], + 'โ„น๏ธ': ['information', 'info', 'i'], + '๐Ÿ”ค': ['abc', 'letters', 'alphabet'], + '๐Ÿ”ก': ['abcd', 'lowercase', 'letters'], + '๐Ÿ” ': ['abcd', 'uppercase', 'letters'], + '๐Ÿ†–': ['ng', 'no good'], + '๐Ÿ†—': ['ok', 'button', 'good'], + '๐Ÿ†™': ['up', 'button', 'cool'], + '๐Ÿ†’': ['cool', 'button'], + '๐Ÿ†•': ['new', 'button'], + '๐Ÿ†“': ['free', 'button'], + '0๏ธโƒฃ': ['zero', '0', 'number'], + '1๏ธโƒฃ': ['one', '1', 'number'], + '2๏ธโƒฃ': ['two', '2', 'number'], + '3๏ธโƒฃ': ['three', '3', 'number'], + '4๏ธโƒฃ': ['four', '4', 'number'], + '5๏ธโƒฃ': ['five', '5', 'number'], + '6๏ธโƒฃ': ['six', '6', 'number'], + '7๏ธโƒฃ': ['seven', '7', 'number'], + '8๏ธโƒฃ': ['eight', '8', 'number'], + '9๏ธโƒฃ': ['nine', '9', 'number'], + '๐Ÿ”Ÿ': ['ten', '10', 'number'], + '๐Ÿ”ข': ['1234', 'numbers', 'input'], + '#๏ธโƒฃ': ['hash', 'hashtag', 'number'], + '*๏ธโƒฃ': ['asterisk', 'star', 'keycap'], + 'โ๏ธ': ['eject', 'button'], + 'โ–ถ๏ธ': ['play', 'button', 'forward'], + 'โธ๏ธ': ['pause', 'button'], + 'โฏ๏ธ': ['play pause', 'button'], + 'โน๏ธ': ['stop', 'button'], + 'โบ๏ธ': ['record', 'button'], + 'โญ๏ธ': ['next', 'track', 'skip'], + 'โฎ๏ธ': ['previous', 'track', 'skip'], + 'โฉ': ['fast forward', 'button'], + 'โช': ['rewind', 'button', 'fast'], + 'โซ': ['up', 'fast', 'button'], + 'โฌ': ['down', 'fast', 'button'], + 'โ—€๏ธ': ['back', 'reverse', 'button'], + '๐Ÿ”ผ': ['up', 'button', 'triangle'], + '๐Ÿ”ฝ': ['down', 'button', 'triangle'], + 'โžก๏ธ': ['right', 'arrow', 'direction'], + 'โฌ…๏ธ': ['left', 'arrow', 'direction'], + 'โฌ†๏ธ': ['up', 'arrow', 'direction'], + 'โฌ‡๏ธ': ['down', 'arrow', 'direction'], + 'โ†—๏ธ': ['up right', 'arrow', 'diagonal'], + 'โ†˜๏ธ': ['down right', 'arrow', 'diagonal'], + 'โ†™๏ธ': ['down left', 'arrow', 'diagonal'], + 'โ†–๏ธ': ['up left', 'arrow', 'diagonal'], + 'โ†•๏ธ': ['up down', 'arrow', 'vertical'], + 'โ†”๏ธ': ['left right', 'arrow', 'horizontal'], + 'โ†ช๏ธ': ['right curved', 'arrow', 'turn'], + 'โ†ฉ๏ธ': ['left curved', 'arrow', 'return'], + 'โคด๏ธ': ['up curved', 'arrow'], + 'โคต๏ธ': ['down curved', 'arrow'], + '๐Ÿ”€': ['shuffle', 'random', 'music'], + '๐Ÿ”': ['repeat', 'loop', 'music'], + '๐Ÿ”‚': ['repeat one', 'loop', 'music'], + '๐Ÿ”„': ['arrows', 'counterclockwise', 'refresh', 'sync'], + '๐Ÿ”ƒ': ['arrows', 'clockwise', 'refresh'], + '๐ŸŽต': ['music', 'note', 'sound'], + '๐ŸŽถ': ['music', 'notes', 'sound', 'singing'], + 'โž•': ['plus', 'add', 'math'], + 'โž–': ['minus', 'subtract', 'math'], + 'โž—': ['divide', 'division', 'math'], + 'โœ–๏ธ': ['multiply', 'x', 'math'], + 'โ™พ๏ธ': ['infinity', 'forever', 'endless'], + '๐Ÿ’ฒ': ['dollar', 'money', 'sign'], + '๐Ÿ’ฑ': ['exchange', 'currency', 'money'], + 'โ„ข๏ธ': ['trademark', 'tm', 'brand'], + 'ยฉ๏ธ': ['copyright', 'c', 'legal'], + 'ยฎ๏ธ': ['registered', 'r', 'brand'], + 'ใ€ฐ๏ธ': ['wavy dash', 'line'], + 'โžฐ': ['curly loop', 'line'], + 'โžฟ': ['double curly loop', 'line'], + '๐Ÿ”š': ['end', 'arrow'], + '๐Ÿ”™': ['back', 'arrow', 'return'], + '๐Ÿ”›': ['on', 'arrow', 'mark'], + '๐Ÿ”': ['top', 'arrow', 'up'], + '๐Ÿ”œ': ['soon', 'arrow'], + 'โœ”๏ธ': ['check', 'mark', 'done', 'correct'], + 'โ˜‘๏ธ': ['check box', 'done', 'ballot'], + '๐Ÿ”˜': ['radio button', 'option'], + '๐Ÿ”ด': ['red', 'circle', 'dot'], + '๐ŸŸ ': ['orange', 'circle', 'dot'], + '๐ŸŸก': ['yellow', 'circle', 'dot'], + '๐ŸŸข': ['green', 'circle', 'dot'], + '๐Ÿ”ต': ['blue', 'circle', 'dot'], + '๐ŸŸฃ': ['purple', 'circle', 'dot'], + 'โšซ': ['black', 'circle', 'dot'], + 'โšช': ['white', 'circle', 'dot'], + '๐ŸŸค': ['brown', 'circle', 'dot'], + '๐Ÿ”บ': ['red triangle', 'up'], + '๐Ÿ”ป': ['red triangle', 'down'], + '๐Ÿ”ธ': ['orange diamond', 'small'], + '๐Ÿ”น': ['blue diamond', 'small'], + '๐Ÿ”ถ': ['orange diamond', 'large'], + '๐Ÿ”ท': ['blue diamond', 'large'], + '๐Ÿ”ณ': ['white square', 'button'], + '๐Ÿ”ฒ': ['black square', 'button'], + 'โ–ช๏ธ': ['black square', 'small'], + 'โ–ซ๏ธ': ['white square', 'small'], + 'โ—พ': ['black square', 'medium small'], + 'โ—ฝ': ['white square', 'medium small'], + 'โ—ผ๏ธ': ['black square', 'medium'], + 'โ—ป๏ธ': ['white square', 'medium'], + '๐ŸŸฅ': ['red square'], + '๐ŸŸง': ['orange square'], + '๐ŸŸจ': ['yellow square'], + '๐ŸŸฉ': ['green square'], + '๐ŸŸฆ': ['blue square'], + '๐ŸŸช': ['purple square'], + 'โฌ›': ['black square', 'large'], + 'โฌœ': ['white square', 'large'], + '๐ŸŸซ': ['brown square'], + '๐Ÿ”ˆ': ['speaker', 'low', 'sound'], + '๐Ÿ”‡': ['mute', 'speaker', 'silent'], + '๐Ÿ”‰': ['speaker', 'medium', 'sound'], + '๐Ÿ”Š': ['speaker', 'loud', 'sound', 'volume'], + '๐Ÿ””': ['bell', 'notification', 'alert'], + '๐Ÿ”•': ['bell', 'mute', 'silent', 'no'], + '๐Ÿ“ฃ': ['megaphone', 'announcement', 'cheer'], + '๐Ÿ“ข': ['loudspeaker', 'announcement', 'public'], + '๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ': ['eye speech', 'witness'], + '๐Ÿ’ฌ': ['speech bubble', 'chat', 'talk', 'comment'], + '๐Ÿ’ญ': ['thought bubble', 'thinking', 'cloud'], + '๐Ÿ—ฏ๏ธ': ['anger bubble', 'mad', 'right'], + 'โ™ ๏ธ': ['spade', 'card', 'suit'], + 'โ™ฃ๏ธ': ['club', 'card', 'suit'], + 'โ™ฅ๏ธ': ['heart', 'card', 'suit'], + 'โ™ฆ๏ธ': ['diamond', 'card', 'suit'], + '๐Ÿƒ': ['joker', 'card', 'wild'], + '๐ŸŽด': ['flower card', 'hanafuda', 'japanese'], + '๐Ÿ€„': ['mahjong', 'red dragon', 'game'], + '๐Ÿ•': ['clock', '1', 'one', 'time'], + '๐Ÿ•‘': ['clock', '2', 'two', 'time'], + '๐Ÿ•’': ['clock', '3', 'three', 'time'], + '๐Ÿ•“': ['clock', '4', 'four', 'time'], + '๐Ÿ•”': ['clock', '5', 'five', 'time'], + '๐Ÿ••': ['clock', '6', 'six', 'time'], + '๐Ÿ•–': ['clock', '7', 'seven', 'time'], + '๐Ÿ•—': ['clock', '8', 'eight', 'time'], + '๐Ÿ•˜': ['clock', '9', 'nine', 'time'], + '๐Ÿ•™': ['clock', '10', 'ten', 'time'], + '๐Ÿ•š': ['clock', '11', 'eleven', 'time'], + '๐Ÿ•›': ['clock', '12', 'twelve', 'time'], + '๐Ÿ•œ': ['clock', '1:30', 'time'], + '๐Ÿ•': ['clock', '2:30', 'time'], + '๐Ÿ•ž': ['clock', '3:30', 'time'], + '๐Ÿ•Ÿ': ['clock', '4:30', 'time'], + '๐Ÿ• ': ['clock', '5:30', 'time'], + '๐Ÿ•ก': ['clock', '6:30', 'time'], + '๐Ÿ•ข': ['clock', '7:30', 'time'], + '๐Ÿ•ฃ': ['clock', '8:30', 'time'], + '๐Ÿ•ค': ['clock', '9:30', 'time'], + '๐Ÿ•ฅ': ['clock', '10:30', 'time'], + '๐Ÿ•ฆ': ['clock', '11:30', 'time'], + '๐Ÿ•ง': ['clock', '12:30', 'time'], + + // Nature (excluding duplicates that exist in other categories) + '๐ŸŒธ': ['cherry blossom', 'flower', 'spring', 'sakura'], + '๐ŸŒน': ['rose', 'flower', 'red', 'love'], + '๐Ÿฅ€': ['wilted', 'flower', 'dead', 'sad'], + '๐ŸŒบ': ['hibiscus', 'flower', 'tropical'], + '๐ŸŒป': ['sunflower', 'flower', 'yellow', 'summer'], + '๐ŸŒผ': ['blossom', 'flower', 'yellow'], + '๐ŸŒท': ['tulip', 'flower', 'spring'], + '๐ŸŒฑ': ['seedling', 'plant', 'grow', 'sprout'], + '๐Ÿชด': ['potted plant', 'houseplant', 'green'], + '๐ŸŒฒ': ['evergreen', 'tree', 'pine', 'christmas'], + '๐ŸŒณ': ['tree', 'deciduous', 'nature'], + '๐ŸŒด': ['palm tree', 'tropical', 'beach'], + '๐ŸŒต': ['cactus', 'desert', 'plant'], + '๐ŸŒพ': ['rice', 'plant', 'grain', 'ear'], + '๐ŸŒฟ': ['herb', 'plant', 'green', 'leaf'], + 'โ˜˜๏ธ': ['shamrock', 'clover', 'irish', 'luck'], + '๐Ÿ€': ['four leaf clover', 'luck', 'irish'], + '๐Ÿ': ['maple leaf', 'fall', 'autumn', 'canada'], + '๐Ÿ‚': ['fallen leaf', 'autumn', 'fall'], + '๐Ÿƒ': ['leaf', 'wind', 'blow', 'flutter'], + '๐Ÿ„': ['mushroom', 'fungus', 'toadstool'], + '๐ŸŒ': ['earth', 'globe', 'europe', 'africa', 'world'], + '๐ŸŒŽ': ['earth', 'globe', 'americas', 'world'], + '๐ŸŒ': ['earth', 'globe', 'asia', 'australia', 'world'], + '๐Ÿชจ': ['rock', 'stone', 'boulder'], + '๐ŸŒ‘': ['new moon', 'dark', 'night'], + '๐ŸŒ’': ['waxing crescent', 'moon', 'night'], + '๐ŸŒ“': ['first quarter', 'moon', 'night'], + '๐ŸŒ”': ['waxing gibbous', 'moon', 'night'], + '๐ŸŒ•': ['full moon', 'night', 'bright'], + '๐ŸŒ–': ['waning gibbous', 'moon', 'night'], + '๐ŸŒ—': ['last quarter', 'moon', 'night'], + '๐ŸŒ˜': ['waning crescent', 'moon', 'night'], + '๐ŸŒ™': ['crescent moon', 'night', 'sleep'], + '๐ŸŒš': ['new moon face', 'night', 'creepy'], + '๐ŸŒ›': ['first quarter face', 'moon', 'night'], + '๐ŸŒœ': ['last quarter face', 'moon', 'night'], + 'โ˜€๏ธ': ['sun', 'sunny', 'bright', 'weather', 'hot'], + '๐ŸŒ': ['full moon face', 'night'], + '๐ŸŒž': ['sun face', 'sunny', 'bright'], + '๐Ÿช': ['planet', 'saturn', 'ring', 'space'], + 'โญ': ['star', 'night', 'favorite'], + '๐ŸŒŸ': ['star', 'glowing', 'sparkle', 'shine'], + '๐ŸŒ ': ['shooting star', 'night', 'wish'], + '๐ŸŒŒ': ['milky way', 'galaxy', 'space', 'stars'], + 'โ˜๏ธ': ['cloud', 'weather', 'sky'], + 'โ›…': ['partly cloudy', 'sun', 'weather'], + 'โ›ˆ๏ธ': ['cloud', 'lightning', 'rain', 'storm', 'thunder'], + '๐ŸŒค๏ธ': ['sun', 'cloud', 'small', 'weather'], + '๐ŸŒฅ๏ธ': ['sun', 'cloud', 'large', 'weather'], + '๐ŸŒฆ๏ธ': ['sun', 'cloud', 'rain', 'weather'], + '๐ŸŒง๏ธ': ['cloud', 'rain', 'weather'], + '๐ŸŒจ๏ธ': ['cloud', 'snow', 'weather', 'winter'], + '๐ŸŒฉ๏ธ': ['cloud', 'lightning', 'weather', 'storm'], + '๐ŸŒช๏ธ': ['tornado', 'cloud', 'weather', 'twister'], + '๐ŸŒซ๏ธ': ['fog', 'cloud', 'weather', 'mist'], + '๐ŸŒฌ๏ธ': ['wind', 'blow', 'face', 'weather'], + '๐ŸŒˆ': ['rainbow', 'sky', 'weather', 'pride'], + '๐ŸŒ‚': ['umbrella', 'closed', 'rain'], + 'โ˜‚๏ธ': ['umbrella', 'open', 'rain'], + 'โ˜”': ['umbrella', 'rain', 'drops', 'weather'], + 'โšก': ['lightning', 'bolt', 'electric', 'zap', 'thunder'], + 'โ„๏ธ': ['snowflake', 'snow', 'winter', 'cold'], + 'โ˜ƒ๏ธ': ['snowman', 'winter', 'snow', 'cold'], + 'โ›„': ['snowman', 'without snow', 'winter'], + 'โ˜„๏ธ': ['comet', 'space', 'meteor'], + '๐Ÿ”ฅ': ['fire', 'flame', 'hot', 'lit', 'burn'], + '๐Ÿ’ง': ['droplet', 'water', 'tear', 'sweat'], + '๐ŸŒŠ': ['wave', 'ocean', 'sea', 'water', 'surf'], +} + const EMOJI_CATEGORIES: Record = { 'People': ['๐Ÿ˜€', '๐Ÿ˜ƒ', '๐Ÿ˜„', '๐Ÿ˜', '๐Ÿ˜†', '๐Ÿ˜…', '๐Ÿคฃ', '๐Ÿ˜‚', '๐Ÿ™‚', '๐Ÿ™ƒ', '๐Ÿ˜‰', '๐Ÿ˜Š', '๐Ÿ˜‡', '๐Ÿฅฐ', '๐Ÿ˜', '๐Ÿคฉ', '๐Ÿ˜˜', '๐Ÿ˜—', '๐Ÿ˜š', '๐Ÿ˜™', '๐Ÿฅฒ', '๐Ÿ˜‹', '๐Ÿ˜›', '๐Ÿ˜œ', '๐Ÿคช', '๐Ÿ˜', '๐Ÿค‘', '๐Ÿค—', '๐Ÿคญ', '๐Ÿคซ', '๐Ÿค”', '๐Ÿค', '๐Ÿคจ', '๐Ÿ˜', '๐Ÿ˜‘', '๐Ÿ˜ถ', '๐Ÿ˜', '๐Ÿ˜’', '๐Ÿ™„', '๐Ÿ˜ฌ', '๐Ÿคฅ', '๐Ÿ˜Œ', '๐Ÿ˜”', '๐Ÿ˜ช', '๐Ÿคค', '๐Ÿ˜ด', '๐Ÿ˜ท', '๐Ÿค’', '๐Ÿค•', '๐Ÿคข', '๐Ÿคฎ', '๐Ÿคง', '๐Ÿฅต', '๐Ÿฅถ', '๐Ÿฅด', '๐Ÿ˜ต', '๐Ÿคฏ', '๐Ÿค ', '๐Ÿฅณ', '๐Ÿฅธ', '๐Ÿ˜Ž', '๐Ÿค“', '๐Ÿง', '๐Ÿ˜•', '๐Ÿ˜Ÿ', '๐Ÿ™', '๐Ÿ˜ฎ', '๐Ÿ˜ฏ', '๐Ÿ˜ฒ', '๐Ÿ˜ณ', '๐Ÿฅบ', '๐Ÿ˜ฆ', '๐Ÿ˜ง', '๐Ÿ˜จ', '๐Ÿ˜ฐ', '๐Ÿ˜ฅ', '๐Ÿ˜ข', '๐Ÿ˜ญ', '๐Ÿ˜ฑ', '๐Ÿ˜–', '๐Ÿ˜ฃ', '๐Ÿ˜ž', '๐Ÿ˜“', '๐Ÿ˜ฉ', '๐Ÿ˜ซ', '๐Ÿฅฑ', '๐Ÿ˜ค', '๐Ÿ˜ก', '๐Ÿ˜ ', '๐Ÿคฌ', '๐Ÿ˜ˆ', '๐Ÿ‘ฟ', '๐Ÿ’€', 'โ˜ ๏ธ', '๐Ÿ’ฉ', '๐Ÿคก', '๐Ÿ‘น', '๐Ÿ‘บ', '๐Ÿ‘ป', '๐Ÿ‘ฝ', '๐Ÿ‘พ', '๐Ÿค–'], 'Gestures': ['๐Ÿ‘‹', '๐Ÿคš', '๐Ÿ–๏ธ', 'โœ‹', '๐Ÿ––', '๐Ÿ‘Œ', '๐ŸคŒ', '๐Ÿค', 'โœŒ๏ธ', '๐Ÿคž', '๐ŸคŸ', '๐Ÿค˜', '๐Ÿค™', '๐Ÿ‘ˆ', '๐Ÿ‘‰', '๐Ÿ‘†', '๐Ÿ–•', '๐Ÿ‘‡', 'โ˜๏ธ', '๐Ÿ‘', '๐Ÿ‘Ž', 'โœŠ', '๐Ÿ‘Š', '๐Ÿค›', '๐Ÿคœ', '๐Ÿ‘', '๐Ÿ™Œ', '๐Ÿ‘', '๐Ÿคฒ', '๐Ÿค', '๐Ÿ™', 'โœ๏ธ', '๐Ÿ’…', '๐Ÿคณ', '๐Ÿ’ช', '๐Ÿฆพ', '๐Ÿฆฟ', '๐Ÿฆต', '๐Ÿฆถ', '๐Ÿ‘‚', '๐Ÿฆป', '๐Ÿ‘ƒ', '๐Ÿง ', '๐Ÿซ€', '๐Ÿซ', '๐Ÿฆท', '๐Ÿฆด', '๐Ÿ‘€', '๐Ÿ‘๏ธ', '๐Ÿ‘…', '๐Ÿ‘„'], @@ -30,6 +1092,7 @@ const EMOJI_CATEGORIES: Record = { let selectedCategory: Category = 'People' let onSelectCallback: ((emoji: string) => void) | null = null +let searchQuery = '' const Container = define('EmojiPickerContainer', { display: 'flex', @@ -37,6 +1100,22 @@ const Container = define('EmojiPickerContainer', { gap: 12, }) +const SearchInput = define('EmojiSearchInput', { + base: 'input', + width: '100%', + padding: '8px 12px', + fontSize: 14, + border: `1px solid ${theme('colors-border')}`, + borderRadius: theme('radius-md'), + background: theme('colors-bg'), + color: theme('colors-text'), + outline: 'none', + selectors: { + '&:focus': { borderColor: theme('colors-primary') }, + '&::placeholder': { color: theme('colors-textMuted') }, + }, +}) + const EmojiGrid = define('EmojiGrid', { display: 'grid', gridTemplateColumns: 'repeat(10, 1fr)', @@ -88,12 +1167,42 @@ const EmojiButton = define('EmojiButton', { }) const getEmojis = (): string[] => { + if (searchQuery.trim()) { + const query = searchQuery.toLowerCase() + const allEmojis = Object.values(EMOJI_CATEGORIES).flat() + return [...new Set(allEmojis)].filter(emoji => { + const keywords = EMOJI_KEYWORDS[emoji] || [] + return keywords.some(keyword => keyword.includes(query)) || emoji.includes(query) + }) + } return EMOJI_CATEGORIES[selectedCategory] } +const EmojiResults = () => { + const emojis = getEmojis() + return ( + <> + {emojis.map((emoji, i) => ( + handleSelect(emoji)}> + {emoji} + + ))} + + ) +} + +const updateSearch = (query: string) => { + searchQuery = query + update('#emoji-results', ) +} + const selectCategory = (category: Category) => { selectedCategory = category - rerenderModal() + searchQuery = '' + // Clear the search input + const input = document.getElementById('emoji-search') as HTMLInputElement + if (input) input.value = '' + update() } const handleSelect = (emoji: string) => { @@ -105,30 +1214,37 @@ const CATEGORIES: Category[] = ['People', 'Gestures', 'Animals', 'Food', 'Activi const EmojiPickerContent = define('EmojiPickerContent', { render() { - const emojis = getEmojis() + const isSearching = searchQuery.trim().length > 0 return ( - - {emojis.map((emoji, i) => ( - handleSelect(emoji)}> - {emoji} - - ))} + updateSearch((e.target as HTMLInputElement).value)} + autofocus + /> + + + - - {CATEGORIES.map(cat => ( - selectCategory(cat)} - title={cat} - > - {CATEGORY_ICONS[cat]} - - ))} - + {!isSearching && ( + + {CATEGORIES.map(cat => ( + selectCategory(cat)} + title={cat} + > + {CATEGORY_ICONS[cat]} + + ))} + + )} ) } @@ -136,6 +1252,7 @@ const EmojiPickerContent = define('EmojiPickerContent', { export const openEmojiPicker = (onSelect: (emoji: string) => void) => { selectedCategory = 'People' + searchQuery = '' onSelectCallback = onSelect openModal('Choose Emoji', () => ) } diff --git a/src/client/update.tsx b/src/client/update.tsx new file mode 100644 index 0000000..39c1e95 --- /dev/null +++ b/src/client/update.tsx @@ -0,0 +1,25 @@ +import { render } from 'hono/jsx/dom' +import type { Child } from 'hono/jsx' + +let globalRenderFn: (() => void) | null = null + +export const initUpdate = (renderFn: () => void) => { + globalRenderFn = renderFn +} + +/** + * Update the UI from state. + * + * update() - redraw everything + * update('#emoji-results', ) - target specific element + */ +export function update(): void +export function update(selector: string, component: Child): void +export function update(selector?: string, component?: Child) { + if (selector && component !== undefined) { + const el = document.querySelector(selector) as HTMLElement | null + if (el) render(component, el) + } else { + globalRenderFn?.() + } +} diff --git a/src/server/apps.ts b/src/server/apps.ts index c640fef..10128bc 100644 --- a/src/server/apps.ts +++ b/src/server/apps.ts @@ -8,6 +8,7 @@ import type { App as SharedApp, AppState, LogLine } from '../shared/types' export type { AppState } from '../shared/types' +const DEFAULT_EMOJI = '๐Ÿ–ฅ๏ธ' const APPS_DIR = join(process.env.DATA_DIR ?? '.', 'apps') const MAX_LOGS = 100 @@ -42,29 +43,20 @@ const allAppDirs = () => { .sort() } -/** Returns names of valid apps (those with scripts.toes in package.json) */ -export const appNames = () => allAppDirs().filter(isApp) - let NEXT_PORT = 3001 const getPort = () => NEXT_PORT++ -/** Discover all apps and set initial states */ const discoverApps = () => { for (const dir of allAppDirs()) { const { pkg, error } = loadApp(dir) const state: AppState = error ? 'invalid' : 'stopped' - const icon = pkg.toes?.icon + const icon = pkg.toes?.icon ?? DEFAULT_EMOJI _apps.set(dir, { name: dir, state, icon, error }) } } -/** Start all valid apps */ -export const runApps = () => { - for (const dir of appNames()) { - const port = getPort() - runApp(dir, port) - } -} +export const runApps = () => + allAppDirs().filter(isApp).forEach(startApp) type LoadResult = { pkg: any; error?: string } @@ -197,6 +189,7 @@ export const getApp = (dir: string): App | undefined => _apps.get(dir) export const startApp = (dir: string) => { const app = _apps.get(dir) if (!app || app.state !== 'stopped') return + if (!isApp(dir)) return runApp(dir, getPort()) } diff --git a/src/server/index.tsx b/src/server/index.tsx index 3e2ff4f..90e2f5c 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -50,6 +50,16 @@ app.get('/api/apps/stream', c => { }) }) +app.get('/api/apps', c => { + const apps = allApps().map(app => { + const clone = { ...app } + delete clone.proc + delete clone.logs + return clone + }) + return c.json(apps) +}) + app.post('/api/apps/:app/start', c => { const appName = c.req.param('app') if (!appName) return c.json({ error: 'App not found' }, 404) diff --git a/src/shared/types.ts b/src/shared/types.ts index e51cb23..ce03c6b 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -8,7 +8,7 @@ export type LogLine = { export type App = { name: string state: AppState - icon?: string + icon: string error?: string port?: number started?: number