@@ -0,0 +1,467 @@
{###############################################################################
_icon_picker.html — Sélecteur d'icône/emoji façon Notion (v5.6.0)
═══════════════════════════════════════════════════════════════════════════
Popover global (inclus par base.html) utilisé par :
• le menu contextuel (library / local-workspace) via fdCtx.setIcon
• l'éditeur de page (clic sur l'icône du titre)
Expose le store Alpine `fdIconPicker` + `window.FDIconPicker`.
Onglets Emoji / Icons / Upload, recherche, aléatoire, teintes de peau,
récents (localStorage) et emojis personnalisés du workspace (API).
############################################################################}
{% set picker_icons = ['folder','file','calendar','clock','star','bot','users','globe','lock','book','check-square','trash','help-circle','settings','refresh','log-out','message-square','home','search','link','plus','bell','image','download','list','bar-chart','grid','align-left','corner-down-right','copy','key','inbox','edit','eye','share','x','paperclip','external-link','sparkles','lightbulb','tag','file-text','save','upload','trending-up','zap','alert-triangle','user'] %}
< script data-cfasync = "false" >
/* Global JS mirror of _icons.html + helpers to render emoji / icon / custom-emoji URLs. */
( function ( ) {
var FD _ICONS = {
'folder' : '<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>' ,
'file' : '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>' ,
'calendar' : '<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>' ,
'clock' : '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>' ,
'star' : '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>' ,
'bot' : '<rect x="3" y="7" width="18" height="13" rx="2"/><path d="M8 7V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v3"/><line x1="12" y1="20" x2="12" y2="24"/><circle cx="8" cy="13" r="1"/><circle cx="16" cy="13" r="1"/>' ,
'users' : '<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>' ,
'globe' : '<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>' ,
'lock' : '<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>' ,
'book' : '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>' ,
'check-square' : '<polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>' ,
'trash' : '<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>' ,
'help-circle' : '<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/>' ,
'settings' : '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>' ,
'refresh' : '<polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>' ,
'log-out' : '<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/>' ,
'message-square' : '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>' ,
'home' : '<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>' ,
'search' : '<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>' ,
'link' : '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>' ,
'plus' : '<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>' ,
'bell' : '<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>' ,
'image' : '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>' ,
'download' : '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>' ,
'chevron-left' : '<polyline points="15 18 9 12 15 6"/>' ,
'chevron-right' : '<polyline points="9 18 15 12 9 6"/>' ,
'list' : '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>' ,
'bar-chart' : '<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>' ,
'grid' : '<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>' ,
'align-left' : '<line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="17" y1="14" x2="3" y2="14"/><line x1="21" y1="18" x2="3" y2="18"/>' ,
'corner-down-right' : '<polyline points="15 10 20 15 15 20"/><path d="M4 4v7a4 4 0 0 0 4 4h12"/>' ,
'copy' : '<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>' ,
'chevron-down' : '<polyline points="6 9 12 15 18 9"/>' ,
'key' : '<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/>' ,
'inbox' : '<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>' ,
'edit' : '<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>' ,
'eye-off' : '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>' ,
'eye' : '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>' ,
'share' : '<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>' ,
'more-horizontal' : '<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>' ,
'x' : '<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>' ,
'paperclip' : '<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/>' ,
'external-link' : '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>' ,
'sparkles' : '<path d="M12 3l1.9 5.8 6.1.5-4.9 3.6 1.7 5.8-4.8-3.5-4.8 3.5 1.7-5.8-4.9-3.6 6.1-.5z"/>' ,
'lightbulb' : '<path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/>' ,
'tag' : '<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/>' ,
'file-text' : '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/>' ,
'save' : '<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/>' ,
'upload' : '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>' ,
'trending-up' : '<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/>' ,
'zap' : '<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>' ,
'alert-triangle' : '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>' ,
'user' : '<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>'
} ;
window . FD _ICONS = FD _ICONS ;
window . fd _icon = function ( name , size ) {
size = size || 18 ;
var inner = FD _ICONS [ name ] ;
if ( inner ) return '<svg width="' + size + '" height="' + size + '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + inner + '</svg>' ;
return ( window . getSvgIcon ? getSvgIcon ( name , size ) : '' ) ;
} ;
/* Render a page_icon value: image URL, known icon name, or emoji text. */
window . fdIconHtml = function ( value , size ) {
size = size || 16 ;
var v = ( value == null ? '' : String ( value ) ) . trim ( ) ;
if ( ! v ) return '' ;
if ( v . charAt ( 0 ) === '/' || v . slice ( 0 , 4 ) === 'http' ) {
return '<img src="' + v . replace ( /"/g , '"' ) + '" alt="" style="width:' + size + 'px;height:' + size + 'px;object-fit:contain;vertical-align:middle;display:inline-block;">' ;
}
if ( FD _ICONS [ v ] || ( window . getSvgIcon && getSvgIcon ( v , size ) ) ) return window . fd _icon ( v , size ) ;
return v ;
} ;
} ) ( ) ;
< / script >
< script data-cfasync = "false" >
( function ( ) {
if ( window . _ _fdIconPickerRegistered ) return ;
window . _ _fdIconPickerRegistered = true ;
var TONES = [ '' , '\u{1F3FB}' , '\u{1F3FC}' , '\u{1F3FD}' , '\u{1F3FE}' , '\u{1F3FF}' ] ;
var TONEABLE = { } ;
[ '👋' , '🤚' , '🖐️' , '✋' , '🖖' , '👌' , '🤌' , '🤏' , '✌️' , '🤞' , '🤟' , '🤘' , '🤙' , '👈' , '👉' , '👆' , '👇' , '☝️' , '👍' , '👎' , '✊' , '👊' , '🤛' , '🤜' , '👏' , '🙌' , '🫶' , '👐' , '🤲' , '🤝' , '🙏' , '💪' , '🦵' , '🦶' , '👂' , '👃' , '👶' , '🧒' , '👦' , '👧' , '🧑' , '👨' , '👩' , '🧓' , '👴' , '👵' , '🙍' , '🙎' , '🙅' , '🙆' , '💁' , '🙋' , '🧏' , '🙇' , '🤦' , '🤷' , '👮' , '🕵️' , '💂' , '👷' , '🤴' , '👸' , '👳' , '👲' , '🧕' , '🤵' , '👰' , '🤰' , '🤱' , '👼' , '🎅' , '🤶' , '🦸' , '🦹' , '🧙' , '🧚' , '🧛' , '🧜' , '🧝' , '💆' , '💇' , '🚶' , '🧍' , '🧎' , '🏃' , '💃' , '🕺' , '👯' , '🧖' , '🧗' , '🏇' , '⛷️' , '🏂' , '🏌️' , '🏄' , '🚣' , '🏊' , '⛹️' , '🏋️' , '🚴' , '🚵' , '🤸' , '🤼' , '🤽' , '🤾' , '🤹' , '🧘' , '🛀' , '🛌' ] . forEach ( function ( e ) { TONEABLE [ e ] = true ; } ) ;
var CATS = [
{ id : 'people' , label : 'People' , items : [
[ '😀' , 'grinning face smile happy' ] , [ '😃' , 'smiley happy' ] , [ '😄' , 'smile laugh happy' ] , [ '😁' , 'grin happy' ] , [ '😆' , 'laughing happy' ] , [ '😅' , 'sweat smile' ] , [ '🤣' , 'rofl rolling laugh' ] , [ '😂' , 'joy tears laugh' ] , [ '🙂' , 'slight smile' ] , [ '🙃' , 'upside down' ] , [ '😉' , 'wink' ] , [ '😊' , 'blush smile happy' ] , [ '😇' , 'innocent halo angel' ] , [ '🥰' , 'love hearts' ] , [ '😍' , 'heart eyes love' ] , [ '🤩' , 'star struck wow' ] , [ '😘' , 'kiss love' ] , [ '😗' , 'kissing' ] , [ '😚' , 'kissing' ] , [ '😙' , 'kissing' ] , [ '🥲' , 'tear smile happy' ] , [ '😋' , 'yum tasty' ] , [ '😛' , 'tongue' ] , [ '😜' , 'wink tongue' ] , [ '🤪' , 'crazy zany' ] , [ '😝' , 'tongue' ] , [ '🤑' , 'money rich' ] , [ '🤗' , 'hug' ] , [ '🤭' , 'giggle' ] , [ '🤫' , 'shush quiet' ] , [ '🤔' , 'thinking' ] , [ '🤐' , 'zip quiet' ] , [ '🤨' , 'raised eyebrow' ] , [ '😐' , 'neutral' ] , [ '😑' , 'expressionless' ] , [ '😶' , 'no mouth' ] , [ '😏' , 'smirk' ] , [ '😒' , 'unamused' ] , [ '🙄' , 'roll eyes' ] , [ '😬' , 'grimace' ] , [ '🤥' , 'lying' ] , [ '😌' , 'relieved' ] , [ '😔' , 'pensive sad' ] , [ '😪' , 'sleepy' ] , [ '🤤' , 'drool' ] , [ '😴' , 'sleeping' ] , [ '😷' , 'mask sick' ] , [ '🤒' , 'sick thermometer' ] , [ '🤕' , 'hurt bandage' ] , [ '🤢' , 'nauseated' ] , [ '🤮' , 'vomit' ] , [ '🤧' , 'sneeze' ] , [ '🥵' , 'hot' ] , [ '🥶' , 'cold' ] , [ '🥴' , 'woozy' ] , [ '😵' , 'dizzy' ] , [ '🤯' , 'mind blown' ] , [ '🤠' , 'cowboy' ] , [ '🥳' , 'party' ] , [ '🥺' , 'pleading' ] , [ '😎' , 'cool sunglasses' ] , [ '🤓' , 'nerd' ] , [ '🧐' , 'monocle' ] , [ '😕' , 'confused' ] , [ '😟' , 'worried' ] , [ '🙁' , 'frown' ] , [ '☹️' , 'frown sad' ] , [ '😮' , 'surprised' ] , [ '😯' , 'hushed' ] , [ '😲' , 'astonished' ] , [ '😳' , 'flushed' ] , [ '😨' , 'fearful' ] , [ '😰' , 'anxious' ] , [ '😥' , 'sad' ] , [ '😢' , 'cry' ] , [ '😭' , 'sob cry' ] , [ '😱' , 'scream fear' ] , [ '😖' , 'confounded' ] , [ '😣' , 'persevere' ] , [ '😞' , 'disappointed' ] , [ '😓' , 'sweat' ] , [ '😩' , 'weary' ] , [ '😫' , 'tired' ] , [ '🥱' , 'yawn' ] , [ '😤' , 'triumph' ] , [ '😡' , 'angry' ] , [ '😠' , 'rage' ] , [ '🤬' , 'cursing' ] , [ '😈' , 'devil' ] , [ '👿' , 'imp' ] , [ '💀' , 'skull' ] , [ '💩' , 'poop' ] , [ '🤡' , 'clown' ] , [ '👻' , 'ghost' ] , [ '👽' , 'alien' ] , [ '🤖' , 'robot' ] , [ '😺' , 'cat' ] , [ '🙈' , 'monkey see' ] , [ '🙉' , 'monkey hear' ] , [ '🙊' , 'monkey speak' ] , [ '👋' , 'wave hand' ] , [ '🤚' , 'raised hand' ] , [ '🖐️' , 'hand' ] , [ '✋' , 'raised hand' ] , [ '🖖' , 'vulcan' ] , [ '👌' , 'ok' ] , [ '🤌' , 'pinched' ] , [ '🤏' , 'pinch' ] , [ '✌️' , 'peace' ] , [ '🤞' , 'cross fingers luck' ] , [ '🤟' , 'love you' ] , [ '🤘' , 'rock' ] , [ '🤙' , 'call me' ] , [ '👈' , 'point left' ] , [ '👉' , 'point right' ] , [ '👆' , 'point up' ] , [ '👇' , 'point down' ] , [ '☝️' , 'point up' ] , [ '👍' , 'thumbs up like' ] , [ '👎' , 'thumbs down dislike' ] , [ '✊' , 'fist' ] , [ '👊' , 'fist bump' ] , [ '🤛' , 'fist' ] , [ '🤜' , 'fist' ] , [ '👏' , 'clap' ] , [ '🙌' , 'raise hands celebrate' ] , [ '🫶' , 'heart hands' ] , [ '👐' , 'open hands' ] , [ '🤲' , 'palms' ] , [ '🤝' , 'handshake' ] , [ '🙏' , 'pray thanks' ] , [ '💪' , 'muscle strong' ] , [ '👂' , 'ear' ] , [ '👃' , 'nose' ] , [ '👀' , 'eyes look' ] , [ '👁️' , 'eye' ] , [ '🧠' , 'brain' ] , [ '👶' , 'baby' ] , [ '🧒' , 'child' ] , [ '👦' , 'boy' ] , [ '👧' , 'girl' ] , [ '🧑' , 'person' ] , [ '👨' , 'man' ] , [ '👩' , 'woman' ] , [ '🧓' , 'older person' ] , [ '👴' , 'old man' ] , [ '👵' , 'old woman' ] , [ '👮' , 'police' ] , [ '🕵️' , 'detective' ] , [ '💂' , 'guard' ] , [ '👷' , 'worker' ] , [ '🤴' , 'prince' ] , [ '👸' , 'princess' ] , [ '👳' , 'turban' ] , [ '🧕' , 'hijab' ] , [ '🤵' , 'tuxedo' ] , [ '👰' , 'bride' ] , [ '🤰' , 'pregnant' ] , [ '🤱' , 'breastfeeding' ] , [ '👼' , 'angel' ] , [ '🎅' , 'santa' ] , [ '🤶' , 'mrs claus' ] , [ '🦸' , 'superhero' ] , [ '🦹' , 'supervillain' ] , [ '🧙' , 'mage wizard' ] , [ '🧚' , 'fairy' ] , [ '🧛' , 'vampire' ] , [ '🧜' , 'mermaid' ] , [ '🧝' , 'elf' ] , [ '💆' , 'massage' ] , [ '💇' , 'haircut' ] , [ '🚶' , 'walk' ] , [ '🏃' , 'run' ] , [ '💃' , 'dance' ] , [ '🕺' , 'dance' ] , [ '👯' , 'people dancing' ] , [ '🧗' , 'climb' ] , [ '🏇' , 'horse race' ] , [ '🏂' , 'snowboard' ] , [ '🏄' , 'surf' ] , [ '🚣' , 'row' ] , [ '🏊' , 'swim' ] , [ '🚴' , 'bike' ] , [ '🚵' , 'mountain bike' ] , [ '🤸' , 'cartwheel' ] , [ '🤼' , 'wrestle' ] , [ '🤽' , 'water polo' ] , [ '🤾' , 'handball' ] , [ '🤹' , 'juggle' ] , [ '🧘' , 'meditate yoga' ] , [ '🛌' , 'sleeping bed' ] , [ '💋' , 'kiss mark' ] , [ '💌' , 'love letter' ] , [ '❤️' , 'heart love red' ] , [ '🧡' , 'orange heart' ] , [ '💛' , 'yellow heart' ] , [ '💚' , 'green heart' ] , [ '💙' , 'blue heart' ] , [ '💜' , 'purple heart' ] , [ '🖤' , 'black heart' ] , [ '🤍' , 'white heart' ] , [ '🤎' , 'brown heart' ] , [ '💔' , 'broken heart' ] , [ '❣️' , 'heart exclamation' ] , [ '💕' , 'two hearts' ] , [ '💞' , 'revolving hearts' ] , [ '💓' , 'beating heart' ] , [ '💗' , 'growing heart' ] , [ '💖' , 'sparkling heart' ] , [ '💘' , 'cupid heart' ] , [ '💝' , 'heart gift' ] , [ '✨' , 'sparkles' ] , [ '⭐' , 'star' ] , [ '🌟' , 'glowing star' ] , [ '💫' , 'dizzy star' ] , [ '💥' , 'boom' ] , [ '💯' , 'hundred perfect' ]
] } ,
{ id : 'nature' , label : 'Nature' , items : [
[ '🐶' , 'dog' ] , [ '🐱' , 'cat' ] , [ '🐭' , 'mouse' ] , [ '🐹' , 'hamster' ] , [ '🐰' , 'rabbit' ] , [ '🦊' , 'fox' ] , [ '🐻' , 'bear' ] , [ '🐼' , 'panda' ] , [ '🐨' , 'koala' ] , [ '🐯' , 'tiger' ] , [ '🦁' , 'lion' ] , [ '🐮' , 'cow' ] , [ '🐷' , 'pig' ] , [ '🐸' , 'frog' ] , [ '🐵' , 'monkey' ] , [ '🐔' , 'chicken' ] , [ '🐧' , 'penguin' ] , [ '🐦' , 'bird' ] , [ '🐤' , 'chick' ] , [ '🦆' , 'duck' ] , [ '🦅' , 'eagle' ] , [ '🦉' , 'owl' ] , [ '🦇' , 'bat' ] , [ '🐺' , 'wolf' ] , [ '🐗' , 'boar' ] , [ '🐴' , 'horse' ] , [ '🦄' , 'unicorn' ] , [ '🐝' , 'bee' ] , [ '🐛' , 'bug' ] , [ '🦋' , 'butterfly' ] , [ '🐌' , 'snail' ] , [ '🐞' , 'ladybug' ] , [ '🐜' , 'ant' ] , [ '🦗' , 'cricket' ] , [ '🕷️' , 'spider' ] , [ '🦂' , 'scorpion' ] , [ '🐢' , 'turtle' ] , [ '🐍' , 'snake' ] , [ '🦎' , 'lizard' ] , [ '🦖' , 'dinosaur' ] , [ '🐙' , 'octopus' ] , [ '🦑' , 'squid' ] , [ '🦐' , 'shrimp' ] , [ '🦀' , 'crab' ] , [ '🐡' , 'fish' ] , [ '🐠' , 'fish' ] , [ '🐟' , 'fish' ] , [ '🐬' , 'dolphin' ] , [ '🐳' , 'whale' ] , [ '🦈' , 'shark' ] , [ '🐊' , 'crocodile' ] , [ '🌵' , 'cactus' ] , [ '🎄' , 'tree christmas' ] , [ '🌲' , 'tree evergreen' ] , [ '🌳' , 'tree' ] , [ '🌴' , 'palm tree' ] , [ '🌱' , 'seedling plant' ] , [ '🌿' , 'herb leaf' ] , [ '☘️' , 'shamrock' ] , [ '🍀' , 'clover luck' ] , [ '🎍' , 'bamboo' ] , [ '🌾' , 'wheat' ] , [ '🌷' , 'tulip flower' ] , [ '🌹' , 'rose flower' ] , [ '🌺' , 'hibiscus flower' ] , [ '🌸' , 'cherry blossom' ] , [ '🌼' , 'flower' ] , [ '🌻' , 'sunflower' ] , [ '🌞' , 'sun' ] , [ '🌝' , 'moon' ] , [ '🌚' , 'moon' ] , [ '🌙' , 'moon crescent' ] , [ '⭐' , 'star' ] , [ '🌟' , 'star' ] , [ '☀️' , 'sun sunny' ] , [ '⛅' , 'cloud sun' ] , [ '☁️' , 'cloud' ] , [ '🌧️' , 'rain' ] , [ '⛈️' , 'storm' ] , [ '🌩️' , 'lightning' ] , [ '❄️' , 'snowflake' ] , [ '☃️' , 'snowman' ] , [ '⛄' , 'snowman' ] , [ '🔥' , 'fire' ] , [ '💧' , 'droplet water' ] , [ '🌊' , 'wave water' ] , [ '🌈' , 'rainbow' ] , [ '🌍' , 'earth globe' ] , [ '🌎' , 'earth globe' ] , [ '🌏' , 'earth globe' ]
] } ,
{ id : 'food' , label : 'Food' , items : [
[ '🍏' , 'apple green' ] , [ '🍎' , 'apple red' ] , [ '🍐' , 'pear' ] , [ '🍊' , 'orange tangerine' ] , [ '🍋' , 'lemon' ] , [ '🍌' , 'banana' ] , [ '🍉' , 'watermelon' ] , [ '🍇' , 'grapes' ] , [ '🍓' , 'strawberry' ] , [ '🫐' , 'blueberry' ] , [ '🍈' , 'melon' ] , [ '🍒' , 'cherry' ] , [ '🍑' , 'peach' ] , [ '🥭' , 'mango' ] , [ '🍍' , 'pineapple' ] , [ '🥥' , 'coconut' ] , [ '🥝' , 'kiwi' ] , [ '🍅' , 'tomato' ] , [ '🍆' , 'eggplant' ] , [ '🥑' , 'avocado' ] , [ '🥦' , 'broccoli' ] , [ '🥬' , 'lettuce' ] , [ '🥒' , 'cucumber' ] , [ '🌶️' , 'pepper hot' ] , [ '🌽' , 'corn' ] , [ '🥕' , 'carrot' ] , [ '🧄' , 'garlic' ] , [ '🧅' , 'onion' ] , [ '🥔' , 'potato' ] , [ '🍠' , 'sweet potato' ] , [ '🥐' , 'croissant' ] , [ '🥯' , 'bagel' ] , [ '🍞' , 'bread' ] , [ '🥖' , 'baguette' ] , [ '🧀' , 'cheese' ] , [ '🥚' , 'egg' ] , [ '🍳' , 'cooking egg' ] , [ '🥓' , 'bacon' ] , [ '🥩' , 'meat steak' ] , [ '🍗' , 'chicken leg' ] , [ '🍖' , 'meat' ] , [ '🌭' , 'hot dog' ] , [ '🍔' , 'burger' ] , [ '🍟' , 'fries' ] , [ '🍕' , 'pizza' ] , [ '🥪' , 'sandwich' ] , [ '🥙' , 'pita' ] , [ '🌮' , 'taco' ] , [ '🌯' , 'burrito' ] , [ '🥗' , 'salad' ] , [ '🍝' , 'pasta spaghetti' ] , [ '🍜' , 'ramen noodles' ] , [ '🍲' , 'stew' ] , [ '🍛' , 'curry rice' ] , [ '🍣' , 'sushi' ] , [ '🍱' , 'bento' ] , [ '🥟' , 'dumpling' ] , [ '🍤' , 'shrimp fried' ] , [ '🍙' , 'rice ball' ] , [ '🍚' , 'rice' ] , [ '🍘' , 'rice cracker' ] , [ '🍥' , 'fish cake' ] , [ '🥠' , 'fortune cookie' ] , [ '🍢' , 'oden' ] , [ '🍡' , 'dango' ] , [ '🍧' , 'shaved ice' ] , [ '🍨' , 'ice cream' ] , [ '🍦' , 'ice cream' ] , [ '🥧' , 'pie' ] , [ '🧁' , 'cupcake' ] , [ '🍰' , 'cake' ] , [ '🎂' , 'birthday cake' ] , [ '🍮' , 'custard' ] , [ '🍭' , 'lollipop' ] , [ '🍬' , 'candy' ] , [ '🍫' , 'chocolate' ] , [ '🍿' , 'popcorn' ] , [ '🍩' , 'donut' ] , [ '🍪' , 'cookie' ] , [ '☕' , 'coffee' ] , [ '🍵' , 'tea' ] , [ '🧃' , 'juice' ] , [ '🥤' , 'cup drink' ] , [ '🍺' , 'beer' ] , [ '🍻' , 'beers cheers' ] , [ '🥂' , 'champagne' ] , [ '🍷' , 'wine' ] , [ '🥃' , 'whiskey' ] , [ '🍸' , 'cocktail' ] , [ '🍹' , 'tropical drink' ] , [ '🧉' , 'mate' ] , [ '🍾' , 'champagne bottle' ]
] } ,
{ id : 'activity' , label : 'Activity' , items : [
[ '⚽' , 'soccer football' ] , [ '🏀' , 'basketball' ] , [ '🏈' , 'football' ] , [ '⚾' , 'baseball' ] , [ '🥎' , 'softball' ] , [ '🎾' , 'tennis' ] , [ '🏐' , 'volleyball' ] , [ '🏉' , 'rugby' ] , [ '🥏' , 'frisbee' ] , [ '🎱' , 'pool billiards' ] , [ '🪀' , 'yo-yo' ] , [ '🏓' , 'ping pong' ] , [ '🏸' , 'badminton' ] , [ '🏒' , 'hockey' ] , [ '🏑' , 'field hockey' ] , [ '🥍' , 'lacrosse' ] , [ '🏏' , 'cricket' ] , [ '🥅' , 'goal' ] , [ '⛳' , 'golf' ] , [ '🏹' , 'archery' ] , [ '🎣' , 'fishing' ] , [ '🥊' , 'boxing' ] , [ '🥋' , 'martial arts' ] , [ '🎽' , 'running shirt' ] , [ '🛹' , 'skateboard' ] , [ '🛼' , 'roller skate' ] , [ '🛷' , 'sled' ] , [ '⛸️' , 'ice skate' ] , [ '🥌' , 'curling' ] , [ '🎿' , 'ski' ] , [ '⛷️' , 'ski' ] , [ '🏂' , 'snowboard' ] , [ '🏋️' , 'weight lift' ] , [ '🤼' , 'wrestle' ] , [ '🤸' , 'cartwheel' ] , [ '⛹️' , 'basketball' ] , [ '🤺' , 'fencing' ] , [ '🤾' , 'handball' ] , [ '🏌️' , 'golf' ] , [ '🏇' , 'horse race' ] , [ '🧘' , 'yoga meditate' ] , [ '🏄' , 'surf' ] , [ '🏊' , 'swim' ] , [ '🤽' , 'water polo' ] , [ '🚣' , 'row' ] , [ '🧗' , 'climb' ] , [ '🚴' , 'bike' ] , [ '🚵' , 'mountain bike' ] , [ '🎪' , 'circus' ] , [ '🎭' , 'theater masks' ] , [ '🎨' , 'art palette' ] , [ '🎬' , 'clapper film' ] , [ '🎤' , 'microphone' ] , [ '🎧' , 'headphones' ] , [ '🎼' , 'music score' ] , [ '🎹' , 'piano' ] , [ '🥁' , 'drum' ] , [ '🎷' , 'saxophone' ] , [ '🎺' , 'trumpet' ] , [ '🎸' , 'guitar' ] , [ '🪕' , 'banjo' ] , [ '🎻' , 'violin' ] , [ '🎲' , 'dice random game' ] , [ '♟️' , 'chess' ] , [ '🎯' , 'target dart' ] , [ '🎳' , 'bowling' ] , [ '🎮' , 'game controller' ] , [ '🎰' , 'slot machine' ] , [ '🧩' , 'puzzle' ] , [ '🏆' , 'trophy win' ] , [ '🥇' , 'gold medal first' ] , [ '🥈' , 'silver medal' ] , [ '🥉' , 'bronze medal' ] , [ '🏅' , 'medal' ] , [ '🎖️' , 'military medal' ] , [ '🎗️' , 'reminder ribbon' ] , [ '🎫' , 'ticket' ] , [ '🎟️' , 'tickets' ] , [ '🎁' , 'gift present' ] , [ '🎉' , 'party popper celebrate' ] , [ '🎊' , 'confetti' ] , [ '🎈' , 'balloon' ] , [ '🎂' , 'cake birthday' ] , [ '🎃' , 'pumpkin halloween' ] , [ '🎄' , 'christmas tree' ] , [ '🎆' , 'fireworks' ] , [ '🎇' , 'fireworks' ] , [ '🧨' , 'firecracker' ] , [ '✨' , 'sparkles' ] , [ '🎓' , 'graduation cap' ]
] } ,
{ id : 'travel' , label : 'Travel' , items : [
[ '🚗' , 'car' ] , [ '🚕' , 'taxi' ] , [ '🚙' , 'car suv' ] , [ '🚌' , 'bus' ] , [ '🚎' , 'trolley bus' ] , [ '🏎️' , 'race car' ] , [ '🚓' , 'police car' ] , [ '🚑' , 'ambulance' ] , [ '🚒' , 'fire truck' ] , [ '🚐' , 'van' ] , [ '🛻' , 'pickup truck' ] , [ '🚚' , 'truck' ] , [ '🚛' , 'truck' ] , [ '🚜' , 'tractor' ] , [ '🏍️' , 'motorcycle' ] , [ '🛵' , 'scooter' ] , [ '🚲' , 'bicycle' ] , [ '🛴' , 'kick scooter' ] , [ '🚨' , 'police light' ] , [ '🚔' , 'police car' ] , [ '🚍' , 'bus' ] , [ '🚝' , 'monorail' ] , [ '🚄' , 'train' ] , [ '🚅' , 'train bullet' ] , [ '🚈' , 'train' ] , [ '🚂' , 'locomotive train' ] , [ '🚆' , 'train' ] , [ '🚇' , 'metro subway' ] , [ '🚊' , 'tram' ] , [ '🚉' , 'station' ] , [ '✈️' , 'airplane flight' ] , [ '🛫' , 'airplane takeoff' ] , [ '🛬' , 'airplane landing' ] , [ '🛩️' , 'plane' ] , [ '💺' , 'seat' ] , [ '🚁' , 'helicopter' ] , [ '🛸' , 'ufo' ] , [ '🚀' , 'rocket launch' ] , [ '🛰️' , 'satellite' ] , [ '🚢' , 'ship' ] , [ '⛵' , 'sailboat' ] , [ '🛥️' , 'motor boat' ] , [ '🚤' , 'speedboat' ] , [ '⛴️' , 'ferry' ] , [ '🛳️' , 'cruise ship' ] , [ '⚓' , 'anchor' ] , [ '🚧' , 'construction' ] , [ '⛽' , 'fuel gas' ] , [ '🚏' , 'bus stop' ] , [ '🗺️' , 'map world' ] , [ '🗿' , 'moai' ] , [ '🗽' , 'statue liberty' ] , [ '🗼' , 'tokyo tower' ] , [ '🏰' , 'castle' ] , [ '🏯' , 'castle japanese' ] , [ '🏟️' , 'stadium' ] , [ '🎡' , 'ferris wheel' ] , [ '🎢' , 'roller coaster' ] , [ '🎠' , 'carousel' ] , [ '⛲' , 'fountain' ] , [ '⛱️' , 'beach umbrella' ] , [ '🏖️' , 'beach' ] , [ '🏝️' , 'island' ] , [ '🏜️' , 'desert' ] , [ '🌋' , 'volcano' ] , [ '⛰️' , 'mountain' ] , [ '🏔️' , 'snow mountain' ] , [ '🗻' , 'mount fuji' ] , [ '🏕️' , 'camping' ] , [ '🏠' , 'house home' ] , [ '🏡' , 'house garden' ] , [ '🏢' , 'office building' ] , [ '🏥' , 'hospital' ] , [ '🏦' , 'bank' ] , [ '🏨' , 'hotel' ] , [ '🏫' , 'school' ] , [ '🏭' , 'factory' ] , [ '🏛️' , 'classical building' ] , [ '⛪' , 'church' ] , [ '🕌' , 'mosque' ] , [ '🕍' , 'synagogue' ] , [ '🛕' , 'temple' ] , [ '🗼' , 'tower' ] , [ '🌆' , 'city sunset' ] , [ '🌃' , 'night city' ] , [ '🌉' , 'bridge night' ] , [ '🌌' , 'milky way' ] , [ '🌠' , 'shooting star' ] , [ '🌅' , 'sunrise' ] , [ '🌄' , 'sunrise mountain' ] , [ '🌇' , 'sunset city' ]
] } ,
{ id : 'objects' , label : 'Objects' , items : [
[ '⌚' , 'watch' ] , [ '📱' , 'phone mobile' ] , [ '💻' , 'laptop computer' ] , [ '⌨️' , 'keyboard' ] , [ '🖥️' , 'desktop computer' ] , [ '🖨️' , 'printer' ] , [ '🖱️' , 'mouse computer' ] , [ '💽' , 'minidisc' ] , [ '💾' , 'floppy disk save' ] , [ '💿' , 'cd disk' ] , [ '📀' , 'dvd' ] , [ '🧮' , 'abacus' ] , [ '🎥' , 'movie camera' ] , [ '🎞️' , 'film frames' ] , [ '📽️' , 'projector' ] , [ '📺' , 'tv television' ] , [ '📷' , 'camera' ] , [ '📸' , 'camera flash' ] , [ '📹' , 'video camera' ] , [ '📼' , 'videocassette' ] , [ '🔍' , 'magnifying search' ] , [ '🔎' , 'magnifying search' ] , [ '🕯️' , 'candle' ] , [ '💡' , 'bulb idea' ] , [ '🔦' , 'flashlight' ] , [ '🏮' , 'lantern' ] , [ '🪔' , 'lamp diya' ] , [ '📔' , 'notebook' ] , [ '📕' , 'book closed' ] , [ '📖' , 'book open' ] , [ '📗' , 'book green' ] , [ '📘' , 'book blue' ] , [ '📙' , 'book orange' ] , [ '📚' , 'books library' ] , [ '📓' , 'notebook' ] , [ '📒' , 'ledger' ] , [ '📃' , 'page' ] , [ '📜' , 'scroll' ] , [ '📄' , 'page document' ] , [ '📰' , 'newspaper' ] , [ '🗞️' , 'newspaper' ] , [ '📑' , 'bookmark tabs' ] , [ '🔖' , 'bookmark' ] , [ '🏷️' , 'label tag' ] , [ '💰' , 'money bag' ] , [ '🪙' , 'coin' ] , [ '💴' , 'yen' ] , [ '💵' , 'dollar' ] , [ '💶' , 'euro' ] , [ '💷' , 'pound' ] , [ '💸' , 'money wings' ] , [ '💳' , 'credit card' ] , [ '🧾' , 'receipt' ] , [ '✉️' , 'envelope mail' ] , [ '📧' , 'email' ] , [ '📨' , 'envelope' ] , [ '📩' , 'envelope' ] , [ '📤' , 'outbox' ] , [ '📥' , 'inbox' ] , [ '📦' , 'package box' ] , [ '📫' , 'mailbox' ] , [ '📪' , 'mailbox' ] , [ '📬' , 'mailbox' ] , [ '📭' , 'mailbox' ] , [ '📮' , 'postbox' ] , [ '🗳️' , 'ballot box' ] , [ '✏️' , 'pencil' ] , [ '✒️' , 'pen nib' ] , [ '🖋️' , 'pen' ] , [ '🖊️' , 'pen' ] , [ '🖌️' , 'paintbrush' ] , [ '🖍️' , 'crayon' ] , [ '📝' , 'memo note write' ] , [ '💼' , 'briefcase work' ] , [ '📁' , 'folder' ] , [ '📂' , 'folder open' ] , [ '🗂️' , 'card index' ] , [ '📅' , 'calendar date' ] , [ '📆' , 'calendar' ] , [ '🗒️' , 'notepad' ] , [ '🗓️' , 'calendar' ] , [ '📇' , 'card index' ] , [ '📈' , 'chart up trending' ] , [ '📉' , 'chart down' ] , [ '📊' , 'bar chart stats' ] , [ '📋' , 'clipboard' ] , [ '📌' , 'pushpin' ] , [ '📍' , 'pin location' ] , [ '📎' , 'paperclip attach' ] , [ '🖇️' , 'paperclips' ] , [ '📏' , 'ruler' ] , [ '📐' , 'triangle ruler' ] , [ '✂️' , 'scissors cut' ] , [ '🗃️' , 'file box' ] , [ '🗄️' , 'file cabinet' ] , [ '🗑️' , 'trash waste' ] , [ '🔒' , 'lock locked' ] , [ '🔓' , 'lock open' ] , [ '🔑' , 'key' ] , [ '🗝️' , 'old key' ] , [ '🔨' , 'hammer' ] , [ '🪓' , 'axe' ] , [ '⛏️' , 'pick' ] , [ '⚒️' , 'tools' ] , [ '🛠️' , 'tools' ] , [ '🔧' , 'wrench' ] , [ '🔩' , 'bolt nut' ] , [ '⚙️' , 'gear settings' ] , [ '🧰' , 'toolbox' ] , [ '🧲' , 'magnet' ] , [ '🔫' , 'water gun' ] , [ '💣' , 'bomb' ] , [ '🧪' , 'test tube science' ] , [ '🧫' , 'petri dish' ] , [ '🧬' , 'dna' ] , [ '🔬' , 'microscope' ] , [ '🔭' , 'telescope' ] , [ '📡' , 'satellite antenna' ] , [ '💉' , 'syringe' ] , [ '💊' , 'pill medicine' ] , [ '🩹' , 'bandage' ] , [ '🩺' , 'stethoscope' ] , [ '🚪' , 'door' ] , [ '🛏️' , 'bed' ] , [ '🛋️' , 'couch' ] , [ '🪑' , 'chair' ] , [ '🚽' , 'toilet' ] , [ '🚿' , 'shower' ] , [ '🛁' , 'bathtub' ] , [ '🧴' , 'lotion' ] , [ '🧷' , 'safety pin' ] , [ '🧹' , 'broom' ] , [ '🧺' , 'basket' ] , [ '🧻' , 'toilet paper' ] , [ '🧼' , 'soap' ] , [ '🪒' , 'razor' ] , [ '🧽' , 'sponge' ] , [ '🧯' , 'extinguisher' ] , [ '🛒' , 'cart shopping' ] , [ '🚬' , 'cigarette' ] , [ '⚰️' , 'coffin' ] , [ '🪦' , 'headstone' ] , [ '⚱️' , 'urn' ]
] } ,
{ id : 'symbols' , label : 'Symbols' , items : [
[ '❤️' , 'heart love' ] , [ '🧡' , 'orange heart' ] , [ '💛' , 'yellow heart' ] , [ '💚' , 'green heart' ] , [ '💙' , 'blue heart' ] , [ '💜' , 'purple heart' ] , [ '🖤' , 'black heart' ] , [ '🤍' , 'white heart' ] , [ '🤎' , 'brown heart' ] , [ '💔' , 'broken heart' ] , [ '❣️' , 'heart' ] , [ '💕' , 'hearts' ] , [ '💞' , 'hearts' ] , [ '💓' , 'heartbeat' ] , [ '💗' , 'heart' ] , [ '💖' , 'heart' ] , [ '💘' , 'heart arrow' ] , [ '💝' , 'heart gift' ] , [ '💟' , 'heart decoration' ] , [ '☮️' , 'peace' ] , [ '✝️' , 'cross' ] , [ '☪️' , 'star crescent' ] , [ '🕉️' , 'om' ] , [ '☸️' , 'dharma' ] , [ '✡️' , 'star david' ] , [ '🔯' , 'star' ] , [ '🕎' , 'menorah' ] , [ '☯️' , 'yin yang' ] , [ '☦️' , 'orthodox cross' ] , [ '🛐' , 'worship' ] , [ '⛎' , 'ophiuchus' ] , [ '♈' , 'aries' ] , [ '♉' , 'taurus' ] , [ '♊' , 'gemini' ] , [ '♋' , 'cancer' ] , [ '♌' , 'leo' ] , [ '♍' , 'virgo' ] , [ '♎' , 'libra' ] , [ '♏' , 'scorpio' ] , [ '♐' , 'sagittarius' ] , [ '♑' , 'capricorn' ] , [ '♒' , 'aquarius' ] , [ '♓' , 'pisces' ] , [ '🆔' , 'id' ] , [ '⚛️' , 'atom' ] , [ '🉑' , 'accept' ] , [ '☢️' , 'radioactive' ] , [ '☣️' , 'biohazard' ] , [ '📴' , 'phone off' ] , [ '📳' , 'vibrate' ] , [ '📵' , 'no phone' ] , [ '🚭' , 'no smoking' ] , [ '❗' , 'exclamation' ] , [ '❕' , 'exclamation' ] , [ '❓' , 'question' ] , [ '❔' , 'question' ] , [ '‼️' , 'double exclamation' ] , [ '⁉️' , 'exclamation question' ] , [ '🔅' , 'dim' ] , [ '🔆' , 'bright' ] , [ '〽️' , 'part alternation' ] , [ '⚠️' , 'warning' ] , [ '🚸' , 'children crossing' ] , [ '🔱' , 'trident' ] , [ '⚜️' , 'fleur de lis' ] , [ '🔰' , 'beginner' ] , [ '♻️' , 'recycle' ] , [ '✅' , 'check done' ] , [ '🈯' , 'reserved' ] , [ '💹' , 'chart yen' ] , [ '❇️' , 'sparkle' ] , [ '✳️' , 'asterisk' ] , [ '❎' , 'cross mark' ] , [ '🌐' , 'globe' ] , [ '💠' , 'diamond' ] , [ 'Ⓜ️' , 'm' ] , [ '🌀' , 'cyclone' ] , [ '💤' , 'zzz sleep' ] , [ '🏧' , 'atm' ] , [ '🚾' , 'wc' ] , [ '♿' , 'wheelchair' ] , [ '🅿️' , 'parking' ] , [ '🈳' , 'vacancy' ] , [ '🈂️' , 'sa' ] , [ '🛂' , 'passport control' ] , [ '🛃' , 'customs' ] , [ '🛄' , 'baggage' ] , [ '🛅' , 'left luggage' ] , [ '🚹' , 'men' ] , [ '🚺' , 'women' ] , [ '🚼' , 'baby' ] , [ '🚻' , 'restroom' ] , [ '🚮' , 'litter' ] , [ '🎦' , 'cinema' ] , [ '📶' , 'signal' ] , [ '🈁' , 'here' ] , [ '🔣' , 'symbols' ] , [ 'ℹ ️' , 'info' ] , [ '🔤' , 'abc' ] , [ '🔡' , 'abcd' ] , [ '🔠' , 'abcd' ] , [ '🆖' , 'ng' ] , [ '🆗' , 'ok' ] , [ '🆙' , 'up' ] , [ '🆒' , 'cool' ] , [ '🆕' , 'new' ] , [ '🆓' , 'free' ] , [ '0️⃣' , 'zero' ] , [ '1️⃣' , 'one' ] , [ '2️⃣' , 'two' ] , [ '3️⃣' , 'three' ] , [ '4️⃣' , 'four' ] , [ '5️⃣' , 'five' ] , [ '6️⃣' , 'six' ] , [ '7️⃣' , 'seven' ] , [ '8️⃣' , 'eight' ] , [ '9️⃣' , 'nine' ] , [ '🔟' , 'ten' ] , [ '🔢' , 'numbers' ] , [ '#️⃣' , 'hash' ] , [ '*️⃣' , 'asterisk' ] , [ '⏏️' , 'eject' ] , [ '▶️' , 'play' ] , [ '⏸️' , 'pause' ] , [ '⏹️' , 'stop' ] , [ '⏺️' , 'record' ] , [ '⏭️' , 'next' ] , [ '⏮️' , 'previous' ] , [ '⏩' , 'fast forward' ] , [ '⏪' , 'rewind' ] , [ '⏫' , 'up' ] , [ '⏬' , 'down' ] , [ '◀️' , 'left' ] , [ '🔼' , 'up' ] , [ '🔽' , 'down' ] , [ '➡️' , 'right' ] , [ '⬅️' , 'left' ] , [ '⬆️' , 'up' ] , [ '⬇️' , 'down' ] , [ '↗️' , 'up right' ] , [ '↘️' , 'down right' ] , [ '↙️' , 'down left' ] , [ '↖️' , 'up left' ] , [ '↕️' , 'up down' ] , [ '↔️' , 'left right' ] , [ '↩️' , 'return' ] , [ '↪️' , 'redo' ] , [ '⤴️' , 'up' ] , [ '⤵️' , 'down' ] , [ '🔀' , 'shuffle' ] , [ '🔁' , 'repeat' ] , [ '🔂' , 'repeat one' ] , [ '🔄' , 'refresh' ] , [ '🔃' , 'refresh' ] , [ '🎵' , 'music note' ] , [ '🎶' , 'music notes' ] , [ '➕ ' , 'plus' ] , [ '➖ ' , 'minus' ] , [ '➗' , 'divide' ] , [ '✖️' , 'multiply' ] , [ '♾️' , 'infinity' ] , [ '💲' , 'dollar' ] , [ '💱' , 'currency' ] , [ '™️' , 'tm' ] , [ '©️' , 'copyright' ] , [ '®️' , 'registered' ] , [ '〰️' , 'wavy' ] , [ '➰' , 'curly loop' ] , [ '➿' , 'double loop' ] , [ '🔚' , 'end' ] , [ '🔙' , 'back' ] , [ '🔛' , 'on' ] , [ '🔝' , 'top' ] , [ '🔜' , 'soon' ] , [ '✔️' , 'check' ] , [ '☑️' , 'checkbox' ] , [ '🔘' , 'radio' ] , [ '🔴' , 'red circle' ] , [ '🟠' , 'orange circle' ] , [ '🟡' , 'yellow circle' ] , [ '🟢' , 'green circle' ] , [ '🔵' , 'blue circle' ] , [ '🟣' , 'purple circle' ] , [ '⚫' , 'black circle' ] , [ '⚪' , 'white circle' ] , [ '🟤' , 'brown circle' ] , [ '🔺' , 'red triangle' ] , [ '🔻' , 'red triangle' ] , [ '🔸' , 'orange diamond' ] , [ '🔹' , 'blue diamond' ] , [ '🔶' , 'orange diamond' ] , [ '🔷' , 'blue diamond' ] , [ '🔳' , 'white square' ] , [ '🔲' , 'black square' ] , [ '▪️' , 'black square' ] , [ '▫️' , 'white square' ] , [ '◾' , 'black square' ] , [ '◽' , 'white square' ] , [ '◼️' , 'black square' ] , [ '◻️' , 'white square' ] , [ '🟥' , 'red square' ] , [ '🟧' , 'orange square' ] , [ '🟨' , 'yellow square' ] , [ '🟩' , 'green square' ] , [ '🟦' , 'blue square' ] , [ '🟪' , 'purple square' ] , [ '⬛' , 'black square' ] , [ '⬜' , 'white square' ] , [ '🟫' , 'brown square' ] , [ '🔈' , 'speaker' ] , [ '🔇' , 'mute' ] , [ '🔉' , 'speaker' ] , [ '🔊' , 'speaker loud' ] , [ '🔔' , 'bell' ] , [ '🔕' , 'bell off' ] , [ '📣' , 'megaphone' ] , [ '📢' , 'loudspeaker' ] , [ '💬' , 'speech bubble' ] , [ '💭' , 'thought bubble' ] , [ '🗯️' , 'anger bubble' ] , [ '♠️' , 'spade' ] , [ '♣️' , 'club' ] , [ '♥️' , 'heart suit' ] , [ '♦️' , 'diamond suit' ] , [ '🃏' , 'joker' ] , [ '🎴' , 'flower cards' ] , [ '🀄' , 'mahjong' ]
] } ,
{ id : 'flags' , label : 'Flags' , items : [
[ '🏁' , 'chequered flag finish' ] , [ '🚩' , 'triangular flag' ] , [ '🎌' , 'crossed flags' ] , [ '🏴' , 'black flag' ] , [ '🏳️' , 'white flag' ] , [ '🏳️🌈' , 'rainbow flag pride' ] , [ '🏴☠️' , 'pirate flag' ] , [ '🇺🇸' , 'usa united states' ] , [ '🇬🇧' , 'uk united kingdom' ] , [ '🇫🇷' , 'france french' ] , [ '🇩🇪' , 'germany german' ] , [ '🇪🇸' , 'spain spanish' ] , [ '🇮🇹' , 'italy italian' ] , [ '🇵🇹' , 'portugal' ] , [ '🇳🇱' , 'netherlands' ] , [ '🇧🇪' , 'belgium' ] , [ '🇨🇭' , 'switzerland' ] , [ '🇦🇹' , 'austria' ] , [ '🇸🇪' , 'sweden' ] , [ '🇳🇴' , 'norway' ] , [ '🇩🇰' , 'denmark' ] , [ '🇫🇮' , 'finland' ] , [ '🇮🇪' , 'ireland' ] , [ '🇵🇱' , 'poland' ] , [ '🇬🇷' , 'greece' ] , [ '🇷🇺' , 'russia' ] , [ '🇺🇦' , 'ukraine' ] , [ '🇹🇷' , 'turkey' ] , [ '🇨🇦' , 'canada' ] , [ '🇲🇽' , 'mexico' ] , [ '🇧🇷' , 'brazil' ] , [ '🇦🇷' , 'argentina' ] , [ '🇨🇱' , 'chile' ] , [ '🇨🇴' , 'colombia' ] , [ '🇨🇳' , 'china chinese' ] , [ '🇯🇵' , 'japan japanese' ] , [ '🇰🇷' , 'korea south' ] , [ '🇮🇳' , 'india' ] , [ '🇦🇺' , 'australia' ] , [ '🇳🇿' , 'new zealand' ] , [ '🇿🇦' , 'south africa' ] , [ '🇪🇬' , 'egypt' ] , [ '🇲🇦' , 'morocco' ] , [ '🇳🇬' , 'nigeria' ] , [ '🇰🇪' , 'kenya' ] , [ '🇸🇦' , 'saudi arabia' ] , [ '🇦🇪' , 'uae emirates' ] , [ '🇮🇱' , 'israel' ] , [ '🇸🇬' , 'singapore' ] , [ '🇹🇭' , 'thailand' ] , [ '🇻🇳' , 'vietnam' ] , [ '🇮🇩' , 'indonesia' ] , [ '🇵🇭' , 'philippines' ] , [ '🇲🇾' , 'malaysia' ] , [ '🇵🇰' , 'pakistan' ] , [ '🇧🇩' , 'bangladesh' ] , [ '🇺🇳' , 'united nations' ]
] }
] ;
document . addEventListener ( 'alpine:init' , function ( ) {
if ( window . Alpine && window . Alpine . _ _fdIconPicker ) return ;
if ( window . Alpine ) window . Alpine . _ _fdIconPicker = true ;
Alpine . store ( 'fdIconPicker' , {
open : false , x : 0 , y : 0 , tab : 'emoji' , query : '' , category : 'people' ,
skinTone : 0 , toneOpen : false , recent : [ ] , custom : [ ] , customLoaded : false ,
customModal : false , customName : '' , customPreview : '' , customFile : null , customBusy : false ,
onPick : null , onRemove : null , _cx : 0 , _cy : 0 ,
cats : CATS ,
openFor ( opts ) {
opts = opts || { } ;
this . onPick = opts . onPick || null ;
this . onRemove = opts . onRemove || null ;
this . query = '' ;
this . toneOpen = false ;
this . customModal = false ;
this . _cx = ( opts . x != null ) ? opts . x : 240 ;
this . _cy = ( opts . y != null ) ? opts . y : 200 ;
this . x = this . _cx ;
this . y = this . _cy ;
this . open = true ;
var self = this ;
var place = function ( ) {
var el = document . querySelector ( '.fd-icon-picker' ) ;
if ( ! el ) return ;
var w = el . offsetWidth || 344 , h = el . offsetHeight || 440 ;
var vw = window . innerWidth , vh = window . innerHeight ;
var nx = self . _cx , ny = self . _cy ;
if ( nx + w > vw - 8 ) nx = vw - w - 8 ;
if ( ny + h > vh - 8 ) ny = vh - h - 8 ;
self . x = Math . max ( 8 , nx ) ;
self . y = Math . max ( 8 , ny ) ;
} ;
if ( window . Alpine && Alpine . nextTick ) Alpine . nextTick ( place ) ;
else setTimeout ( place , 0 ) ;
this . loadRecent ( ) ;
this . loadCustom ( ) ;
} ,
close ( ) {
this . open = false ;
this . customModal = false ;
this . toneOpen = false ;
this . onPick = null ;
this . onRemove = null ;
} ,
matches ( name ) {
var q = ( this . query || '' ) . trim ( ) . toLowerCase ( ) ;
if ( ! q ) return true ;
return name . toLowerCase ( ) . indexOf ( q ) >= 0 ;
} ,
items ( ) {
var q = ( this . query || '' ) . trim ( ) . toLowerCase ( ) ;
if ( q ) {
var out = [ ] ;
this . cats . forEach ( function ( c ) {
c . items . forEach ( function ( it ) {
if ( ( it [ 1 ] || '' ) . toLowerCase ( ) . indexOf ( q ) >= 0 || it [ 0 ] . indexOf ( q ) >= 0 ) out . push ( it [ 0 ] ) ;
} ) ;
} ) ;
return out ;
}
if ( this . category === 'recent' ) return this . recent ;
var found = [ ] ;
for ( var i = 0 ; i < this . cats . length ; i ++ ) {
if ( this . cats [ i ] . id === this . category ) { found = this . cats [ i ] . items . map ( function ( it ) { return it [ 0 ] ; } ) ; break ; }
}
return found ;
} ,
withTone ( e ) {
if ( ! this . skinTone ) return e ;
if ( TONEABLE [ e ] ) return e + TONES [ this . skinTone ] ;
return e ;
} ,
pick ( v ) {
v = ( v || '' ) . trim ( ) ;
if ( ! v ) return ;
this . pushRecent ( v ) ;
var fn = this . onPick ;
if ( fn ) { try { fn ( v ) ; } catch ( e ) { console . error ( 'fdIconPicker.pick' , e ) ; } }
this . close ( ) ;
} ,
remove ( ) {
var fn = this . onRemove || this . onPick ;
if ( fn ) { try { fn ( '' ) ; } catch ( e ) { } }
this . close ( ) ;
} ,
random ( ) {
var pool = [ ] ;
this . cats . forEach ( function ( c ) { c . items . forEach ( function ( it ) { pool . push ( it [ 0 ] ) ; } ) ; } ) ;
if ( ! pool . length ) return ;
this . pick ( pool [ Math . floor ( Math . random ( ) * pool . length ) ] ) ;
} ,
setTone ( i ) { this . skinTone = i ; this . toneOpen = false ; } ,
setCategory ( id ) { this . category = id ; this . tab = 'emoji' ; this . query = '' ; } ,
setTab ( t ) { this . tab = t ; this . query = '' ; if ( t === 'upload' ) this . loadCustom ( ) ; } ,
loadRecent ( ) {
try { this . recent = JSON . parse ( localStorage . getItem ( 'fd_icon_recent' ) || '[]' ) ; }
catch ( e ) { this . recent = [ ] ; }
} ,
pushRecent ( e ) {
try {
var r = this . recent . filter ( function ( x ) { return x !== e ; } ) ;
r . unshift ( e ) ;
this . recent = r . slice ( 0 , 32 ) ;
localStorage . setItem ( 'fd_icon_recent' , JSON . stringify ( this . recent ) ) ;
} catch ( err ) { }
} ,
async loadCustom ( ) {
try {
var r = await fetch ( '/api/custom-emojis' , { credentials : 'same-origin' } ) ;
var d = await r . json ( ) ;
this . custom = ( d && d . emojis ) || [ ] ;
this . customLoaded = true ;
} catch ( e ) { this . custom = [ ] ; }
} ,
openCustomModal ( ) {
this . customModal = true ;
this . customName = '' ;
this . customPreview = '' ;
this . customFile = null ;
this . tab = 'upload' ;
} ,
closeCustomModal ( ) { this . customModal = false ; } ,
onCustomFile ( ev ) {
var f = ev . target . files && ev . target . files [ 0 ] ;
if ( ! f ) return ;
this . customFile = f ;
var self = this ;
var fr = new FileReader ( ) ;
fr . onload = function ( ) { self . customPreview = fr . result ; } ;
fr . readAsDataURL ( f ) ;
if ( ! this . customName ) this . customName = ( f . name || '' ) . replace ( /\.[^.]+$/ , '' ) . slice ( 0 , 40 ) ;
} ,
async saveCustom ( ) {
if ( ! this . customFile || this . customBusy ) return ;
this . customBusy = true ;
try {
var fd = new FormData ( ) ;
fd . append ( 'name' , this . customName || 'emoji' ) ;
fd . append ( 'file' , this . customFile ) ;
var csrf = ( document . cookie . match ( /csrf_token=([^;]+)/ ) || [ ] ) [ 1 ] || '' ;
var r = await fetch ( '/api/custom-emojis' , { method : 'POST' , headers : { 'X-CSRF-Token' : csrf } , body : fd , credentials : 'same-origin' } ) ;
var d = await r . json ( ) ;
if ( d && d . emoji ) {
this . custom . unshift ( d . emoji ) ;
this . customModal = false ;
this . pick ( d . emoji . url ) ;
}
} catch ( e ) {
if ( window . showToast ) window . showToast ( 'Emoji upload failed' , 'error' ) ;
}
this . customBusy = false ;
} ,
async deleteCustom ( id ) {
try {
var csrf = ( document . cookie . match ( /csrf_token=([^;]+)/ ) || [ ] ) [ 1 ] || '' ;
await fetch ( '/api/custom-emojis/' + id , { method : 'DELETE' , headers : { 'X-CSRF-Token' : csrf } , credentials : 'same-origin' } ) ;
this . custom = this . custom . filter ( function ( e ) { return e . id !== id ; } ) ;
} catch ( e ) { }
}
} ) ;
} ) ;
window . FDIconPicker = {
openFor : function ( opts ) {
var s = window . Alpine && Alpine . store ( 'fdIconPicker' ) ;
if ( s ) s . openFor ( opts ) ;
}
} ;
} ) ( ) ;
< / script >
< style >
. fd-icon-picker { position : fixed ; top : 0 ; left : 0 ; width : 344 px ; background : var ( - - bg - modal ) ; border : 1 px solid var ( - - border ) ; border-radius : 10 px ; box-shadow : 0 8 px 32 px rgba ( 0 , 0 , 0 , .28 ) ; z-index : 2200 ; display : flex ; flex-direction : column ; max-height : 440 px ; overflow : hidden ; padding : 0 ; }
. fd-icon-picker . fdip-tabs { display : flex ; align-items : center ; gap : 2 px ; padding : 8 px 10 px 6 px ; border-bottom : 1 px solid var ( - - border ) ; }
. fd-icon-picker . fdip-tab { background : transparent ; border : none ; color : var ( - - text - secondary ) ; font-size : 13 px ; padding : 5 px 10 px ; border-radius : 6 px ; cursor : pointer ; }
. fd-icon-picker . fdip-tab : hover { background : var ( - - bg - hover ) ; }
. fd-icon-picker . fdip-tab . active { background : var ( - - bg - hover ) ; color : var ( - - text - primary ) ; font-weight : 600 ; }
. fd-icon-picker . fdip-remove { margin-left : auto ; background : transparent ; border : none ; color : var ( - - text - secondary ) ; font-size : 12 px ; padding : 5 px 8 px ; border-radius : 6 px ; cursor : pointer ; }
. fd-icon-picker . fdip-remove : hover { background : var ( - - bg - hover ) ; color : var ( - - danger ) ; }
. fd-icon-picker . fdip-tools { display : flex ; align-items : center ; gap : 6 px ; padding : 8 px 10 px ; }
. fd-icon-picker . fdip-search { flex : 1 ; min-width : 0 ; font-size : 13 px ; padding : 6 px 10 px ; background : var ( - - bg - primary ) ; border : 1 px solid var ( - - border ) ; border-radius : 6 px ; color : var ( - - text - primary ) ; outline : none ; }
. fd-icon-picker . fdip-search : focus { border-color : var ( - - accent ) ; }
. fd-icon-picker . fdip-tool { width : 30 px ; height : 30 px ; flex-shrink : 0 ; display : flex ; align-items : center ; justify-content : center ; background : transparent ; border : 1 px solid var ( - - border ) ; border-radius : 6 px ; cursor : pointer ; font-size : 15 px ; color : var ( - - text - primary ) ; }
. fd-icon-picker . fdip-tool : hover { background : var ( - - bg - hover ) ; }
. fd-icon-picker . fdip-tone-wrap { position : relative ; }
. fd-icon-picker . fdip-tone-menu { position : absolute ; right : 0 ; top : 34 px ; display : flex ; gap : 2 px ; padding : 6 px ; background : var ( - - bg - modal ) ; border : 1 px solid var ( - - border ) ; border-radius : 8 px ; box-shadow : 0 6 px 20 px rgba ( 0 , 0 , 0 , .25 ) ; z-index : 5 ; }
. fd-icon-picker . fdip-tone { width : 26 px ; height : 26 px ; border : none ; background : transparent ; border-radius : 6 px ; cursor : pointer ; font-size : 16 px ; }
. fd-icon-picker . fdip-tone : hover , . fd-icon-picker . fdip-tone . selected { background : var ( - - bg - hover ) ; }
. fd-icon-picker . fdip-body { flex : 1 ; overflow-y : auto ; padding : 0 10 px 6 px ; }
. fd-icon-picker . fdip-section { font-size : 11 px ; text-transform : uppercase ; letter-spacing : .04 em ; color : var ( - - text - dim ) ; padding : 6 px 2 px 2 px ; }
. fd-icon-picker . fdip-grid { display : grid ; grid-template-columns : repeat ( 8 , 1 fr ) ; gap : 2 px ; }
. fd-icon-picker . fdip-emoji , . fd-icon-picker . fdip-icon { width : 100 % ; aspect-ratio : 1 ; display : flex ; align-items : center ; justify-content : center ; background : transparent ; border : none ; border-radius : 6 px ; cursor : pointer ; font-size : 21 px ; line-height : 1 ; color : var ( - - text - primary ) ; position : relative ; }
. fd-icon-picker . fdip-emoji : hover , . fd-icon-picker . fdip-icon : hover { background : var ( - - bg - hover ) ; }
. fd-icon-picker . fdip-custom img { width : 24 px ; height : 24 px ; object-fit : contain ; }
. fd-icon-picker . fdip-del { position : absolute ; top : -2 px ; right : -2 px ; width : 14 px ; height : 14 px ; border-radius : 50 % ; background : var ( - - danger ) ; color : #fff ; font-size : 10 px ; line-height : 14 px ; text-align : center ; display : none ; }
. fd-icon-picker . fdip-custom : hover . fdip-del { display : block ; }
. fd-icon-picker . fdip-empty { color : var ( - - text - dim ) ; font-size : 12 px ; text-align : center ; padding : 24 px 0 ; }
. fd-icon-picker . fdip-cats { display : flex ; align-items : center ; gap : 2 px ; padding : 6 px 10 px ; border-top : 1 px solid var ( - - border ) ; }
. fd-icon-picker . fdip-cat { flex : 1 ; height : 30 px ; display : flex ; align-items : center ; justify-content : center ; background : transparent ; border : none ; border-radius : 6 px ; cursor : pointer ; color : var ( - - text - secondary ) ; }
. fd-icon-picker . fdip-cat : hover { background : var ( - - bg - hover ) ; }
. fd-icon-picker . fdip-cat . active { background : var ( - - bg - hover ) ; color : var ( - - accent ) ; }
. fd-icon-picker . fdip-cat svg { width : 16 px ; height : 16 px ; }
. fdip-modal-overlay { position : fixed ; inset : 0 ; background : rgba ( 0 , 0 , 0 , .5 ) ; z-index : 2300 ; display : flex ; align-items : center ; justify-content : center ; }
. fdip-modal { width : 420 px ; max-width : 92 vw ; background : var ( - - bg - modal ) ; border : 1 px solid var ( - - border ) ; border-radius : 12 px ; padding : 20 px ; box-shadow : 0 16 px 48 px rgba ( 0 , 0 , 0 , .35 ) ; }
. fdip-modal-title { font-size : 16 px ; font-weight : 600 ; color : var ( - - text - primary ) ; margin-bottom : 6 px ; }
. fdip-modal-desc { font-size : 13 px ; color : var ( - - text - secondary ) ; margin-bottom : 16 px ; }
. fdip-upload-btn { display : inline-block ; padding : 8 px 14 px ; font-size : 13 px ; border : 1 px solid var ( - - border ) ; border-radius : 8 px ; cursor : pointer ; color : var ( - - text - primary ) ; background : var ( - - bg - secondary ) ; }
. fdip-upload-btn : hover { background : var ( - - bg - hover ) ; }
. fdip-preview-boxes { display : flex ; gap : 10 px ; margin : 14 px 0 ; }
. fdip-preview { width : 64 px ; height : 64 px ; border-radius : 8 px ; display : flex ; align-items : center ; justify-content : center ; border : 1 px solid var ( - - border ) ; }
. fdip-preview . dark { background : #111 ; }
. fdip-preview . light { background : #fff ; }
. fdip-preview img { max-width : 44 px ; max-height : 44 px ; object-fit : contain ; }
. fdip-modal-label { display : block ; font-size : 12 px ; color : var ( - - text - secondary ) ; margin : 8 px 0 4 px ; }
. fdip-modal-input { width : 100 % ; font-size : 14 px ; padding : 8 px 10 px ; background : var ( - - bg - primary ) ; border : 1 px solid var ( - - border ) ; border-radius : 8 px ; color : var ( - - text - primary ) ; outline : none ; box-sizing : border-box ; }
. fdip-modal-input : focus { border-color : var ( - - accent ) ; }
. fdip-modal-actions { display : flex ; justify-content : flex-end ; gap : 8 px ; margin-top : 18 px ; }
. fdip-modal-actions button { padding : 8 px 16 px ; font-size : 13 px ; border-radius : 8 px ; cursor : pointer ; border : 1 px solid var ( - - border ) ; background : var ( - - bg - secondary ) ; color : var ( - - text - primary ) ; }
. fdip-modal-actions button . primary { background : var ( - - accent ) ; border-color : var ( - - accent ) ; color : #fff ; }
. fdip-modal-actions button : disabled { opacity : .5 ; cursor : default ; }
< / style >
< div x-data >
< div class = "fd-icon-picker" x-show = "$store.fdIconPicker.open" x-cloak
@ click . outside = "$store.fdIconPicker.customModal || $store.fdIconPicker.close()"
@ keydown . escape . window = "$store.fdIconPicker.close()"
:style = "'top:' + $store.fdIconPicker.y + 'px;left:' + $store.fdIconPicker.x + 'px'" >
< div class = "fdip-tabs" >
< button class = "fdip-tab" :class = "{ active: $store.fdIconPicker.tab === 'emoji' }" @ click = "$store.fdIconPicker.setTab('emoji')" > Emoji< / button >
< button class = "fdip-tab" :class = "{ active: $store.fdIconPicker.tab === 'icons' }" @ click = "$store.fdIconPicker.setTab('icons')" > Icons< / button >
< button class = "fdip-tab" :class = "{ active: $store.fdIconPicker.tab === 'upload' }" @ click = "$store.fdIconPicker.setTab('upload')" > Upload< / button >
< button class = "fdip-remove" @ click = "$store.fdIconPicker.remove()" > Remove< / button >
< / div >
< div class = "fdip-tools" x-show = "$store.fdIconPicker.tab !== 'upload'" >
< input class = "fdip-search" placeholder = "Filter..." x-model = "$store.fdIconPicker.query" >
< button class = "fdip-tool" title = "Random" @ click = "$store.fdIconPicker.random()" > 🎲< / button >
< div class = "fdip-tone-wrap" x-show = "$store.fdIconPicker.tab === 'emoji'" >
< button class = "fdip-tool" title = "Select skin tone" @ click . stop = "$store.fdIconPicker.toneOpen = !$store.fdIconPicker.toneOpen" > 👋< / button >
< div class = "fdip-tone-menu" x-show = "$store.fdIconPicker.toneOpen" @ click . outside = "$store.fdIconPicker.toneOpen = false" >
< template x-for = "(t, ti) in ['👋','👋🏻','👋🏼','👋🏽','👋🏾','👋🏿']" :key = "ti" >
< button class = "fdip-tone" :class = "{ selected: $store.fdIconPicker.skinTone === ti }" @ click = "$store.fdIconPicker.setTone(ti)" x-text = "t" > < / button >
< / template >
< / div >
< / div >
< / div >
< div class = "fdip-body" >
< template x-if = "$store.fdIconPicker.tab === 'emoji'" >
< div >
< div class = "fdip-section" x-show = "$store.fdIconPicker.category === 'recent' && !$store.fdIconPicker.query" > Recent< / div >
< div class = "fdip-grid" >
< template x-for = "e in $store.fdIconPicker.items()" :key = "e" >
< button class = "fdip-emoji" @ click = "$store.fdIconPicker.pick($store.fdIconPicker.withTone(e))" x-text = "$store.fdIconPicker.withTone(e)" > < / button >
< / template >
< / div >
< div class = "fdip-empty" x-show = "!$store.fdIconPicker.items().length" > No emoji found< / div >
< / div >
< / template >
< template x-if = "$store.fdIconPicker.tab === 'icons'" >
< div >
< div class = "fdip-grid" >
{% for name in picker_icons %}
< button class = "fdip-icon" x-show = "$store.fdIconPicker.matches('{{ name }}')" @ click = "$store.fdIconPicker.pick('{{ name }}')" title = "{{ name }}" > {{ fd_icon(name, 20) }}< / button >
{% endfor %}
< / div >
< / div >
< / template >
< template x-if = "$store.fdIconPicker.tab === 'upload'" >
< div >
< div class = "fdip-custom-head" style = "display:flex;align-items:center;justify-content:space-between;padding:6px 2px;" >
< span class = "fdip-section" style = "padding:0;" > Custom emojis< / span >
< button class = "fdip-tool" style = "width:auto;padding:0 10px;" @ click = "$store.fdIconPicker.openCustomModal()" > + Add< / button >
< / div >
< div class = "fdip-grid" >
< template x-for = "ce in $store.fdIconPicker.custom" :key = "ce.id" >
< button class = "fdip-emoji fdip-custom" @ click = "$store.fdIconPicker.pick(ce.url)" :title = "ce.name" >
< img :src = "ce.url" :alt = "ce.name" >
< span class = "fdip-del" @ click . stop = "$store.fdIconPicker.deleteCustom(ce.id)" > × < / span >
< / button >
< / template >
< / div >
< div class = "fdip-empty" x-show = "!$store.fdIconPicker.custom.length" > No custom emoji yet< / div >
< / div >
< / template >
< / div >
< div class = "fdip-cats" x-show = "$store.fdIconPicker.tab === 'emoji'" >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'recent' }" title = "Recent" @ click = "$store.fdIconPicker.setCategory('recent')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < circle cx = "12" cy = "12" r = "9" / > < polyline points = "12 7 12 12 15 14" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'people' }" title = "People" @ click = "$store.fdIconPicker.setCategory('people')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < circle cx = "12" cy = "12" r = "9" / > < path d = "M8.5 14s1.3 2 3.5 2 3.5-2 3.5-2" / > < line x1 = "9" y1 = "9.5" x2 = "9.01" y2 = "9.5" / > < line x1 = "15" y1 = "9.5" x2 = "15.01" y2 = "9.5" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'nature' }" title = "Nature" @ click = "$store.fdIconPicker.setCategory('nature')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M11 20A7 7 0 0 1 4 13c0-6 7-10 16-10 0 9-4 16-10 16z" / > < path d = "M4 21c2-4 5-7 9-9" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'food' }" title = "Food" @ click = "$store.fdIconPicker.setCategory('food')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M3 21l6-6" / > < path d = "M14 3s5 1 7 7c-4 4-8 3-10 1s-1-6 3-8z" / > < path d = "M9 12l-4 4" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'activity' }" title = "Activity" @ click = "$store.fdIconPicker.setCategory('activity')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M6 11V6a2 2 0 0 1 4 0v5" / > < path d = "M10 11V4a2 2 0 0 1 4 0v7" / > < path d = "M14 11V6a2 2 0 0 1 4 0v9a7 7 0 0 1-7 7H9a6 6 0 0 1-6-6v-3a2 2 0 0 1 3-1.7" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'travel' }" title = "Travel" @ click = "$store.fdIconPicker.setCategory('travel')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M2 16l20-6-3-3-7 1-5-5-2 1 3 5-4 1-2-2-1 1z" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'objects' }" title = "Objects" @ click = "$store.fdIconPicker.setCategory('objects')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M9 18h6" / > < path d = "M10 22h4" / > < path d = "M12 2a6 6 0 0 0-4 10.5c.8.7 1 1.5 1 2.5h6c0-1 .2-1.8 1-2.5A6 6 0 0 0 12 2z" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'symbols' }" title = "Symbols" @ click = "$store.fdIconPicker.setCategory('symbols')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < polyline points = "9 11 12 14 22 4" / > < path d = "M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" / > < / svg > < / button >
< button class = "fdip-cat" :class = "{ active: $store.fdIconPicker.category === 'flags' }" title = "Flags" @ click = "$store.fdIconPicker.setCategory('flags')" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < path d = "M4 22V4" / > < path d = "M4 4h13l-2 4 2 4H4" / > < / svg > < / button >
< button class = "fdip-cat" title = "Add custom emoji" @ click = "$store.fdIconPicker.openCustomModal()" > < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" > < line x1 = "12" y1 = "5" x2 = "12" y2 = "19" / > < line x1 = "5" y1 = "12" x2 = "19" y2 = "12" / > < / svg > < / button >
< / div >
< / div >
< div class = "fdip-modal-overlay" x-show = "$store.fdIconPicker.customModal" x-cloak @ click . self = "$store.fdIconPicker.closeCustomModal()" >
< div class = "fdip-modal" >
< div class = "fdip-modal-title" > Add custom emoji< / div >
< div class = "fdip-modal-desc" > Custom emoji can be used by anyone in your workspace.< / div >
< label class = "fdip-upload-btn" >
< span x-show = "!$store.fdIconPicker.customPreview" > Upload an image< / span >
< span x-show = "$store.fdIconPicker.customPreview" > Replace< / span >
< input type = "file" accept = "image/*" @ change = "$store.fdIconPicker.onCustomFile($event)" style = "display:none" >
< / label >
< div class = "fdip-preview-boxes" x-show = "$store.fdIconPicker.customPreview" >
< div class = "fdip-preview dark" > < img :src = "$store.fdIconPicker.customPreview" alt = "" > < / div >
< div class = "fdip-preview light" > < img :src = "$store.fdIconPicker.customPreview" alt = "" > < / div >
< / div >
< label class = "fdip-modal-label" > Emoji name< / label >
< input class = "fdip-modal-input" x-model = "$store.fdIconPicker.customName" placeholder = "pushup" >
< div class = "fdip-modal-actions" >
< button @ click = "$store.fdIconPicker.closeCustomModal()" > Cancel< / button >
< button class = "primary" :disabled = "$store.fdIconPicker.customBusy || !$store.fdIconPicker.customFile" @ click = "$store.fdIconPicker.saveCustom()" > Save< / button >
< / div >
< / div >
< / div >
< / div >