(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
99
fork

Configure Feed

Select the types of activity you want to include in your feed.

emoji picker for collections

scanash00 5345691c 35352b49

+332 -65
+5
web/bun.lock
··· 13 13 "autoprefixer": "^10.4.24", 14 14 "clsx": "^2.1.1", 15 15 "date-fns": "^4.1.0", 16 + "emoji-picker-react": "^4.18.0", 16 17 "lucide-react": "^0.563.0", 17 18 "nanostores": "^1.1.0", 18 19 "postcss": "^8.5.6", ··· 593 594 594 595 "electron-to-chromium": ["electron-to-chromium@1.5.286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="], 595 596 597 + "emoji-picker-react": ["emoji-picker-react@4.18.0", "", { "dependencies": { "flairup": "1.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-vLTrLfApXAIciguGE57pXPWs9lPLBspbEpPMiUq03TIli2dHZBiB+aZ0R9/Wat0xmTfcd4AuEzQgSYxEZ8C88Q=="], 598 + 596 599 "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], 597 600 598 601 "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], ··· 680 683 "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 681 684 682 685 "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 686 + 687 + "flairup": ["flairup@1.0.0", "", {}, "sha512-IKlE+pNvL2R+kVL1kEhUYqRxVqeFnjiIvHWDMLFXNaqyUdFXQM2wte44EfMYJNHkW16X991t2Zg8apKkhv7OBA=="], 683 688 684 689 "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 685 690
+1
web/package.json
··· 19 19 "autoprefixer": "^10.4.24", 20 20 "clsx": "^2.1.1", 21 21 "date-fns": "^4.1.0", 22 + "emoji-picker-react": "^4.18.0", 22 23 "lucide-react": "^0.563.0", 23 24 "nanostores": "^1.1.0", 24 25 "postcss": "^8.5.6",
+86 -22
web/src/components/modals/AddToCollectionModal.tsx
··· 9 9 } from "lucide-react"; 10 10 import CollectionIcon from "../common/CollectionIcon"; 11 11 import { ICON_MAP } from "../common/iconMap"; 12 + import EmojiPicker, { Theme } from "emoji-picker-react"; 12 13 import { useStore } from "@nanostores/react"; 13 14 import { $user } from "../../store/auth"; 15 + import { $theme } from "../../store/theme"; 14 16 import { 15 17 getCollections, 16 18 addCollectionItem, ··· 31 33 annotationUri, 32 34 }: AddToCollectionModalProps) { 33 35 const user = useStore($user); 36 + const theme = useStore($theme); 34 37 const [collections, setCollections] = useState<Collection[]>([]); 35 38 const [loading, setLoading] = useState(true); 36 39 const [addingTo, setAddingTo] = useState<string | null>(null); ··· 41 44 const [newName, setNewName] = useState(""); 42 45 const [newDescription, setNewDescription] = useState(""); 43 46 const [newIcon, setNewIcon] = useState(""); 47 + const [activeTab, setActiveTab] = useState<"icon" | "emoji">("icon"); 44 48 const [creating, setCreating] = useState(false); 45 49 46 50 useEffect(() => { ··· 96 100 if (!newName.trim()) return; 97 101 try { 98 102 setCreating(true); 99 - const iconValue = newIcon ? `icon:${newIcon}` : undefined; 103 + const iconValue = newIcon 104 + ? ICON_MAP[newIcon] 105 + ? `icon:${newIcon}` 106 + : newIcon 107 + : undefined; 100 108 const newCollection = await createCollection( 101 109 newName.trim(), 102 110 newDescription.trim() || undefined, ··· 184 192 <label className="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-2"> 185 193 Icon 186 194 </label> 187 - <div className="grid grid-cols-8 gap-1.5 max-h-32 overflow-y-auto p-2 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700"> 188 - {Object.keys(ICON_MAP).map((iconName) => { 189 - const isSelected = newIcon === iconName; 190 - return ( 191 - <button 192 - key={iconName} 193 - type="button" 194 - onClick={() => setNewIcon(isSelected ? "" : iconName)} 195 - className={`w-8 h-8 flex items-center justify-center rounded-lg transition-all ${ 196 - isSelected 197 - ? "bg-primary-600 text-white" 198 - : "hover:bg-surface-200 dark:hover:bg-surface-700 text-surface-600 dark:text-surface-400" 199 - }`} 200 - title={iconName} 201 - > 202 - <CollectionIcon icon={`icon:${iconName}`} size={16} /> 203 - </button> 204 - ); 205 - })} 195 + 196 + <div className="flex gap-2 mb-3 bg-surface-100 dark:bg-surface-800 p-1 rounded-xl"> 197 + <button 198 + type="button" 199 + onClick={() => setActiveTab("icon")} 200 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 201 + activeTab === "icon" 202 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 203 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 204 + }`} 205 + > 206 + Icons 207 + </button> 208 + <button 209 + type="button" 210 + onClick={() => setActiveTab("emoji")} 211 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 212 + activeTab === "emoji" 213 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 214 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 215 + }`} 216 + > 217 + Emojis 218 + </button> 206 219 </div> 220 + 221 + {activeTab === "icon" ? ( 222 + <div className="grid grid-cols-8 gap-1.5 max-h-60 overflow-y-auto p-2 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 custom-scrollbar"> 223 + {Object.keys(ICON_MAP).map((iconName) => { 224 + const isSelected = newIcon === iconName; 225 + return ( 226 + <button 227 + key={iconName} 228 + type="button" 229 + onClick={() => setNewIcon(isSelected ? "" : iconName)} 230 + className={`w-8 h-8 flex items-center justify-center rounded-lg transition-all ${ 231 + isSelected 232 + ? "bg-primary-600 text-white" 233 + : "hover:bg-surface-200 dark:hover:bg-surface-700 text-surface-600 dark:text-surface-400" 234 + }`} 235 + title={iconName} 236 + > 237 + <CollectionIcon icon={`icon:${iconName}`} size={16} /> 238 + </button> 239 + ); 240 + })} 241 + </div> 242 + ) : ( 243 + <div className="w-full bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden"> 244 + <EmojiPicker 245 + className="custom-emoji-picker" 246 + onEmojiClick={(emojiData) => setNewIcon(emojiData.emoji)} 247 + autoFocusSearch={false} 248 + width="100%" 249 + height={300} 250 + previewConfig={{ showPreview: false }} 251 + skinTonesDisabled 252 + lazyLoadEmojis 253 + theme={ 254 + theme === "dark" || 255 + (theme === "system" && 256 + window.matchMedia("(prefers-color-scheme: dark)") 257 + .matches) 258 + ? (Theme.DARK as Theme) 259 + : (Theme.LIGHT as Theme) 260 + } 261 + /> 262 + </div> 263 + )} 264 + 207 265 {newIcon && ( 208 - <p className="mt-1 text-xs text-surface-500"> 209 - Selected: {newIcon} 266 + <p className="mt-2 text-sm text-surface-600 dark:text-surface-300 flex items-center gap-2"> 267 + Selected: 268 + <span className="inline-flex items-center justify-center w-8 h-8 bg-surface-100 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> 269 + <CollectionIcon 270 + icon={ICON_MAP[newIcon] ? `icon:${newIcon}` : newIcon} 271 + size={18} 272 + /> 273 + </span> 210 274 </p> 211 275 )} 212 276 </div>
+97 -23
web/src/components/modals/EditCollectionModal.tsx
··· 2 2 import { X, Loader2 } from "lucide-react"; 3 3 import CollectionIcon from "../common/CollectionIcon"; 4 4 import { ICON_MAP } from "../common/iconMap"; 5 + import EmojiPicker, { Theme } from "emoji-picker-react"; 5 6 import { updateCollection, type Collection } from "../../api/client"; 7 + import { useStore } from "@nanostores/react"; 8 + import { $theme } from "../../store/theme"; 6 9 7 10 interface EditCollectionModalProps { 8 11 isOpen: boolean; ··· 19 22 }: EditCollectionModalProps) { 20 23 const [name, setName] = useState(collection.name); 21 24 const [description, setDescription] = useState(collection.description || ""); 22 - const [icon, setIcon] = useState(collection.icon?.replace("icon:", "") || ""); 25 + const initialIsIcon = collection.icon?.startsWith("icon:") ?? false; 26 + const initialIconValue = collection.icon?.replace("icon:", "") || ""; 27 + 28 + const [activeTab, setActiveTab] = useState<"icon" | "emoji">( 29 + initialIsIcon || !collection.icon ? "icon" : "emoji", 30 + ); 31 + const [icon, setIcon] = useState(initialIconValue); 23 32 const [loading, setLoading] = useState(false); 24 33 const [error, setError] = useState<string | null>(null); 34 + const theme = useStore($theme); 25 35 26 36 useEffect(() => { 27 37 if (isOpen) { 28 38 setName(collection.name); 29 39 setDescription(collection.description || ""); 40 + 41 + const isIcon = collection.icon?.startsWith("icon:") ?? false; 42 + setActiveTab(isIcon || !collection.icon ? "icon" : "emoji"); 30 43 setIcon(collection.icon?.replace("icon:", "") || ""); 44 + 31 45 setError(null); 32 46 document.body.style.overflow = "hidden"; 33 47 } ··· 43 57 try { 44 58 setLoading(true); 45 59 setError(null); 46 - const iconValue = icon ? `icon:${icon}` : undefined; 60 + const iconValue = icon 61 + ? ICON_MAP[icon] 62 + ? `icon:${icon}` 63 + : icon 64 + : undefined; 47 65 const updated = await updateCollection( 48 66 collection.uri, 49 67 name.trim(), ··· 121 139 <label className="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-2"> 122 140 Icon 123 141 </label> 124 - <div className="grid grid-cols-8 gap-1.5 max-h-32 overflow-y-auto p-2 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700"> 125 - {Object.keys(ICON_MAP).map((iconName) => { 126 - const isSelected = icon === iconName; 127 - return ( 128 - <button 129 - key={iconName} 130 - type="button" 131 - onClick={() => setIcon(isSelected ? "" : iconName)} 132 - className={`w-8 h-8 flex items-center justify-center rounded-lg transition-all ${ 133 - isSelected 134 - ? "bg-primary-600 text-white" 135 - : "hover:bg-surface-200 dark:hover:bg-surface-700 text-surface-600 dark:text-surface-400" 136 - }`} 137 - title={iconName} 138 - > 139 - <CollectionIcon icon={`icon:${iconName}`} size={16} /> 140 - </button> 141 - ); 142 - })} 142 + 143 + <div className="flex gap-2 mb-3 bg-surface-100 dark:bg-surface-800 p-1 rounded-xl"> 144 + <button 145 + type="button" 146 + onClick={() => setActiveTab("icon")} 147 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 148 + activeTab === "icon" 149 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 150 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 151 + }`} 152 + > 153 + Icons 154 + </button> 155 + <button 156 + type="button" 157 + onClick={() => setActiveTab("emoji")} 158 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 159 + activeTab === "emoji" 160 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 161 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 162 + }`} 163 + > 164 + Emojis 165 + </button> 143 166 </div> 167 + 168 + {activeTab === "icon" ? ( 169 + <div className="grid grid-cols-8 gap-1.5 max-h-60 overflow-y-auto p-2 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 custom-scrollbar"> 170 + {Object.keys(ICON_MAP).map((iconName) => { 171 + const isSelected = icon === iconName; 172 + return ( 173 + <button 174 + key={iconName} 175 + type="button" 176 + onClick={() => setIcon(isSelected ? "" : iconName)} 177 + className={`w-8 h-8 flex items-center justify-center rounded-lg transition-all ${ 178 + isSelected 179 + ? "bg-primary-600 text-white" 180 + : "hover:bg-surface-200 dark:hover:bg-surface-700 text-surface-600 dark:text-surface-400" 181 + }`} 182 + title={iconName} 183 + > 184 + <CollectionIcon icon={`icon:${iconName}`} size={16} /> 185 + </button> 186 + ); 187 + })} 188 + </div> 189 + ) : ( 190 + <div className="w-full bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden"> 191 + <EmojiPicker 192 + className="custom-emoji-picker" 193 + onEmojiClick={(emojiData) => setIcon(emojiData.emoji)} 194 + autoFocusSearch={false} 195 + width="100%" 196 + height={300} 197 + previewConfig={{ showPreview: false }} 198 + skinTonesDisabled 199 + lazyLoadEmojis 200 + theme={ 201 + theme === "dark" || 202 + (theme === "system" && 203 + window.matchMedia("(prefers-color-scheme: dark)") 204 + .matches) 205 + ? (Theme.DARK as Theme) 206 + : (Theme.LIGHT as Theme) 207 + } 208 + /> 209 + </div> 210 + )} 211 + 144 212 {icon && ( 145 - <p className="mt-1 text-xs text-surface-500"> 146 - Selected: {icon} 213 + <p className="mt-2 text-sm text-surface-600 dark:text-surface-300 flex items-center gap-2"> 214 + Selected: 215 + <span className="inline-flex items-center justify-center w-8 h-8 bg-surface-100 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> 216 + <CollectionIcon 217 + icon={ICON_MAP[icon] ? `icon:${icon}` : icon} 218 + size={18} 219 + /> 220 + </span> 147 221 </p> 148 222 )} 149 223 </div>
+63
web/src/styles/global.css
··· 71 71 .custom-scrollbar::-webkit-scrollbar-thumb { 72 72 @apply bg-surface-300 dark:bg-surface-700 rounded-full hover:bg-surface-400 dark:hover:bg-surface-600 transition-colors; 73 73 } 74 + 75 + .custom-emoji-picker { 76 + --epr-bg-color: transparent !important; 77 + --epr-category-label-bg-color: transparent !important; 78 + --epr-text-color: theme("colors.surface.900") !important; 79 + --epr-picker-border-color: theme("colors.surface.200") !important; 80 + 81 + --epr-search-input-bg-color: theme("colors.surface.50") !important; 82 + --epr-search-input-text-color: theme("colors.surface.900") !important; 83 + 84 + --epr-hover-bg-color: theme("colors.surface.200") !important; 85 + --epr-focus-bg-color: theme("colors.primary.100") !important; 86 + --epr-highlight-color: theme("colors.primary.500") !important; 87 + 88 + font-family: inherit !important; 89 + border: none !important; 90 + } 91 + 92 + [data-theme="dark"] .custom-emoji-picker { 93 + --epr-text-color: theme("colors.white") !important; 94 + --epr-picker-border-color: theme("colors.surface.700") !important; 95 + 96 + --epr-search-input-bg-color: theme("colors.surface.800") !important; 97 + --epr-search-input-text-color: theme("colors.white") !important; 98 + 99 + --epr-hover-bg-color: theme("colors.surface.700") !important; 100 + --epr-focus-bg-color: theme("colors.primary.900") !important; 101 + } 102 + 103 + .custom-emoji-picker .epr-search-container input { 104 + border-radius: 0.5rem !important; 105 + border: 1px solid theme("colors.surface.200") !important; 106 + background-color: theme("colors.surface.50") !important; 107 + } 108 + 109 + [data-theme="dark"] .custom-emoji-picker .epr-search-container input { 110 + border: 1px solid theme("colors.surface.700") !important; 111 + background-color: theme("colors.surface.800") !important; 112 + } 113 + 114 + .custom-emoji-picker .epr-header-overlay { 115 + padding: 0 !important; 116 + } 117 + 118 + .custom-emoji-picker .epr-emoji-category-label { 119 + position: static !important; 120 + background-color: transparent !important; 121 + height: 32px !important; 122 + line-height: 32px !important; 123 + } 124 + 125 + .custom-emoji-picker .epr-body::-webkit-scrollbar { 126 + width: 6px; 127 + height: 6px; 128 + } 129 + 130 + .custom-emoji-picker .epr-body::-webkit-scrollbar-track { 131 + @apply bg-transparent; 132 + } 133 + 134 + .custom-emoji-picker .epr-body::-webkit-scrollbar-thumb { 135 + @apply bg-surface-300 dark:bg-surface-700 rounded-full hover:bg-surface-400 dark:hover:bg-surface-600 transition-colors; 136 + } 74 137 } 75 138 76 139 @keyframes fadeIn {
+80 -20
web/src/views/collections/Collections.tsx
··· 9 9 import { ICON_MAP } from "../../components/common/iconMap"; 10 10 import { useStore } from "@nanostores/react"; 11 11 import { $user } from "../../store/auth"; 12 + import EmojiPicker, { Theme } from "emoji-picker-react"; 13 + import { $theme } from "../../store/theme"; 12 14 import type { Collection } from "../../types"; 13 15 import { formatDistanceToNow } from "date-fns"; 14 16 import { clsx } from "clsx"; ··· 16 18 17 19 export default function Collections() { 18 20 const user = useStore($user); 21 + const theme = useStore($theme); 19 22 const [collections, setCollections] = useState<Collection[]>([]); 20 23 const [loading, setLoading] = useState(true); 21 24 const [showCreateModal, setShowCreateModal] = useState(false); 22 25 const [newItemName, setNewItemName] = useState(""); 23 26 const [newItemDesc, setNewItemDesc] = useState(""); 24 27 const [newItemIcon, setNewItemIcon] = useState("folder"); 28 + const [activeTab, setActiveTab] = useState<"icon" | "emoji">("icon"); 25 29 const [creating, setCreating] = useState(false); 26 30 27 31 const fetchCollections = async () => { ··· 45 49 if (!newItemName.trim()) return; 46 50 47 51 setCreating(true); 48 - const res = await createCollection(newItemName, newItemDesc); 52 + const finalIcon = ICON_MAP[newItemIcon] 53 + ? `icon:${newItemIcon}` 54 + : newItemIcon; 55 + 56 + const res = await createCollection(newItemName, newItemDesc, finalIcon); 49 57 if (res) { 50 58 setCollections([res, ...collections]); 51 59 setShowCreateModal(false); 52 60 setNewItemName(""); 53 61 setNewItemDesc(""); 54 62 setNewItemIcon("folder"); 63 + setActiveTab("icon"); 55 64 fetchCollections(); 56 65 } 57 66 setCreating(false); ··· 187 196 <label className="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-2"> 188 197 Icon 189 198 </label> 190 - <div className="grid grid-cols-7 gap-1.5 p-3 bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-xl max-h-28 overflow-y-auto"> 191 - {Object.keys(ICON_MAP).map((key) => { 192 - const Icon = ICON_MAP[key]; 193 - return ( 194 - <button 195 - key={key} 196 - type="button" 197 - onClick={() => setNewItemIcon(key)} 198 - className={clsx( 199 - "p-2 rounded-lg flex items-center justify-center transition-all", 200 - newItemIcon === key 201 - ? "bg-primary-100 dark:bg-primary-900/50 text-primary-600 dark:text-primary-400 ring-2 ring-primary-500" 202 - : "hover:bg-surface-100 dark:hover:bg-surface-700 text-surface-500 dark:text-surface-400", 203 - )} 204 - > 205 - <Icon size={18} /> 206 - </button> 207 - ); 208 - })} 199 + 200 + <div className="flex gap-2 mb-3 bg-surface-100 dark:bg-surface-800 p-1 rounded-xl"> 201 + <button 202 + type="button" 203 + onClick={() => setActiveTab("icon")} 204 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 205 + activeTab === "icon" 206 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 207 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 208 + }`} 209 + > 210 + Icons 211 + </button> 212 + <button 213 + type="button" 214 + onClick={() => setActiveTab("emoji")} 215 + className={`flex-1 py-1.5 text-sm font-medium rounded-lg transition-colors ${ 216 + activeTab === "emoji" 217 + ? "bg-white dark:bg-surface-700 text-surface-900 dark:text-white shadow-sm" 218 + : "text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-200" 219 + }`} 220 + > 221 + Emojis 222 + </button> 209 223 </div> 224 + 225 + {activeTab === "icon" ? ( 226 + <div className="grid grid-cols-7 gap-1.5 p-3 bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-xl max-h-48 overflow-y-auto custom-scrollbar"> 227 + {Object.keys(ICON_MAP).map((key) => { 228 + const Icon = ICON_MAP[key]; 229 + return ( 230 + <button 231 + key={key} 232 + type="button" 233 + onClick={() => setNewItemIcon(key)} 234 + className={clsx( 235 + "p-2 rounded-lg flex items-center justify-center transition-all", 236 + newItemIcon === key 237 + ? "bg-primary-100 dark:bg-primary-900/50 text-primary-600 dark:text-primary-400 ring-2 ring-primary-500" 238 + : "hover:bg-surface-100 dark:hover:bg-surface-700 text-surface-500 dark:text-surface-400", 239 + )} 240 + > 241 + <Icon size={18} /> 242 + </button> 243 + ); 244 + })} 245 + </div> 246 + ) : ( 247 + <div className="w-full bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden"> 248 + <EmojiPicker 249 + className="custom-emoji-picker" 250 + onEmojiClick={(emojiData) => 251 + setNewItemIcon(emojiData.emoji) 252 + } 253 + autoFocusSearch={false} 254 + width="100%" 255 + height={300} 256 + previewConfig={{ showPreview: false }} 257 + skinTonesDisabled 258 + lazyLoadEmojis 259 + theme={ 260 + theme === "dark" || 261 + (theme === "system" && 262 + window.matchMedia("(prefers-color-scheme: dark)") 263 + .matches) 264 + ? (Theme.DARK as Theme) 265 + : (Theme.LIGHT as Theme) 266 + } 267 + /> 268 + </div> 269 + )} 210 270 </div> 211 271 <div className="mb-6"> 212 272 <label className="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-2">