From b4405f05ab4f16528b798d8fc49e93bc8c3fc107 Mon Sep 17 00:00:00 2001 From: Karsa Date: Fri, 5 Dec 2025 14:18:46 +0100 Subject: [PATCH] feat(site): add brand stop words to icon search (#3824) * feat(site): added extended no results placeholder with brand icon stop words * feat(site): fix grammatical error * feat: extract brand stopwords & update github action to use these stopwords * Apply suggestions from code review Co-authored-by: Jakob Guddas * feat: only use icon name section for closing brand request issues * feat: added mcp brand stopword --------- Co-authored-by: Jakob Guddas Co-authored-by: Eric Fennis --- .../close-issue-with-banned-phrases.yml | 39 ++- .gitignore | 2 +- brand-stopwords.json | 149 ++++++++++ .../icons/IconsCategoryOverview.vue | 83 +++--- .../theme/components/icons/IconsOverview.vue | 49 ++-- .../theme/components/icons/NoResults.vue | 267 +++++++++++++++--- .../theme/utils/useSearchPlaceholder.ts | 41 +++ docs/package.json | 1 + docs/scripts/writeBrandStopwords.mjs | 15 + 9 files changed, 515 insertions(+), 131 deletions(-) create mode 100644 brand-stopwords.json create mode 100644 docs/.vitepress/theme/utils/useSearchPlaceholder.ts create mode 100644 docs/scripts/writeBrandStopwords.mjs diff --git a/.github/workflows/close-issue-with-banned-phrases.yml b/.github/workflows/close-issue-with-banned-phrases.yml index e6dd40207..abd2d7c7f 100644 --- a/.github/workflows/close-issue-with-banned-phrases.yml +++ b/.github/workflows/close-issue-with-banned-phrases.yml @@ -1,4 +1,4 @@ -name: Close Issue with Banned Phrases +name: Close Icon Requests with Brand Terms on: issues: @@ -13,23 +13,36 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: Check for blocked phrases in issue title + - name: Load stopwords from JSON & check issue title & body + if: contains(github.event.issue.labels.*.name, '🙌 icon request') run: | ISSUE_TITLE=$(jq -r '.issue.title' "$GITHUB_EVENT_PATH") - BLOCKED_PHRASES=("twitter" "whatsapp" "logo" "google" "tiktok" "facebook" "slack" "discord" "bluesky" "spotify" "behance" "pix" "x.com" "telegram") + ISSUE_BODY=$(jq -r '.issue.body // ""' "$GITHUB_EVENT_PATH") + ICON_NAME_SECTION=$(printf '%s\n' "$ISSUE_BODY" | awk '/### Icon name/{flag=1; next} /^### /{flag=0} flag') - # Check title and body for blocked phrases - for PHRASE in "${BLOCKED_PHRASES[@]}" - do - if echo "$ISSUE_TITLE" | grep -i "$PHRASE"; then - gh issue close ${{ github.event.issue.number }} --reason "not planned" --comment "This looks like a duplicate, use the [search](https://github.com/lucide-icons/lucide/issues?q=is%3Aissue+$PHRASE) to find similar issues. + jq -r 'to_entries[] | "\(.key) \(.value)"' brand-stopwords.json | while read -r KEY VALUE; do + SAFE_KEY=$(printf '%s\n' "$KEY" | sed 's/[][\.^$*]/\\&/g') + SAFE_VALUE=$(printf '%s\n' "$VALUE" | sed 's/[][\.^$*]/\\&/g') - Read [our official statement about brand logos in Lucide](https://github.com/lucide-icons/lucide/blob/main/BRAND_LOGOS_STATEMENT.md). + if echo "$ISSUE_TITLE" | grep -iqE "$SAFE_KEY|$SAFE_VALUE" || \ + { [ -n "$ICON_NAME_SECTION" ] && echo "$ICON_NAME_SECTION" | grep -iqE "$SAFE_KEY|$SAFE_VALUE"; }; then + + gh issue close ${{ github.event.issue.number }} \ + --reason "not_planned" \ + --comment "It looks like this request is about **${VALUE}**, which is a brand logo. + + Lucide **does not accept** brand logos, and we do not plan to add them in the future. This is due to a combination of **legal restrictions**, **design consistency concerns**, and **practical maintenance reasons**. + + [Click here to read our official statement about brand logos in Lucide.](./BRAND_LOGOS_STATEMENT.md) + + You can [search for similar issues.](https://github.com/lucide-icons/lucide/issues?q=is%3Aissue+${VALUE}) + + We’re always happy to help on [Discord](https://discord.gg/EH6nSts)." - Always happy to help on [Discord](https://discord.gg/EH6nSts)." gh issue lock ${{ github.event.issue.number }} --reason spam - exit 1 + exit 0 fi done - env: - GH_TOKEN: ${{ github.token }} + +env: + GH_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 41cb26c26..41a9f0839 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,7 @@ docs/.vitepress/data/releaseMetaData docs/.vitepress/data/categoriesData.json docs/.vitepress/data/iconDetails docs/.vitepress/data/relatedIcons.json +docs/.vitepress/data/brandStopwords.json docs/.vercel docs/.nitro .gitignore - diff --git a/brand-stopwords.json b/brand-stopwords.json new file mode 100644 index 000000000..be5cb329a --- /dev/null +++ b/brand-stopwords.json @@ -0,0 +1,149 @@ +{ + "adobe": "Adobe", + "airplay": "AirPlay", + "amazon": "Amazon", + "angular": "Angular", + "aws": "AWS", + "azure": "Azure", + "bandcamp": "Bandcamp", + "behance": "Behance", + "bitbucket": "Bitbucket", + "blender": "Blender", + "bluesky": "BlueSky", + "bootstrap": "Bootstrap", + "brave": "Brave", + "chakra": "Chakra UI", + "chrome": "Chrome", + "codepen": "Codepen", + "codesandbox": "CodeSandbox", + "csharp": "C#", + "cypress": "Cypress", + "dart": "Dart", + "deezer": "Deezer", + "deno": "Deno", + "discord": "Discord", + "docker": "Docker", + "dribbble": "Dribbble", + "dropbox": "Dropbox", + "edge": "Edge", + "ember": "Ember", + "epic": "Epic Games", + "erlang": "Erlang", + "esbuild": "esbuild", + "eslint": "ESLint", + "facebook": "Facebook", + "figjam": "FigJam", + "figma": "Figma", + "firebase": "Firebase", + "firefox": "Firefox", + "framer": "Framer", + "gatsby": "Gatsby", + "gcp": "Google Cloud", + "github": "GitHub", + "gitlab": "GitLab", + "golang": "GoLang", + "google": "Google", + "gmail": "Gmail", + "gravatar": "Gravatar", + "haskell": "Haskell", + "instagram": "Instagram", + "java": "Java", + "javascript": "JavaScript", + "jest": "Jest", + "jira": "Jira", + "kotlin": "Kotlin", + "kubernetes": "Kubernetes", + "less": "Less", + "leetcode": "LeetCode", + "leet-code": "LeetCode", + "line": "LINE", + "linkedin": "LinkedIn", + "lua": "Lua", + "mariadb": "MariaDB", + "mcp": "MCP", + "messenger": "Messenger", + "microsoft": "Microsoft", + "mongodb": "MongoDB", + "mui": "Material UI", + "mysql": "MySQL", + "nestjs": "NestJS", + "netflix": "Netflix", + "netlify": "Netlify", + "next": "Next.js", + "nodejs": "Node.js", + "notion": "Notion", + "nostr": "Nostr", + "npm": "npm", + "nuxt": "Nuxt", + "opera": "Opera", + "oracle": "Oracle", + "patreon": "Patreon", + "paypal": "PayPal", + "perl": "Perl", + "php": "PHP", + "pinterest": "Pinterest", + "pix": "PiX", + "playstation": "PlayStation", + "playwright": "Playwright", + "pnpm": "pnpm", + "postcss": "PostCSS", + "postgresql": "PostgreSQL", + "prettier": "Prettier", + "prisma": "Prisma", + "python": "Python", + "qwik": "Qwik", + "react": "React", + "reddit": "Reddit", + "redis": "Redis", + "rollup": "Rollup", + "rust": "Rust", + "safari": "Safari", + "sass": "Sass", + "scala": "Scala", + "scss": "Sass", + "semantic": "Semantic UI", + "shopify": "Shopify", + "skype": "Skype", + "slack": "Slack", + "solid": "SolidJS", + "soundcloud": "SoundCloud", + "spotify": "Spotify", + "sqlite": "SQLite", + "squarespace": "Squarespace", + "steam": "Steam", + "stripe": "Stripe", + "substack": "Substack", + "supabase": "Supabase", + "surge": "Surge", + "svelte": "Svelte", + "swift": "Swift", + "tailwind": "Tailwind CSS", + "telegram": "Telegram", + "terraform": "Terraform", + "tesla": "Tesla", + "tidal": "Tidal", + "tiktok": "TikTok", + "trello": "Trello", + "twitch": "Twitch", + "twitter": "Twitter", + "typescript": "TypeScript", + "unity": "Unity", + "unreal": "Unreal Engine", + "vercel": "Vercel", + "vimeo": "Vimeo", + "vite": "Vite", + "vitest": "Vitest", + "vue": "Vue", + "webpack": "Webpack", + "wechat": "WeChat", + "whatsapp": "WhatsApp", + "windows": "Windows", + "wix": "Wix", + "x.com": "X.com", + "x-social": "X.com", + "xbox": "Xbox", + "yarn": "Yarn", + "youtube": "YouTube", + "zig": "Zig", + "zoom": "Zoom" +} diff --git a/docs/.vitepress/theme/components/icons/IconsCategoryOverview.vue b/docs/.vitepress/theme/components/icons/IconsCategoryOverview.vue index 355bc2685..b5b9882b2 100644 --- a/docs/.vitepress/theme/components/icons/IconsCategoryOverview.vue +++ b/docs/.vitepress/theme/components/icons/IconsCategoryOverview.vue @@ -1,19 +1,19 @@