feat: improved icon picker with search, FontAwesome and MDI icons
Replace the small grid of ~45 icons with a searchable IconPicker component featuring ~250 icons from FontAwesome and Material Design Icons. Includes keyword search, library tabs (All/FA/MDI), and categories covering tech, home, sports, food, nature, finance, health, and more. v1.58.0
This commit is contained in:
parent
7e11b261a3
commit
9093149f5e
24
package-lock.json
generated
24
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.56.0",
|
||||
"version": "1.57.16",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.56.0",
|
||||
"version": "1.57.16",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.11.1",
|
||||
@ -14,6 +14,8 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^7.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
||||
"@fortawesome/react-fontawesome": "^3.2.0",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@notionhq/client": "^5.14.0",
|
||||
"@prisma/client": "5.22.0",
|
||||
@ -2039,6 +2041,21 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@mdi/js": {
|
||||
"version": "7.4.47",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz",
|
||||
"integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@mdi/react": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/react/-/react-1.6.1.tgz",
|
||||
"integrity": "sha512-4qZeDcluDFGFTWkHs86VOlHkm6gnKaMql13/gpIcUQ8kzxHgpj31NuCkD8abECVfbULJ3shc7Yt4HJ6Wu6SN4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||
@ -9554,7 +9571,6 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@ -10442,7 +10458,6 @@
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
@ -10454,7 +10469,6 @@
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prosemirror-changeset": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.57.16",
|
||||
"version": "1.58.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@ -26,6 +26,8 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^7.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
||||
"@fortawesome/react-fontawesome": "^3.2.0",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@notionhq/client": "^5.14.0",
|
||||
"@prisma/client": "5.22.0",
|
||||
|
||||
515
src/components/IconPicker.tsx
Normal file
515
src/components/IconPicker.tsx
Normal file
@ -0,0 +1,515 @@
|
||||
import React, { useState, useRef, useEffect, useMemo } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faFolder, faBriefcase, faBullseye, faRocket, faStar, faLightbulb,
|
||||
faFire, faPalette, faMusic, faMobileScreen, faLaptop, faGlobe,
|
||||
faHouse, faBuilding, faChartBar, faChartLine, faWrench, faBolt,
|
||||
faGamepad, faPen, faBook, faGraduationCap, faFlask, faMicroscope,
|
||||
faDumbbell, faUtensils, faPlane, faLeaf, faHeart, faCartShopping,
|
||||
faCoins, faGift, faCamera, faFilm, faBroom, faPaw, faEarthAmericas,
|
||||
faLock, faCheck, faCode, faCube, faUsers, faCar, faMountain,
|
||||
faUmbrella, faClock, faTag, faPhone, faEnvelope, faPrint,
|
||||
faDatabase, faServer, faCloud, faWifi, faBug, faShield,
|
||||
faBell, faBookmark, faCalendar, faCircleCheck, faCircleXmark,
|
||||
faComment, faCompass, faCreditCard, faCrown, faDiamond,
|
||||
faDisplay, faDownload, faDroplet, faEye, faFaceSmile,
|
||||
faFile, faFileCode, faFilter, faFingerprint, faFlag,
|
||||
faGear, faGlasses, faHandshake, faHashtag, faHeadphones,
|
||||
faHospital, faImage, faInbox, faInfinity, faKey,
|
||||
faLanguage, faLayerGroup, faLink, faListCheck, faMagnet,
|
||||
faMap, faMapPin, faMedal, faMessage, faMicrophone,
|
||||
faMoon, faNewspaper, faPaperPlane, faPaperclip, faPaste,
|
||||
faPeace, faPercent, faPersonRunning, faPiggyBank, faPills,
|
||||
faPuzzlePiece, faQrcode, faQuoteLeft, faRobot, faRotate,
|
||||
faRoute, faRuler, faScissors, faScrewdriverWrench, faSeedling,
|
||||
faShare, faShirt, faShop, faSignal, faSitemap,
|
||||
faSliders, faSnowflake, faSpa, faSquareCheck, faStethoscope,
|
||||
faSun, faTableCells, faTerminal, faThumbsUp, faToolbox,
|
||||
faTrashCan, faTrophy, faTruck, faTv, faUpload,
|
||||
faUserGear, faVault, faVideo, faVolumeHigh, faWallet,
|
||||
faWandMagicSparkles, faWarehouse, faWeight, faWindowMaximize,
|
||||
IconDefinition,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import Icon from "@mdi/react";
|
||||
import {
|
||||
mdiHomeAssistant, mdiDocker, mdiGithub, mdiGitlab, mdiLinux, mdiApple,
|
||||
mdiMicrosoftWindows, mdiAndroid, mdiReact, mdiNodejs, mdiLanguagePython,
|
||||
mdiLanguageJavascript, mdiLanguageTypescript, mdiLanguageHtml5, mdiLanguageCss3,
|
||||
mdiAws, mdiGoogleCloud, mdiMicrosoftAzure, mdiKubernetes, mdiTerraform,
|
||||
mdiRaspberryPi, mdiNas, mdiRouter, mdiIpNetwork, mdiServerNetwork,
|
||||
mdiBabyCarriage, mdiDog, mdiCat, mdiFish, mdiBird,
|
||||
mdiFlower, mdiTree, mdiForest, mdiWeatherSunny, mdiWeatherRainy,
|
||||
mdiBicycle, mdiMotorbike, mdiTrain, mdiBus, mdiAirplane,
|
||||
mdiSailBoat, mdiSwim, mdiSki, mdiSoccer, mdiBasketball,
|
||||
mdiTennis, mdiGolf, mdiYoga, mdiMeditation, mdiRunFast,
|
||||
mdiFood, mdiFoodApple, mdiCoffee, mdiBeer, mdiGlassCocktail,
|
||||
mdiPizza, mdiCupcake, mdiIceCream, mdiGrill, mdiFridge,
|
||||
mdiWashingMachine, mdiVacuum, mdiSofa, mdiBed, mdiBathtub,
|
||||
mdiToilet, mdiLamp, mdiCeilingFan, mdiThermometer, mdiFireplace,
|
||||
mdiBriefcase, mdiCash, mdiCurrencyEur, mdiCurrencyUsd, mdiCurrencyBtc,
|
||||
mdiChartLine, mdiChartPie, mdiChartBar, mdiTrendingUp, mdiBank,
|
||||
mdiSchool, mdiBookOpenVariant, mdiNotebook, mdiPencil, mdiPaletteOutline,
|
||||
mdiMusic, mdiMovieOpen, mdiTelevision, mdiGamepadVariant, mdiPuzzle,
|
||||
mdiCamera, mdiMicrophone, mdiHeadphones, mdiSpeaker, mdiPrinter3d,
|
||||
mdiHeart, mdiHandHeart, mdiHumanMaleFemaleChild, mdiAccountGroup, mdiPartyPopper,
|
||||
mdiGift, mdiBalloon, mdiCake, mdiRing, mdiEmoticonHappy,
|
||||
mdiMedicalBag, mdiHospitalBox, mdiPill, mdiStethoscope, mdiTooth,
|
||||
mdiSecurity, mdiShieldCheck, mdiLock, mdiEyeOff, mdiVpn,
|
||||
mdiTools, mdiHammer, mdiHandSaw, mdiScrewdriver, mdiWrench,
|
||||
mdiRecycle, mdiLeaf, mdiSprout, mdiEarth, mdiWaterOutline,
|
||||
mdiRocket, mdiBrain, mdiAtom, mdiDna, mdiMagnet,
|
||||
mdiCellphone, mdiTablet, mdiLaptop, mdiDesktopClassic, mdiWatch,
|
||||
} from "@mdi/js";
|
||||
|
||||
// --- Icon Registry ---
|
||||
|
||||
interface IconEntry {
|
||||
name: string;
|
||||
keywords: string[];
|
||||
type: "fa" | "mdi";
|
||||
icon: IconDefinition | string; // FA IconDefinition or MDI path string
|
||||
}
|
||||
|
||||
const faIcons: IconEntry[] = [
|
||||
{ name: "folder", keywords: ["folder", "file", "directory", "project"], type: "fa", icon: faFolder },
|
||||
{ name: "briefcase", keywords: ["briefcase", "work", "business", "job", "office"], type: "fa", icon: faBriefcase },
|
||||
{ name: "bullseye", keywords: ["bullseye", "target", "goal", "aim"], type: "fa", icon: faBullseye },
|
||||
{ name: "rocket", keywords: ["rocket", "launch", "startup", "space", "fast"], type: "fa", icon: faRocket },
|
||||
{ name: "star", keywords: ["star", "favorite", "rating", "important"], type: "fa", icon: faStar },
|
||||
{ name: "lightbulb", keywords: ["lightbulb", "idea", "innovation", "think"], type: "fa", icon: faLightbulb },
|
||||
{ name: "fire", keywords: ["fire", "hot", "trending", "flame", "urgent"], type: "fa", icon: faFire },
|
||||
{ name: "palette", keywords: ["palette", "art", "design", "color", "paint", "creative"], type: "fa", icon: faPalette },
|
||||
{ name: "music", keywords: ["music", "audio", "song", "sound", "note"], type: "fa", icon: faMusic },
|
||||
{ name: "mobile", keywords: ["mobile", "phone", "smartphone", "cell"], type: "fa", icon: faMobileScreen },
|
||||
{ name: "laptop", keywords: ["laptop", "computer", "pc", "notebook"], type: "fa", icon: faLaptop },
|
||||
{ name: "globe", keywords: ["globe", "world", "web", "internet", "global"], type: "fa", icon: faGlobe },
|
||||
{ name: "house", keywords: ["house", "home", "residence", "living"], type: "fa", icon: faHouse },
|
||||
{ name: "building", keywords: ["building", "office", "company", "corporate", "city"], type: "fa", icon: faBuilding },
|
||||
{ name: "chart-bar", keywords: ["chart", "bar", "statistics", "analytics", "graph", "data"], type: "fa", icon: faChartBar },
|
||||
{ name: "chart-line", keywords: ["chart", "line", "statistics", "analytics", "trend", "growth"], type: "fa", icon: faChartLine },
|
||||
{ name: "wrench", keywords: ["wrench", "tool", "repair", "fix", "maintenance"], type: "fa", icon: faWrench },
|
||||
{ name: "bolt", keywords: ["bolt", "lightning", "power", "energy", "electric", "fast"], type: "fa", icon: faBolt },
|
||||
{ name: "gamepad", keywords: ["gamepad", "game", "gaming", "play", "controller"], type: "fa", icon: faGamepad },
|
||||
{ name: "pen", keywords: ["pen", "write", "edit", "draw"], type: "fa", icon: faPen },
|
||||
{ name: "book", keywords: ["book", "read", "library", "study", "education"], type: "fa", icon: faBook },
|
||||
{ name: "graduation-cap", keywords: ["graduation", "education", "school", "university", "degree", "study"], type: "fa", icon: faGraduationCap },
|
||||
{ name: "flask", keywords: ["flask", "science", "chemistry", "lab", "experiment"], type: "fa", icon: faFlask },
|
||||
{ name: "microscope", keywords: ["microscope", "science", "research", "biology", "lab"], type: "fa", icon: faMicroscope },
|
||||
{ name: "dumbbell", keywords: ["dumbbell", "gym", "fitness", "exercise", "workout", "sport"], type: "fa", icon: faDumbbell },
|
||||
{ name: "utensils", keywords: ["utensils", "food", "restaurant", "eat", "dining", "cook"], type: "fa", icon: faUtensils },
|
||||
{ name: "plane", keywords: ["plane", "flight", "travel", "airport", "vacation"], type: "fa", icon: faPlane },
|
||||
{ name: "leaf", keywords: ["leaf", "nature", "plant", "eco", "green", "organic"], type: "fa", icon: faLeaf },
|
||||
{ name: "heart", keywords: ["heart", "love", "health", "favorite", "like"], type: "fa", icon: faHeart },
|
||||
{ name: "cart-shopping", keywords: ["cart", "shopping", "buy", "store", "ecommerce"], type: "fa", icon: faCartShopping },
|
||||
{ name: "coins", keywords: ["coins", "money", "finance", "currency", "savings"], type: "fa", icon: faCoins },
|
||||
{ name: "gift", keywords: ["gift", "present", "birthday", "surprise"], type: "fa", icon: faGift },
|
||||
{ name: "camera", keywords: ["camera", "photo", "photography", "picture", "image"], type: "fa", icon: faCamera },
|
||||
{ name: "film", keywords: ["film", "movie", "cinema", "video"], type: "fa", icon: faFilm },
|
||||
{ name: "broom", keywords: ["broom", "clean", "sweep", "housework", "tidy"], type: "fa", icon: faBroom },
|
||||
{ name: "paw", keywords: ["paw", "pet", "animal", "dog", "cat"], type: "fa", icon: faPaw },
|
||||
{ name: "earth", keywords: ["earth", "world", "planet", "global", "environment"], type: "fa", icon: faEarthAmericas },
|
||||
{ name: "lock", keywords: ["lock", "security", "password", "private", "safe"], type: "fa", icon: faLock },
|
||||
{ name: "check", keywords: ["check", "done", "complete", "tick", "approve"], type: "fa", icon: faCheck },
|
||||
{ name: "code", keywords: ["code", "programming", "developer", "software", "coding"], type: "fa", icon: faCode },
|
||||
{ name: "cube", keywords: ["cube", "3d", "block", "box", "package"], type: "fa", icon: faCube },
|
||||
{ name: "users", keywords: ["users", "team", "group", "people", "community"], type: "fa", icon: faUsers },
|
||||
{ name: "car", keywords: ["car", "vehicle", "drive", "auto", "transport"], type: "fa", icon: faCar },
|
||||
{ name: "mountain", keywords: ["mountain", "hiking", "outdoor", "adventure", "nature"], type: "fa", icon: faMountain },
|
||||
{ name: "umbrella", keywords: ["umbrella", "rain", "weather", "protection"], type: "fa", icon: faUmbrella },
|
||||
{ name: "clock", keywords: ["clock", "time", "schedule", "timer", "watch"], type: "fa", icon: faClock },
|
||||
{ name: "tag", keywords: ["tag", "label", "category", "price"], type: "fa", icon: faTag },
|
||||
{ name: "phone", keywords: ["phone", "call", "telephone", "contact"], type: "fa", icon: faPhone },
|
||||
{ name: "envelope", keywords: ["envelope", "email", "mail", "message", "letter"], type: "fa", icon: faEnvelope },
|
||||
{ name: "print", keywords: ["print", "printer", "paper", "document"], type: "fa", icon: faPrint },
|
||||
{ name: "database", keywords: ["database", "data", "storage", "sql", "server"], type: "fa", icon: faDatabase },
|
||||
{ name: "server", keywords: ["server", "hosting", "backend", "infrastructure"], type: "fa", icon: faServer },
|
||||
{ name: "cloud", keywords: ["cloud", "storage", "upload", "saas", "hosting"], type: "fa", icon: faCloud },
|
||||
{ name: "wifi", keywords: ["wifi", "wireless", "internet", "network", "connection"], type: "fa", icon: faWifi },
|
||||
{ name: "bug", keywords: ["bug", "debug", "error", "issue", "testing"], type: "fa", icon: faBug },
|
||||
{ name: "shield", keywords: ["shield", "security", "protection", "defense", "safe"], type: "fa", icon: faShield },
|
||||
{ name: "bell", keywords: ["bell", "notification", "alert", "alarm", "reminder"], type: "fa", icon: faBell },
|
||||
{ name: "bookmark", keywords: ["bookmark", "save", "favorite", "mark"], type: "fa", icon: faBookmark },
|
||||
{ name: "calendar", keywords: ["calendar", "date", "schedule", "event", "planner"], type: "fa", icon: faCalendar },
|
||||
{ name: "circle-check", keywords: ["circle", "check", "done", "approve", "success"], type: "fa", icon: faCircleCheck },
|
||||
{ name: "circle-xmark", keywords: ["circle", "close", "cancel", "delete", "remove"], type: "fa", icon: faCircleXmark },
|
||||
{ name: "comment", keywords: ["comment", "chat", "message", "discussion", "talk"], type: "fa", icon: faComment },
|
||||
{ name: "compass", keywords: ["compass", "navigation", "direction", "explore"], type: "fa", icon: faCompass },
|
||||
{ name: "credit-card", keywords: ["credit", "card", "payment", "bank", "finance"], type: "fa", icon: faCreditCard },
|
||||
{ name: "crown", keywords: ["crown", "king", "premium", "vip", "royal"], type: "fa", icon: faCrown },
|
||||
{ name: "diamond", keywords: ["diamond", "gem", "luxury", "premium", "jewel"], type: "fa", icon: faDiamond },
|
||||
{ name: "display", keywords: ["display", "monitor", "screen", "desktop"], type: "fa", icon: faDisplay },
|
||||
{ name: "download", keywords: ["download", "save", "get", "arrow"], type: "fa", icon: faDownload },
|
||||
{ name: "droplet", keywords: ["droplet", "water", "liquid", "rain", "tear"], type: "fa", icon: faDroplet },
|
||||
{ name: "eye", keywords: ["eye", "view", "see", "watch", "visible"], type: "fa", icon: faEye },
|
||||
{ name: "face-smile", keywords: ["face", "smile", "happy", "emoji", "smiley"], type: "fa", icon: faFaceSmile },
|
||||
{ name: "file", keywords: ["file", "document", "paper", "page"], type: "fa", icon: faFile },
|
||||
{ name: "file-code", keywords: ["file", "code", "programming", "source", "script"], type: "fa", icon: faFileCode },
|
||||
{ name: "filter", keywords: ["filter", "sort", "funnel", "search"], type: "fa", icon: faFilter },
|
||||
{ name: "fingerprint", keywords: ["fingerprint", "identity", "biometric", "security"], type: "fa", icon: faFingerprint },
|
||||
{ name: "flag", keywords: ["flag", "mark", "country", "report", "milestone"], type: "fa", icon: faFlag },
|
||||
{ name: "gear", keywords: ["gear", "settings", "config", "options", "preferences"], type: "fa", icon: faGear },
|
||||
{ name: "glasses", keywords: ["glasses", "read", "vision", "spectacles"], type: "fa", icon: faGlasses },
|
||||
{ name: "handshake", keywords: ["handshake", "deal", "agreement", "partnership", "meeting"], type: "fa", icon: faHandshake },
|
||||
{ name: "hashtag", keywords: ["hashtag", "number", "tag", "social", "trending"], type: "fa", icon: faHashtag },
|
||||
{ name: "headphones", keywords: ["headphones", "audio", "music", "listen", "podcast"], type: "fa", icon: faHeadphones },
|
||||
{ name: "hospital", keywords: ["hospital", "medical", "health", "doctor", "clinic"], type: "fa", icon: faHospital },
|
||||
{ name: "image", keywords: ["image", "photo", "picture", "gallery"], type: "fa", icon: faImage },
|
||||
{ name: "inbox", keywords: ["inbox", "mail", "email", "messages"], type: "fa", icon: faInbox },
|
||||
{ name: "infinity", keywords: ["infinity", "loop", "endless", "unlimited"], type: "fa", icon: faInfinity },
|
||||
{ name: "key", keywords: ["key", "access", "password", "unlock", "authentication"], type: "fa", icon: faKey },
|
||||
{ name: "language", keywords: ["language", "translate", "i18n", "multilingual"], type: "fa", icon: faLanguage },
|
||||
{ name: "layer-group", keywords: ["layer", "stack", "design", "photoshop"], type: "fa", icon: faLayerGroup },
|
||||
{ name: "link", keywords: ["link", "chain", "url", "connection", "hyperlink"], type: "fa", icon: faLink },
|
||||
{ name: "list-check", keywords: ["list", "check", "todo", "tasks", "checklist"], type: "fa", icon: faListCheck },
|
||||
{ name: "magnet", keywords: ["magnet", "attract", "magnetic"], type: "fa", icon: faMagnet },
|
||||
{ name: "map", keywords: ["map", "location", "geography", "navigation"], type: "fa", icon: faMap },
|
||||
{ name: "map-pin", keywords: ["map", "pin", "location", "marker", "place"], type: "fa", icon: faMapPin },
|
||||
{ name: "medal", keywords: ["medal", "award", "achievement", "winner", "prize"], type: "fa", icon: faMedal },
|
||||
{ name: "message", keywords: ["message", "chat", "sms", "text", "conversation"], type: "fa", icon: faMessage },
|
||||
{ name: "microphone", keywords: ["microphone", "audio", "record", "voice", "podcast"], type: "fa", icon: faMicrophone },
|
||||
{ name: "moon", keywords: ["moon", "night", "dark", "sleep"], type: "fa", icon: faMoon },
|
||||
{ name: "newspaper", keywords: ["newspaper", "news", "article", "press", "media"], type: "fa", icon: faNewspaper },
|
||||
{ name: "paper-plane", keywords: ["paper", "plane", "send", "message", "email"], type: "fa", icon: faPaperPlane },
|
||||
{ name: "paperclip", keywords: ["paperclip", "attach", "attachment", "file"], type: "fa", icon: faPaperclip },
|
||||
{ name: "paste", keywords: ["paste", "clipboard", "copy"], type: "fa", icon: faPaste },
|
||||
{ name: "peace", keywords: ["peace", "harmony", "symbol"], type: "fa", icon: faPeace },
|
||||
{ name: "percent", keywords: ["percent", "discount", "sale", "percentage"], type: "fa", icon: faPercent },
|
||||
{ name: "person-running", keywords: ["person", "running", "exercise", "sport", "fitness", "jogging"], type: "fa", icon: faPersonRunning },
|
||||
{ name: "piggy-bank", keywords: ["piggy", "bank", "savings", "money", "finance"], type: "fa", icon: faPiggyBank },
|
||||
{ name: "pills", keywords: ["pills", "medicine", "health", "pharmacy", "drug"], type: "fa", icon: faPills },
|
||||
{ name: "puzzle-piece", keywords: ["puzzle", "piece", "plugin", "extension", "addon"], type: "fa", icon: faPuzzlePiece },
|
||||
{ name: "qrcode", keywords: ["qr", "code", "scan", "barcode"], type: "fa", icon: faQrcode },
|
||||
{ name: "quote-left", keywords: ["quote", "text", "citation", "blockquote"], type: "fa", icon: faQuoteLeft },
|
||||
{ name: "robot", keywords: ["robot", "ai", "automation", "bot", "machine"], type: "fa", icon: faRobot },
|
||||
{ name: "rotate", keywords: ["rotate", "refresh", "reload", "sync", "update"], type: "fa", icon: faRotate },
|
||||
{ name: "route", keywords: ["route", "path", "direction", "way", "navigation"], type: "fa", icon: faRoute },
|
||||
{ name: "ruler", keywords: ["ruler", "measure", "size", "length"], type: "fa", icon: faRuler },
|
||||
{ name: "scissors", keywords: ["scissors", "cut", "trim", "clip"], type: "fa", icon: faScissors },
|
||||
{ name: "screwdriver-wrench", keywords: ["screwdriver", "wrench", "tools", "repair", "fix", "maintenance"], type: "fa", icon: faScrewdriverWrench },
|
||||
{ name: "seedling", keywords: ["seedling", "plant", "grow", "garden", "nature", "eco"], type: "fa", icon: faSeedling },
|
||||
{ name: "share", keywords: ["share", "social", "send", "forward"], type: "fa", icon: faShare },
|
||||
{ name: "shirt", keywords: ["shirt", "clothing", "fashion", "apparel"], type: "fa", icon: faShirt },
|
||||
{ name: "shop", keywords: ["shop", "store", "retail", "market", "commerce"], type: "fa", icon: faShop },
|
||||
{ name: "signal", keywords: ["signal", "reception", "antenna", "strength"], type: "fa", icon: faSignal },
|
||||
{ name: "sitemap", keywords: ["sitemap", "structure", "hierarchy", "organization"], type: "fa", icon: faSitemap },
|
||||
{ name: "sliders", keywords: ["sliders", "settings", "adjust", "control", "equalizer"], type: "fa", icon: faSliders },
|
||||
{ name: "snowflake", keywords: ["snowflake", "winter", "cold", "freeze", "ice"], type: "fa", icon: faSnowflake },
|
||||
{ name: "spa", keywords: ["spa", "wellness", "relax", "massage", "health"], type: "fa", icon: faSpa },
|
||||
{ name: "square-check", keywords: ["square", "check", "checkbox", "done", "complete"], type: "fa", icon: faSquareCheck },
|
||||
{ name: "stethoscope", keywords: ["stethoscope", "doctor", "medical", "health", "hospital"], type: "fa", icon: faStethoscope },
|
||||
{ name: "sun", keywords: ["sun", "day", "light", "bright", "weather", "summer"], type: "fa", icon: faSun },
|
||||
{ name: "table-cells", keywords: ["table", "grid", "spreadsheet", "data", "cells"], type: "fa", icon: faTableCells },
|
||||
{ name: "terminal", keywords: ["terminal", "console", "command", "cli", "shell"], type: "fa", icon: faTerminal },
|
||||
{ name: "thumbs-up", keywords: ["thumbs", "up", "like", "approve", "good"], type: "fa", icon: faThumbsUp },
|
||||
{ name: "toolbox", keywords: ["toolbox", "tools", "repair", "kit", "equipment"], type: "fa", icon: faToolbox },
|
||||
{ name: "trash-can", keywords: ["trash", "delete", "remove", "bin", "garbage"], type: "fa", icon: faTrashCan },
|
||||
{ name: "trophy", keywords: ["trophy", "award", "winner", "champion", "prize", "achievement"], type: "fa", icon: faTrophy },
|
||||
{ name: "truck", keywords: ["truck", "delivery", "shipping", "transport", "logistics"], type: "fa", icon: faTruck },
|
||||
{ name: "tv", keywords: ["tv", "television", "screen", "monitor", "watch"], type: "fa", icon: faTv },
|
||||
{ name: "upload", keywords: ["upload", "send", "cloud", "arrow"], type: "fa", icon: faUpload },
|
||||
{ name: "user-gear", keywords: ["user", "gear", "admin", "settings", "account"], type: "fa", icon: faUserGear },
|
||||
{ name: "vault", keywords: ["vault", "safe", "secure", "bank", "storage"], type: "fa", icon: faVault },
|
||||
{ name: "video", keywords: ["video", "camera", "record", "film", "stream"], type: "fa", icon: faVideo },
|
||||
{ name: "volume-high", keywords: ["volume", "sound", "audio", "speaker", "loud"], type: "fa", icon: faVolumeHigh },
|
||||
{ name: "wallet", keywords: ["wallet", "money", "payment", "finance", "cash"], type: "fa", icon: faWallet },
|
||||
{ name: "wand-magic", keywords: ["wand", "magic", "sparkle", "wizard", "auto"], type: "fa", icon: faWandMagicSparkles },
|
||||
{ name: "warehouse", keywords: ["warehouse", "storage", "inventory", "logistics"], type: "fa", icon: faWarehouse },
|
||||
{ name: "weight", keywords: ["weight", "scale", "heavy", "mass", "gym"], type: "fa", icon: faWeight },
|
||||
{ name: "window", keywords: ["window", "browser", "app", "application"], type: "fa", icon: faWindowMaximize },
|
||||
];
|
||||
|
||||
const mdiIcons: IconEntry[] = [
|
||||
// Smart Home & Tech
|
||||
{ name: "mdi-home-assistant", keywords: ["home", "assistant", "smart", "automation", "iot", "homeassistant"], type: "mdi", icon: mdiHomeAssistant },
|
||||
{ name: "mdi-docker", keywords: ["docker", "container", "devops", "deploy"], type: "mdi", icon: mdiDocker },
|
||||
{ name: "mdi-github", keywords: ["github", "git", "repository", "code", "open source"], type: "mdi", icon: mdiGithub },
|
||||
{ name: "mdi-gitlab", keywords: ["gitlab", "git", "repository", "code", "ci"], type: "mdi", icon: mdiGitlab },
|
||||
{ name: "mdi-linux", keywords: ["linux", "os", "ubuntu", "debian", "penguin"], type: "mdi", icon: mdiLinux },
|
||||
{ name: "mdi-apple", keywords: ["apple", "mac", "ios", "macos", "iphone"], type: "mdi", icon: mdiApple },
|
||||
{ name: "mdi-windows", keywords: ["windows", "microsoft", "pc", "os"], type: "mdi", icon: mdiMicrosoftWindows },
|
||||
{ name: "mdi-android", keywords: ["android", "google", "mobile", "phone"], type: "mdi", icon: mdiAndroid },
|
||||
{ name: "mdi-react", keywords: ["react", "javascript", "frontend", "web", "component"], type: "mdi", icon: mdiReact },
|
||||
{ name: "mdi-nodejs", keywords: ["node", "nodejs", "javascript", "backend", "server"], type: "mdi", icon: mdiNodejs },
|
||||
{ name: "mdi-python", keywords: ["python", "programming", "language", "script"], type: "mdi", icon: mdiLanguagePython },
|
||||
{ name: "mdi-javascript", keywords: ["javascript", "js", "programming", "web", "frontend"], type: "mdi", icon: mdiLanguageJavascript },
|
||||
{ name: "mdi-typescript", keywords: ["typescript", "ts", "programming", "type", "web"], type: "mdi", icon: mdiLanguageTypescript },
|
||||
{ name: "mdi-html5", keywords: ["html", "html5", "web", "markup", "frontend"], type: "mdi", icon: mdiLanguageHtml5 },
|
||||
{ name: "mdi-css3", keywords: ["css", "css3", "style", "web", "frontend", "design"], type: "mdi", icon: mdiLanguageCss3 },
|
||||
{ name: "mdi-aws", keywords: ["aws", "amazon", "cloud", "hosting"], type: "mdi", icon: mdiAws },
|
||||
{ name: "mdi-gcloud", keywords: ["google", "cloud", "gcp", "hosting"], type: "mdi", icon: mdiGoogleCloud },
|
||||
{ name: "mdi-azure", keywords: ["azure", "microsoft", "cloud", "hosting"], type: "mdi", icon: mdiMicrosoftAzure },
|
||||
{ name: "mdi-kubernetes", keywords: ["kubernetes", "k8s", "container", "orchestration", "devops"], type: "mdi", icon: mdiKubernetes },
|
||||
{ name: "mdi-terraform", keywords: ["terraform", "infrastructure", "iac", "devops", "cloud"], type: "mdi", icon: mdiTerraform },
|
||||
{ name: "mdi-raspberry-pi", keywords: ["raspberry", "pi", "hardware", "iot", "maker"], type: "mdi", icon: mdiRaspberryPi },
|
||||
{ name: "mdi-nas", keywords: ["nas", "storage", "network", "synology", "backup"], type: "mdi", icon: mdiNas },
|
||||
{ name: "mdi-router", keywords: ["router", "network", "wifi", "internet"], type: "mdi", icon: mdiRouter },
|
||||
{ name: "mdi-ip-network", keywords: ["ip", "network", "internet", "lan", "subnet"], type: "mdi", icon: mdiIpNetwork },
|
||||
{ name: "mdi-server-network", keywords: ["server", "network", "hosting", "infrastructure", "datacenter"], type: "mdi", icon: mdiServerNetwork },
|
||||
// Devices
|
||||
{ name: "mdi-cellphone", keywords: ["cellphone", "mobile", "phone", "smartphone"], type: "mdi", icon: mdiCellphone },
|
||||
{ name: "mdi-tablet", keywords: ["tablet", "ipad", "device", "screen"], type: "mdi", icon: mdiTablet },
|
||||
{ name: "mdi-laptop", keywords: ["laptop", "computer", "notebook", "macbook"], type: "mdi", icon: mdiLaptop },
|
||||
{ name: "mdi-desktop", keywords: ["desktop", "computer", "pc", "monitor", "imac"], type: "mdi", icon: mdiDesktopClassic },
|
||||
{ name: "mdi-watch", keywords: ["watch", "smartwatch", "wearable", "time"], type: "mdi", icon: mdiWatch },
|
||||
// Family & Pets
|
||||
{ name: "mdi-baby", keywords: ["baby", "child", "infant", "family", "stroller", "kids"], type: "mdi", icon: mdiBabyCarriage },
|
||||
{ name: "mdi-dog", keywords: ["dog", "pet", "animal", "puppy"], type: "mdi", icon: mdiDog },
|
||||
{ name: "mdi-cat", keywords: ["cat", "pet", "animal", "kitten"], type: "mdi", icon: mdiCat },
|
||||
{ name: "mdi-fish", keywords: ["fish", "aquarium", "pet", "sea", "ocean"], type: "mdi", icon: mdiFish },
|
||||
{ name: "mdi-bird", keywords: ["bird", "pet", "animal", "fly", "parrot"], type: "mdi", icon: mdiBird },
|
||||
// Nature
|
||||
{ name: "mdi-flower", keywords: ["flower", "garden", "plant", "nature", "bloom"], type: "mdi", icon: mdiFlower },
|
||||
{ name: "mdi-tree", keywords: ["tree", "nature", "forest", "plant", "wood"], type: "mdi", icon: mdiTree },
|
||||
{ name: "mdi-forest", keywords: ["forest", "trees", "nature", "woods", "park"], type: "mdi", icon: mdiForest },
|
||||
{ name: "mdi-sunny", keywords: ["sun", "sunny", "weather", "bright", "summer", "warm"], type: "mdi", icon: mdiWeatherSunny },
|
||||
{ name: "mdi-rainy", keywords: ["rain", "rainy", "weather", "storm", "wet"], type: "mdi", icon: mdiWeatherRainy },
|
||||
// Transport
|
||||
{ name: "mdi-bicycle", keywords: ["bicycle", "bike", "cycling", "sport", "transport"], type: "mdi", icon: mdiBicycle },
|
||||
{ name: "mdi-motorbike", keywords: ["motorbike", "motorcycle", "ride", "vehicle"], type: "mdi", icon: mdiMotorbike },
|
||||
{ name: "mdi-train", keywords: ["train", "rail", "transport", "travel", "commute"], type: "mdi", icon: mdiTrain },
|
||||
{ name: "mdi-bus", keywords: ["bus", "transport", "public", "commute", "travel"], type: "mdi", icon: mdiBus },
|
||||
{ name: "mdi-airplane", keywords: ["airplane", "flight", "travel", "vacation", "airport"], type: "mdi", icon: mdiAirplane },
|
||||
{ name: "mdi-sail", keywords: ["sail", "boat", "ship", "sea", "ocean", "sailing"], type: "mdi", icon: mdiSailBoat },
|
||||
// Sports & Fitness
|
||||
{ name: "mdi-swim", keywords: ["swim", "pool", "water", "sport", "exercise"], type: "mdi", icon: mdiSwim },
|
||||
{ name: "mdi-ski", keywords: ["ski", "skiing", "winter", "snow", "sport"], type: "mdi", icon: mdiSki },
|
||||
{ name: "mdi-soccer", keywords: ["soccer", "football", "sport", "ball", "game"], type: "mdi", icon: mdiSoccer },
|
||||
{ name: "mdi-basketball", keywords: ["basketball", "sport", "ball", "game", "nba"], type: "mdi", icon: mdiBasketball },
|
||||
{ name: "mdi-tennis", keywords: ["tennis", "sport", "racket", "ball", "game"], type: "mdi", icon: mdiTennis },
|
||||
{ name: "mdi-golf", keywords: ["golf", "sport", "club", "ball", "green"], type: "mdi", icon: mdiGolf },
|
||||
{ name: "mdi-yoga", keywords: ["yoga", "meditation", "fitness", "relax", "stretch", "wellness"], type: "mdi", icon: mdiYoga },
|
||||
{ name: "mdi-meditation", keywords: ["meditation", "mindfulness", "zen", "calm", "relax"], type: "mdi", icon: mdiMeditation },
|
||||
{ name: "mdi-run", keywords: ["run", "running", "jogging", "sport", "fitness", "exercise"], type: "mdi", icon: mdiRunFast },
|
||||
// Food & Drink
|
||||
{ name: "mdi-food", keywords: ["food", "meal", "eat", "dinner", "lunch", "restaurant"], type: "mdi", icon: mdiFood },
|
||||
{ name: "mdi-apple-fruit", keywords: ["apple", "fruit", "food", "healthy", "snack"], type: "mdi", icon: mdiFoodApple },
|
||||
{ name: "mdi-coffee", keywords: ["coffee", "cafe", "drink", "morning", "espresso", "latte"], type: "mdi", icon: mdiCoffee },
|
||||
{ name: "mdi-beer", keywords: ["beer", "drink", "alcohol", "pub", "bar", "brewery"], type: "mdi", icon: mdiBeer },
|
||||
{ name: "mdi-cocktail", keywords: ["cocktail", "drink", "alcohol", "bar", "party", "wine"], type: "mdi", icon: mdiGlassCocktail },
|
||||
{ name: "mdi-pizza", keywords: ["pizza", "food", "italian", "fast food", "eat"], type: "mdi", icon: mdiPizza },
|
||||
{ name: "mdi-cupcake", keywords: ["cupcake", "cake", "bake", "dessert", "sweet"], type: "mdi", icon: mdiCupcake },
|
||||
{ name: "mdi-ice-cream", keywords: ["ice cream", "dessert", "sweet", "summer", "gelato"], type: "mdi", icon: mdiIceCream },
|
||||
{ name: "mdi-grill", keywords: ["grill", "bbq", "barbecue", "cook", "outdoor", "food"], type: "mdi", icon: mdiGrill },
|
||||
// Home & Appliances
|
||||
{ name: "mdi-fridge", keywords: ["fridge", "refrigerator", "kitchen", "appliance", "food"], type: "mdi", icon: mdiFridge },
|
||||
{ name: "mdi-washing-machine", keywords: ["washing", "machine", "laundry", "clothes", "clean"], type: "mdi", icon: mdiWashingMachine },
|
||||
{ name: "mdi-vacuum", keywords: ["vacuum", "clean", "floor", "housework", "appliance"], type: "mdi", icon: mdiVacuum },
|
||||
{ name: "mdi-sofa", keywords: ["sofa", "couch", "living room", "furniture", "relax"], type: "mdi", icon: mdiSofa },
|
||||
{ name: "mdi-bed", keywords: ["bed", "sleep", "bedroom", "rest", "furniture"], type: "mdi", icon: mdiBed },
|
||||
{ name: "mdi-bathtub", keywords: ["bathtub", "bath", "bathroom", "shower", "wash"], type: "mdi", icon: mdiBathtub },
|
||||
{ name: "mdi-toilet", keywords: ["toilet", "bathroom", "wc", "restroom"], type: "mdi", icon: mdiToilet },
|
||||
{ name: "mdi-lamp", keywords: ["lamp", "light", "desk", "reading", "illumination"], type: "mdi", icon: mdiLamp },
|
||||
{ name: "mdi-ceiling-fan", keywords: ["ceiling", "fan", "cool", "air", "ventilation"], type: "mdi", icon: mdiCeilingFan },
|
||||
{ name: "mdi-thermometer", keywords: ["thermometer", "temperature", "heat", "cold", "weather"], type: "mdi", icon: mdiThermometer },
|
||||
{ name: "mdi-fireplace", keywords: ["fireplace", "fire", "warm", "cozy", "chimney"], type: "mdi", icon: mdiFireplace },
|
||||
// Finance
|
||||
{ name: "mdi-briefcase", keywords: ["briefcase", "work", "business", "job", "career"], type: "mdi", icon: mdiBriefcase },
|
||||
{ name: "mdi-cash", keywords: ["cash", "money", "payment", "bills", "finance"], type: "mdi", icon: mdiCash },
|
||||
{ name: "mdi-euro", keywords: ["euro", "currency", "money", "finance", "europe"], type: "mdi", icon: mdiCurrencyEur },
|
||||
{ name: "mdi-dollar", keywords: ["dollar", "usd", "currency", "money", "finance", "us"], type: "mdi", icon: mdiCurrencyUsd },
|
||||
{ name: "mdi-bitcoin", keywords: ["bitcoin", "btc", "crypto", "cryptocurrency", "blockchain"], type: "mdi", icon: mdiCurrencyBtc },
|
||||
{ name: "mdi-chart-line", keywords: ["chart", "line", "trend", "analytics", "statistics"], type: "mdi", icon: mdiChartLine },
|
||||
{ name: "mdi-chart-pie", keywords: ["chart", "pie", "analytics", "statistics", "data"], type: "mdi", icon: mdiChartPie },
|
||||
{ name: "mdi-chart-bar", keywords: ["chart", "bar", "analytics", "statistics", "data", "graph"], type: "mdi", icon: mdiChartBar },
|
||||
{ name: "mdi-trending-up", keywords: ["trending", "up", "growth", "increase", "profit"], type: "mdi", icon: mdiTrendingUp },
|
||||
{ name: "mdi-bank", keywords: ["bank", "finance", "money", "institution", "savings"], type: "mdi", icon: mdiBank },
|
||||
// Education & Creative
|
||||
{ name: "mdi-school", keywords: ["school", "education", "study", "learn", "university"], type: "mdi", icon: mdiSchool },
|
||||
{ name: "mdi-book-open", keywords: ["book", "open", "read", "study", "library", "education"], type: "mdi", icon: mdiBookOpenVariant },
|
||||
{ name: "mdi-notebook", keywords: ["notebook", "journal", "notes", "write", "diary"], type: "mdi", icon: mdiNotebook },
|
||||
{ name: "mdi-pencil", keywords: ["pencil", "write", "draw", "edit", "sketch"], type: "mdi", icon: mdiPencil },
|
||||
{ name: "mdi-palette", keywords: ["palette", "art", "paint", "design", "creative", "color"], type: "mdi", icon: mdiPaletteOutline },
|
||||
{ name: "mdi-music", keywords: ["music", "note", "song", "audio", "melody"], type: "mdi", icon: mdiMusic },
|
||||
{ name: "mdi-movie", keywords: ["movie", "film", "cinema", "video", "entertainment"], type: "mdi", icon: mdiMovieOpen },
|
||||
{ name: "mdi-television", keywords: ["television", "tv", "screen", "watch", "show", "series"], type: "mdi", icon: mdiTelevision },
|
||||
{ name: "mdi-gamepad", keywords: ["gamepad", "game", "gaming", "play", "controller", "console"], type: "mdi", icon: mdiGamepadVariant },
|
||||
{ name: "mdi-puzzle", keywords: ["puzzle", "piece", "game", "solve", "jigsaw"], type: "mdi", icon: mdiPuzzle },
|
||||
{ name: "mdi-camera", keywords: ["camera", "photo", "picture", "photography"], type: "mdi", icon: mdiCamera },
|
||||
{ name: "mdi-microphone", keywords: ["microphone", "audio", "record", "voice", "podcast", "sing"], type: "mdi", icon: mdiMicrophone },
|
||||
{ name: "mdi-headphones", keywords: ["headphones", "audio", "music", "listen"], type: "mdi", icon: mdiHeadphones },
|
||||
{ name: "mdi-speaker", keywords: ["speaker", "audio", "sound", "music", "volume"], type: "mdi", icon: mdiSpeaker },
|
||||
{ name: "mdi-3d-printer", keywords: ["3d", "printer", "print", "maker", "prototype"], type: "mdi", icon: mdiPrinter3d },
|
||||
// People & Events
|
||||
{ name: "mdi-heart", keywords: ["heart", "love", "health", "favorite", "like", "romance"], type: "mdi", icon: mdiHeart },
|
||||
{ name: "mdi-hand-heart", keywords: ["hand", "heart", "charity", "volunteer", "donate", "care"], type: "mdi", icon: mdiHandHeart },
|
||||
{ name: "mdi-family", keywords: ["family", "parents", "children", "kids", "household"], type: "mdi", icon: mdiHumanMaleFemaleChild },
|
||||
{ name: "mdi-group", keywords: ["group", "team", "people", "community", "users"], type: "mdi", icon: mdiAccountGroup },
|
||||
{ name: "mdi-party", keywords: ["party", "celebration", "confetti", "event", "fun"], type: "mdi", icon: mdiPartyPopper },
|
||||
{ name: "mdi-gift", keywords: ["gift", "present", "birthday", "surprise", "wrap"], type: "mdi", icon: mdiGift },
|
||||
{ name: "mdi-balloon", keywords: ["balloon", "party", "celebration", "birthday", "fun"], type: "mdi", icon: mdiBalloon },
|
||||
{ name: "mdi-cake", keywords: ["cake", "birthday", "celebration", "dessert", "party"], type: "mdi", icon: mdiCake },
|
||||
{ name: "mdi-ring", keywords: ["ring", "wedding", "engagement", "marriage", "jewelry"], type: "mdi", icon: mdiRing },
|
||||
{ name: "mdi-happy", keywords: ["happy", "smiley", "face", "emoji", "joy", "mood"], type: "mdi", icon: mdiEmoticonHappy },
|
||||
// Health
|
||||
{ name: "mdi-medical", keywords: ["medical", "bag", "doctor", "health", "first aid"], type: "mdi", icon: mdiMedicalBag },
|
||||
{ name: "mdi-hospital", keywords: ["hospital", "medical", "health", "clinic", "emergency"], type: "mdi", icon: mdiHospitalBox },
|
||||
{ name: "mdi-pill", keywords: ["pill", "medicine", "drug", "pharmacy", "health"], type: "mdi", icon: mdiPill },
|
||||
{ name: "mdi-stethoscope", keywords: ["stethoscope", "doctor", "medical", "health", "checkup"], type: "mdi", icon: mdiStethoscope },
|
||||
{ name: "mdi-tooth", keywords: ["tooth", "dental", "dentist", "teeth", "health"], type: "mdi", icon: mdiTooth },
|
||||
// Security
|
||||
{ name: "mdi-security", keywords: ["security", "guard", "protect", "safe", "shield"], type: "mdi", icon: mdiSecurity },
|
||||
{ name: "mdi-shield-check", keywords: ["shield", "check", "verified", "secure", "safe"], type: "mdi", icon: mdiShieldCheck },
|
||||
{ name: "mdi-lock", keywords: ["lock", "secure", "password", "private", "encrypted"], type: "mdi", icon: mdiLock },
|
||||
{ name: "mdi-eye-off", keywords: ["eye", "off", "hidden", "privacy", "invisible"], type: "mdi", icon: mdiEyeOff },
|
||||
{ name: "mdi-vpn", keywords: ["vpn", "network", "private", "secure", "tunnel"], type: "mdi", icon: mdiVpn },
|
||||
// Tools & DIY
|
||||
{ name: "mdi-tools", keywords: ["tools", "repair", "fix", "maintenance", "kit"], type: "mdi", icon: mdiTools },
|
||||
{ name: "mdi-hammer", keywords: ["hammer", "build", "construction", "nail", "diy"], type: "mdi", icon: mdiHammer },
|
||||
{ name: "mdi-saw", keywords: ["saw", "cut", "wood", "diy", "construction"], type: "mdi", icon: mdiHandSaw },
|
||||
{ name: "mdi-screwdriver", keywords: ["screwdriver", "repair", "fix", "tool", "diy"], type: "mdi", icon: mdiScrewdriver },
|
||||
{ name: "mdi-wrench", keywords: ["wrench", "repair", "fix", "tool", "plumbing"], type: "mdi", icon: mdiWrench },
|
||||
// Environment
|
||||
{ name: "mdi-recycle", keywords: ["recycle", "green", "environment", "eco", "sustainability"], type: "mdi", icon: mdiRecycle },
|
||||
{ name: "mdi-leaf", keywords: ["leaf", "nature", "plant", "eco", "green", "organic"], type: "mdi", icon: mdiLeaf },
|
||||
{ name: "mdi-sprout", keywords: ["sprout", "grow", "plant", "garden", "seedling"], type: "mdi", icon: mdiSprout },
|
||||
{ name: "mdi-earth", keywords: ["earth", "world", "planet", "global", "environment"], type: "mdi", icon: mdiEarth },
|
||||
{ name: "mdi-water", keywords: ["water", "drop", "liquid", "ocean", "sea", "hydrate"], type: "mdi", icon: mdiWaterOutline },
|
||||
// Science
|
||||
{ name: "mdi-rocket", keywords: ["rocket", "space", "launch", "startup", "fast"], type: "mdi", icon: mdiRocket },
|
||||
{ name: "mdi-brain", keywords: ["brain", "think", "mind", "intelligence", "ai", "neuro"], type: "mdi", icon: mdiBrain },
|
||||
{ name: "mdi-atom", keywords: ["atom", "science", "physics", "nuclear", "chemistry"], type: "mdi", icon: mdiAtom },
|
||||
{ name: "mdi-dna", keywords: ["dna", "genetics", "biology", "science", "genome"], type: "mdi", icon: mdiDna },
|
||||
{ name: "mdi-magnet", keywords: ["magnet", "attract", "magnetic", "physics"], type: "mdi", icon: mdiMagnet },
|
||||
];
|
||||
|
||||
const allIcons: IconEntry[] = [...faIcons, ...mdiIcons];
|
||||
|
||||
// --- Component ---
|
||||
|
||||
interface IconPickerProps {
|
||||
selectedIcon: string;
|
||||
onSelect: (iconName: string) => void;
|
||||
darkMode: boolean;
|
||||
}
|
||||
|
||||
export default function IconPicker({ selectedIcon, onSelect, darkMode }: IconPickerProps) {
|
||||
const [search, setSearch] = useState("");
|
||||
const [activeTab, setActiveTab] = useState<"all" | "fa" | "mdi">("all");
|
||||
const searchRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
searchRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
const source = activeTab === "all" ? allIcons : activeTab === "fa" ? faIcons : mdiIcons;
|
||||
if (!search.trim()) return source;
|
||||
const terms = search.toLowerCase().split(/\s+/);
|
||||
return source.filter(entry =>
|
||||
terms.every(term =>
|
||||
entry.name.toLowerCase().includes(term) ||
|
||||
entry.keywords.some(kw => kw.includes(term))
|
||||
)
|
||||
);
|
||||
}, [search, activeTab]);
|
||||
|
||||
const bg = darkMode ? "#2a2a3a" : "#fff";
|
||||
const border = darkMode ? "#555" : "#e5e7eb";
|
||||
const textColor = darkMode ? "#d1d5db" : "#555";
|
||||
const activeBg = darkMode ? "#374151" : "#e0e7ff";
|
||||
const hoverBg = darkMode ? "#333" : "#f3f4f6";
|
||||
const tabActiveBg = darkMode ? "#374151" : "#e0e7ff";
|
||||
const tabColor = darkMode ? "#9ca3af" : "#888";
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
background: bg,
|
||||
border: `1px solid ${border}`,
|
||||
borderRadius: "12px",
|
||||
padding: "8px",
|
||||
boxShadow: "0 8px 24px rgba(0,0,0,0.2)",
|
||||
width: "300px",
|
||||
}}>
|
||||
{/* Search */}
|
||||
<input
|
||||
ref={searchRef}
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
placeholder="Search icons..."
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: "6px 10px",
|
||||
border: `1px solid ${border}`,
|
||||
borderRadius: "8px",
|
||||
background: darkMode ? "#1e1e2e" : "#f9fafb",
|
||||
color: darkMode ? "#e5e7eb" : "#333",
|
||||
fontSize: "0.8rem",
|
||||
outline: "none",
|
||||
boxSizing: "border-box",
|
||||
marginBottom: "6px",
|
||||
}}
|
||||
/>
|
||||
{/* Tabs */}
|
||||
<div style={{ display: "flex", gap: "2px", marginBottom: "6px" }}>
|
||||
{(["all", "fa", "mdi"] as const).map(tab => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: "3px 6px",
|
||||
fontSize: "0.7rem",
|
||||
fontWeight: activeTab === tab ? 600 : 400,
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
background: activeTab === tab ? tabActiveBg : "transparent",
|
||||
color: activeTab === tab ? (darkMode ? "#e5e7eb" : "#333") : tabColor,
|
||||
}}
|
||||
>
|
||||
{tab === "all" ? `All (${allIcons.length})` : tab === "fa" ? "FontAwesome" : "Material"}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{/* Grid */}
|
||||
<div style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(8, 1fr)",
|
||||
gap: "2px",
|
||||
maxHeight: "240px",
|
||||
overflowY: "auto",
|
||||
}}>
|
||||
{filtered.map(entry => (
|
||||
<button
|
||||
key={entry.name}
|
||||
onClick={() => onSelect(entry.name)}
|
||||
title={entry.name}
|
||||
style={{
|
||||
width: "32px",
|
||||
height: "32px",
|
||||
border: "none",
|
||||
background: selectedIcon === entry.name ? activeBg : "transparent",
|
||||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: textColor,
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
if (selectedIcon !== entry.name) (e.currentTarget as HTMLButtonElement).style.background = hoverBg;
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
if (selectedIcon !== entry.name) (e.currentTarget as HTMLButtonElement).style.background = "transparent";
|
||||
}}
|
||||
>
|
||||
{entry.type === "fa" ? (
|
||||
<FontAwesomeIcon icon={entry.icon as IconDefinition} style={{ fontSize: "14px" }} />
|
||||
) : (
|
||||
<Icon path={entry.icon as string} size={0.6} />
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
{filtered.length === 0 && (
|
||||
<div style={{ gridColumn: "1 / -1", textAlign: "center", padding: "16px", color: tabColor, fontSize: "0.8rem" }}>
|
||||
No icons found
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Re-export for use in ProjectIcon renderer
|
||||
export { allIcons, type IconEntry };
|
||||
@ -12,6 +12,8 @@ import { useSession, signOut } from "next-auth/react";
|
||||
import CalendarEventModal from "./CalendarEventModal";
|
||||
import TaskRecurrenceModal from "./RecurrenceModal";
|
||||
import { GridTaskBlock } from "./GridTaskBlock";
|
||||
import IconPicker, { allIcons } from "./IconPicker";
|
||||
import MdiIcon from "@mdi/react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faApple, faGoogle, faMicrosoft, faNotion } from "@fortawesome/free-brands-svg-icons";
|
||||
import {
|
||||
@ -10312,12 +10314,20 @@ const projectIconsGlobal: { name: string; icon: IconDefinition }[] = [
|
||||
{ name: "tag", icon: faTag },
|
||||
];
|
||||
|
||||
// Helper to render a project icon (FA name or legacy emoji)
|
||||
// Helper to render a project icon (FA name, MDI name, or legacy emoji)
|
||||
function ProjectIcon({ icon, size = 18, color }: { icon?: string | null; size?: number; color?: string }) {
|
||||
if (!icon) return <FontAwesomeIcon icon={faFolder} style={{ fontSize: size, color }} />;
|
||||
// Check if it's an FA icon name
|
||||
const found = projectIconsGlobal.find((i) => i.name === icon);
|
||||
if (found) return <FontAwesomeIcon icon={found.icon} style={{ fontSize: size, color }} />;
|
||||
// Check unified icon registry (FA + MDI)
|
||||
const found = allIcons.find((i) => i.name === icon);
|
||||
if (found) {
|
||||
if (found.type === "fa") {
|
||||
return <FontAwesomeIcon icon={found.icon as import("@fortawesome/free-solid-svg-icons").IconDefinition} style={{ fontSize: size, color }} />;
|
||||
}
|
||||
return <MdiIcon path={found.icon as string} size={size / 24} color={color} />;
|
||||
}
|
||||
// Legacy: check old projectIconsGlobal for backwards compat
|
||||
const legacy = projectIconsGlobal.find((i) => i.name === icon);
|
||||
if (legacy) return <FontAwesomeIcon icon={legacy.icon} style={{ fontSize: size, color }} />;
|
||||
// Legacy emoji fallback
|
||||
return <span style={{ fontSize: size, lineHeight: 1 }}>{icon}</span>;
|
||||
}
|
||||
@ -10408,14 +10418,8 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl
|
||||
<ProjectIcon icon={editIcon} size={18} color={darkMode ? "#d1d5db" : "#555"} />
|
||||
</button>
|
||||
{showEditIconPicker && (
|
||||
<div style={{ position: "absolute", top: "100%", left: 0, marginTop: "4px", zIndex: 50, background: darkMode ? "#2a2a3a" : "#fff", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, borderRadius: "12px", padding: "10px", boxShadow: "0 8px 24px rgba(0,0,0,0.2)", width: "280px", maxHeight: "240px", overflowY: "auto" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(8, 1fr)", gap: "4px" }}>
|
||||
{projectIconsGlobal.map((item) => (
|
||||
<button key={item.name} onClick={() => { setEditIcon(item.name); setShowEditIconPicker(false); }} style={{ width: "30px", height: "30px", border: "none", background: editIcon === item.name ? (darkMode ? "#374151" : "#e0e7ff") : "transparent", borderRadius: "6px", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", color: darkMode ? "#d1d5db" : "#555" }}>
|
||||
<FontAwesomeIcon icon={item.icon} style={{ fontSize: "14px" }} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ position: "absolute", top: "100%", left: 0, marginTop: "4px", zIndex: 50 }}>
|
||||
<IconPicker selectedIcon={editIcon} onSelect={(name) => { setEditIcon(name); setShowEditIconPicker(false); }} darkMode={darkMode} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -10457,14 +10461,8 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl
|
||||
<ProjectIcon icon={newProjectIcon} size={18} color={darkMode ? "#d1d5db" : "#555"} />
|
||||
</button>
|
||||
{showNewIconPicker && (
|
||||
<div style={{ position: "absolute", bottom: "100%", left: 0, marginBottom: "4px", zIndex: 50, background: darkMode ? "#2a2a3a" : "#fff", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, borderRadius: "12px", padding: "10px", boxShadow: "0 8px 24px rgba(0,0,0,0.2)", width: "280px", maxHeight: "240px", overflowY: "auto" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(8, 1fr)", gap: "4px" }}>
|
||||
{projectIconsGlobal.map((item) => (
|
||||
<button key={item.name} onClick={() => { setNewProjectIcon(item.name); setShowNewIconPicker(false); }} style={{ width: "30px", height: "30px", border: "none", background: newProjectIcon === item.name ? (darkMode ? "#374151" : "#e0e7ff") : "transparent", borderRadius: "6px", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", color: darkMode ? "#d1d5db" : "#555" }}>
|
||||
<FontAwesomeIcon icon={item.icon} style={{ fontSize: "14px" }} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ position: "absolute", bottom: "100%", left: 0, marginBottom: "4px", zIndex: 50 }}>
|
||||
<IconPicker selectedIcon={newProjectIcon} onSelect={(name) => { setNewProjectIcon(name); setShowNewIconPicker(false); }} darkMode={darkMode} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user