From 9827d4af912045ec0b70fd9be631210b7de404a2 Mon Sep 17 00:00:00 2001 From: vaishnavs0 Date: Thu, 2 Apr 2026 11:19:37 +0530 Subject: [PATCH 1/4] improve: show icons in left sidebar --- docs/intro.md | 2 + docs/llm-gateway/_category_.json | 3 + docs/llm-gateway/architecture.md | 2 + docs/llm-gateway/features/_category_.json | 3 +- docs/llm-gateway/features/custom-intents.md | 2 + docs/llm-gateway/features/identity-aware.md | 2 + docs/llm-gateway/features/prompt-store.md | 1 + docs/llm-gateway/features/rate-limits.md | 2 + docs/llm-gateway/features/red-team-testing.md | 2 + docs/llm-gateway/features/request-routing.md | 2 + .../features/security-guardrails.md | 2 + docs/llm-gateway/features/token-saving.md | 1 + docs/llm-gateway/ha-and-sla.md | 1 + docs/llm-gateway/integration-guide.md | 2 + docs/llm-gateway/provider-support.md | 2 + docs/llm-gateway/quick-start.md | 2 + docs/llm-gateway/ux-changelog.md | 2 + docs/mcp-gateway/_category_.json | 3 + docs/mcp-gateway/architecture.md | 2 + docs/mcp-gateway/features/_category_.json | 3 +- docs/mcp-gateway/features/access-control.md | 2 + .../features/agents-configuration.md | 2 + docs/mcp-gateway/features/api-tokens.md | 2 + docs/mcp-gateway/features/mcp-library.md | 1 + docs/mcp-gateway/features/oauth-connect.md | 2 + .../features/security-guardrails.md | 2 + docs/mcp-gateway/features/tools-management.md | 2 + .../mcp-gateway/features/web-search-policy.md | 1 + docs/mcp-gateway/integration-guide.md | 2 + docs/mcp-gateway/quick-start.md | 2 + package-lock.json | 10 ++++ package.json | 1 + src/css/custom.css | 12 ++++ src/theme/DocSidebarItem/Category/index.js | 24 +++++++- src/theme/DocSidebarItem/Link/index.js | 11 +++- src/utils/sidebarIcons.js | 59 +++++++++++++++++++ 36 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 src/utils/sidebarIcons.js diff --git a/docs/intro.md b/docs/intro.md index f104436..460e7f0 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,6 +1,8 @@ --- sidebar_position: 1 slug: / +sidebar_custom_props: + icon: BookOpen --- # Welcome to QuilrAI Docs diff --git a/docs/llm-gateway/_category_.json b/docs/llm-gateway/_category_.json index 6b4abdf..e3a6bb5 100644 --- a/docs/llm-gateway/_category_.json +++ b/docs/llm-gateway/_category_.json @@ -4,5 +4,8 @@ "link": { "type": "generated-index", "description": "Unified API gateway for LLM providers - route, secure, monitor, and optimize all your LLM traffic through a single endpoint." + }, + "customProps": { + "icon": "BrainCircuit" } } diff --git a/docs/llm-gateway/architecture.md b/docs/llm-gateway/architecture.md index aaf389a..551c00b 100644 --- a/docs/llm-gateway/architecture.md +++ b/docs/llm-gateway/architecture.md @@ -1,5 +1,7 @@ --- sidebar_position: 2 +sidebar_custom_props: + icon: Layers --- # Architecture diff --git a/docs/llm-gateway/features/_category_.json b/docs/llm-gateway/features/_category_.json index 4ac44eb..3502eaa 100644 --- a/docs/llm-gateway/features/_category_.json +++ b/docs/llm-gateway/features/_category_.json @@ -6,6 +6,7 @@ "description": "Detailed documentation for each LLM Gateway capability - Routing, Token Saving, Guardrails, Prompt Store, Identity Aware, and more." }, "customProps": { - "badge": "new" + "badge": "new", + "icon": "Sparkles" } } diff --git a/docs/llm-gateway/features/custom-intents.md b/docs/llm-gateway/features/custom-intents.md index ff0ef07..3a33ae8 100644 --- a/docs/llm-gateway/features/custom-intents.md +++ b/docs/llm-gateway/features/custom-intents.md @@ -1,5 +1,7 @@ --- sidebar_position: 5 +sidebar_custom_props: + icon: Target --- # Custom Intents diff --git a/docs/llm-gateway/features/identity-aware.md b/docs/llm-gateway/features/identity-aware.md index 850ab57..dfa56a5 100644 --- a/docs/llm-gateway/features/identity-aware.md +++ b/docs/llm-gateway/features/identity-aware.md @@ -1,5 +1,7 @@ --- sidebar_position: 9 +sidebar_custom_props: + icon: Fingerprint --- # Identity Aware diff --git a/docs/llm-gateway/features/prompt-store.md b/docs/llm-gateway/features/prompt-store.md index 9097067..0fc58f1 100644 --- a/docs/llm-gateway/features/prompt-store.md +++ b/docs/llm-gateway/features/prompt-store.md @@ -2,6 +2,7 @@ sidebar_position: 7 sidebar_custom_props: badge: new + icon: MessageSquareText --- # Prompt Store diff --git a/docs/llm-gateway/features/rate-limits.md b/docs/llm-gateway/features/rate-limits.md index ead9e28..149e23c 100644 --- a/docs/llm-gateway/features/rate-limits.md +++ b/docs/llm-gateway/features/rate-limits.md @@ -1,5 +1,7 @@ --- sidebar_position: 6 +sidebar_custom_props: + icon: Gauge --- # Rate Limits diff --git a/docs/llm-gateway/features/red-team-testing.md b/docs/llm-gateway/features/red-team-testing.md index cadfe30..8f4c94a 100644 --- a/docs/llm-gateway/features/red-team-testing.md +++ b/docs/llm-gateway/features/red-team-testing.md @@ -1,5 +1,7 @@ --- sidebar_position: 8 +sidebar_custom_props: + icon: FlaskConical --- # Red Team Testing diff --git a/docs/llm-gateway/features/request-routing.md b/docs/llm-gateway/features/request-routing.md index b0235aa..e1b3f8b 100644 --- a/docs/llm-gateway/features/request-routing.md +++ b/docs/llm-gateway/features/request-routing.md @@ -1,5 +1,7 @@ --- sidebar_position: 1 +sidebar_custom_props: + icon: Route --- # Request Routing diff --git a/docs/llm-gateway/features/security-guardrails.md b/docs/llm-gateway/features/security-guardrails.md index 8458f33..162a484 100644 --- a/docs/llm-gateway/features/security-guardrails.md +++ b/docs/llm-gateway/features/security-guardrails.md @@ -1,5 +1,7 @@ --- sidebar_position: 4 +sidebar_custom_props: + icon: ShieldCheck --- # Security Guardrails diff --git a/docs/llm-gateway/features/token-saving.md b/docs/llm-gateway/features/token-saving.md index c0785b6..f13135d 100644 --- a/docs/llm-gateway/features/token-saving.md +++ b/docs/llm-gateway/features/token-saving.md @@ -2,6 +2,7 @@ sidebar_position: 2 sidebar_custom_props: badge: new + icon: Coins --- # Token Saving diff --git a/docs/llm-gateway/ha-and-sla.md b/docs/llm-gateway/ha-and-sla.md index 2c07038..03b9a12 100644 --- a/docs/llm-gateway/ha-and-sla.md +++ b/docs/llm-gateway/ha-and-sla.md @@ -2,6 +2,7 @@ sidebar_position: 3 sidebar_custom_props: badge: new + icon: Activity --- # HA & SLA diff --git a/docs/llm-gateway/integration-guide.md b/docs/llm-gateway/integration-guide.md index adf8487..8cf56d5 100644 --- a/docs/llm-gateway/integration-guide.md +++ b/docs/llm-gateway/integration-guide.md @@ -1,5 +1,7 @@ --- sidebar_position: 4 +sidebar_custom_props: + icon: Plug --- # Integration Guide diff --git a/docs/llm-gateway/provider-support.md b/docs/llm-gateway/provider-support.md index 7140a28..1b1508e 100644 --- a/docs/llm-gateway/provider-support.md +++ b/docs/llm-gateway/provider-support.md @@ -1,5 +1,7 @@ --- sidebar_position: 5 +sidebar_custom_props: + icon: Handshake --- # Provider Support diff --git a/docs/llm-gateway/quick-start.md b/docs/llm-gateway/quick-start.md index 79e0785..3036f94 100644 --- a/docs/llm-gateway/quick-start.md +++ b/docs/llm-gateway/quick-start.md @@ -1,5 +1,7 @@ --- sidebar_position: 1 +sidebar_custom_props: + icon: Rocket --- # Quick Start diff --git a/docs/llm-gateway/ux-changelog.md b/docs/llm-gateway/ux-changelog.md index 4303771..4a20c44 100644 --- a/docs/llm-gateway/ux-changelog.md +++ b/docs/llm-gateway/ux-changelog.md @@ -1,5 +1,7 @@ --- sidebar_position: 4 +sidebar_custom_props: + icon: ClipboardList --- # UX Changelog diff --git a/docs/mcp-gateway/_category_.json b/docs/mcp-gateway/_category_.json index 3cc6306..dd14358 100644 --- a/docs/mcp-gateway/_category_.json +++ b/docs/mcp-gateway/_category_.json @@ -4,5 +4,8 @@ "link": { "type": "generated-index", "description": "Enterprise-grade management layer for MCP servers - install, configure, secure, and monitor MCP integrations used by AI agents." + }, + "customProps": { + "icon": "Network" } } diff --git a/docs/mcp-gateway/architecture.md b/docs/mcp-gateway/architecture.md index d94b182..d35a5a4 100644 --- a/docs/mcp-gateway/architecture.md +++ b/docs/mcp-gateway/architecture.md @@ -1,5 +1,7 @@ --- sidebar_position: 2 +sidebar_custom_props: + icon: Layers --- # Architecture diff --git a/docs/mcp-gateway/features/_category_.json b/docs/mcp-gateway/features/_category_.json index 3737ad3..5b7ba28 100644 --- a/docs/mcp-gateway/features/_category_.json +++ b/docs/mcp-gateway/features/_category_.json @@ -6,6 +6,7 @@ "description": "Detailed documentation for each MCP Gateway capability - MCP Library, Tools Management, Guardrails, Access Control, and more." }, "customProps": { - "badge": "new" + "badge": "new", + "icon": "Sparkles" } } diff --git a/docs/mcp-gateway/features/access-control.md b/docs/mcp-gateway/features/access-control.md index c7bc4d4..565edd8 100644 --- a/docs/mcp-gateway/features/access-control.md +++ b/docs/mcp-gateway/features/access-control.md @@ -1,5 +1,7 @@ --- sidebar_position: 5 +sidebar_custom_props: + icon: Lock --- # Access Control diff --git a/docs/mcp-gateway/features/agents-configuration.md b/docs/mcp-gateway/features/agents-configuration.md index ac6ca9d..6c980da 100644 --- a/docs/mcp-gateway/features/agents-configuration.md +++ b/docs/mcp-gateway/features/agents-configuration.md @@ -1,5 +1,7 @@ --- sidebar_position: 3 +sidebar_custom_props: + icon: Bot --- # Agents Configuration diff --git a/docs/mcp-gateway/features/api-tokens.md b/docs/mcp-gateway/features/api-tokens.md index d5d24a3..b3306d3 100644 --- a/docs/mcp-gateway/features/api-tokens.md +++ b/docs/mcp-gateway/features/api-tokens.md @@ -1,5 +1,7 @@ --- sidebar_position: 6 +sidebar_custom_props: + icon: KeyRound --- # API Tokens diff --git a/docs/mcp-gateway/features/mcp-library.md b/docs/mcp-gateway/features/mcp-library.md index 48d3bd7..cf746c4 100644 --- a/docs/mcp-gateway/features/mcp-library.md +++ b/docs/mcp-gateway/features/mcp-library.md @@ -2,6 +2,7 @@ sidebar_position: 1 sidebar_custom_props: badge: new + icon: LibraryBig --- # MCP Library diff --git a/docs/mcp-gateway/features/oauth-connect.md b/docs/mcp-gateway/features/oauth-connect.md index fd544d7..5c6eaf7 100644 --- a/docs/mcp-gateway/features/oauth-connect.md +++ b/docs/mcp-gateway/features/oauth-connect.md @@ -1,5 +1,7 @@ --- sidebar_position: 7 +sidebar_custom_props: + icon: Link --- # OAuth Connect diff --git a/docs/mcp-gateway/features/security-guardrails.md b/docs/mcp-gateway/features/security-guardrails.md index 8a1c937..1fb8bf4 100644 --- a/docs/mcp-gateway/features/security-guardrails.md +++ b/docs/mcp-gateway/features/security-guardrails.md @@ -1,5 +1,7 @@ --- sidebar_position: 4 +sidebar_custom_props: + icon: ShieldCheck --- # Security Guardrails diff --git a/docs/mcp-gateway/features/tools-management.md b/docs/mcp-gateway/features/tools-management.md index 78f3769..4c1323f 100644 --- a/docs/mcp-gateway/features/tools-management.md +++ b/docs/mcp-gateway/features/tools-management.md @@ -1,5 +1,7 @@ --- sidebar_position: 2 +sidebar_custom_props: + icon: Wrench --- # Tools Management diff --git a/docs/mcp-gateway/features/web-search-policy.md b/docs/mcp-gateway/features/web-search-policy.md index b40642d..db72c44 100644 --- a/docs/mcp-gateway/features/web-search-policy.md +++ b/docs/mcp-gateway/features/web-search-policy.md @@ -2,6 +2,7 @@ sidebar_position: 8 sidebar_custom_props: badge: new + icon: Globe --- # Web Search Policy diff --git a/docs/mcp-gateway/integration-guide.md b/docs/mcp-gateway/integration-guide.md index 79366bb..d6d7882 100644 --- a/docs/mcp-gateway/integration-guide.md +++ b/docs/mcp-gateway/integration-guide.md @@ -1,5 +1,7 @@ --- sidebar_position: 3 +sidebar_custom_props: + icon: Plug --- # Integration Guide diff --git a/docs/mcp-gateway/quick-start.md b/docs/mcp-gateway/quick-start.md index 24b8773..aae7eb1 100644 --- a/docs/mcp-gateway/quick-start.md +++ b/docs/mcp-gateway/quick-start.md @@ -1,5 +1,7 @@ --- sidebar_position: 1 +sidebar_custom_props: + icon: Rocket --- # Quick Start diff --git a/package-lock.json b/package-lock.json index 24d066d..49740f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@fontsource/geist-mono": "^5.2.7", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", + "lucide-react": "^1.7.0", "prism-react-renderer": "^2.3.0", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -12676,6 +12677,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.7.0.tgz", + "integrity": "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", diff --git a/package.json b/package.json index 6704e65..92cda78 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@fontsource/geist-mono": "^5.2.7", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", + "lucide-react": "^1.7.0", "prism-react-renderer": "^2.3.0", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/src/css/custom.css b/src/css/custom.css index 91d2574..69c03bf 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -687,6 +687,18 @@ main > .container.padding-top--md.padding-bottom--lg, align-items: center; } +.sidebar-icon { + flex-shrink: 0; + width: 1rem; + height: 1rem; + stroke-width: 2; + color: var(--ifm-color-content-secondary); +} + +.menu__link--active > .sidebar-icon { + color: var(--ifm-color-primary); +} + .sidebar-link-label { overflow: hidden; text-overflow: ellipsis; diff --git a/src/theme/DocSidebarItem/Category/index.js b/src/theme/DocSidebarItem/Category/index.js index 85a47f8..5719f77 100644 --- a/src/theme/DocSidebarItem/Category/index.js +++ b/src/theme/DocSidebarItem/Category/index.js @@ -19,6 +19,7 @@ import { translate } from "@docusaurus/Translate"; import useIsBrowser from "@docusaurus/useIsBrowser"; import DocSidebarItems from "@theme/DocSidebarItems"; import DocSidebarItemLink from "@theme/DocSidebarItem/Link"; +import { getSidebarIcon } from "@site/src/utils/sidebarIcons"; function useAutoExpandActiveCategory({ isActive, @@ -106,7 +107,14 @@ function DocSidebarItemCategoryEmpty({ item, ...props }) { if (!isCategoryWithHref(item)) { return null; } - const { type, collapsed, collapsible, items, linkUnlisted, ...forwardableProps } = item; + const { + type, + collapsed, + collapsible, + items, + linkUnlisted, + ...forwardableProps + } = item; const linkItem = { type: "link", ...forwardableProps }; return ; } @@ -175,6 +183,7 @@ function DocSidebarItemCategoryCollapsible({ }; const badge = customProps?.badge; + const IconComponent = getSidebarIcon(customProps?.icon); return (
  • + {IconComponent && ( +
  • + {IconComponent && ( +
  • diff --git a/src/utils/sidebarIcons.js b/src/utils/sidebarIcons.js new file mode 100644 index 0000000..1b90cc2 --- /dev/null +++ b/src/utils/sidebarIcons.js @@ -0,0 +1,59 @@ +import { + BookOpen, + Network, + BrainCircuit, + Rocket, + Layers, + Sparkles, + LibraryBig, + Wrench, + Bot, + ShieldCheck, + Lock, + KeyRound, + Link, + Globe, + Plug, + Route, + Coins, + Target, + Gauge, + MessageSquareText, + FlaskConical, + Fingerprint, + Activity, + ClipboardList, + Handshake, +} from "lucide-react"; + +const iconMap = { + BookOpen, + Network, + BrainCircuit, + Rocket, + Layers, + Sparkles, + LibraryBig, + Wrench, + Bot, + ShieldCheck, + Lock, + KeyRound, + Link, + Globe, + Plug, + Route, + Coins, + Target, + Gauge, + MessageSquareText, + FlaskConical, + Fingerprint, + Activity, + ClipboardList, + Handshake, +}; + +export function getSidebarIcon(name) { + return iconMap[name] ?? null; +} From 0d102815a892d898ffaa1c378bf46996379f805f Mon Sep 17 00:00:00 2001 From: vaishnavs0 Date: Thu, 2 Apr 2026 11:49:30 +0530 Subject: [PATCH 2/4] added: pre commit hook and cursor rule --- .cursor/rules/docs-icons.mdc | 57 ++++++++++++++ .husky/pre-commit | 1 + package-lock.json | 17 +++++ package.json | 5 +- scripts/check-sidebar-icons.js | 135 +++++++++++++++++++++++++++++++++ 5 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 .cursor/rules/docs-icons.mdc create mode 100644 .husky/pre-commit create mode 100644 scripts/check-sidebar-icons.js diff --git a/.cursor/rules/docs-icons.mdc b/.cursor/rules/docs-icons.mdc new file mode 100644 index 0000000..e03ead3 --- /dev/null +++ b/.cursor/rules/docs-icons.mdc @@ -0,0 +1,57 @@ +--- +description: Enforce sidebar icons on all documentation pages and categories +globs: docs/**/*.md, docs/**/_category_.json +alwaysApply: false +--- + +# Sidebar Icon Requirement + +Every doc page and category MUST have a sidebar icon from `lucide-react`. + +## Markdown pages (`docs/**/*.md`) + +Add `sidebar_custom_props` with an `icon` in frontmatter: + +```yaml +--- +sidebar_position: 1 +sidebar_custom_props: + icon: Rocket +--- +``` + +## Category folders (`_category_.json`) + +Add `customProps` with an `icon`: + +```json +{ + "label": "Features", + "position": 3, + "customProps": { + "icon": "Sparkles" + } +} +``` + +## Available icons + +Only use icons registered in `src/utils/sidebarIcons.js`: + +BookOpen, Network, BrainCircuit, Rocket, Layers, Sparkles, LibraryBig, Wrench, Bot, ShieldCheck, Lock, KeyRound, Link, Globe, Plug, Route, Coins, Target, Gauge, MessageSquareText, FlaskConical, Fingerprint, Activity, ClipboardList, Handshake + +## Adding a new icon + +If none of the above fit: + +1. Import the icon from `lucide-react` in `src/utils/sidebarIcons.js` +2. Add it to `iconMap` +3. Use the exact export name as the icon value + +Browse https://lucide.dev/icons to find appropriate icons. + +## Rules + +- NEVER create a doc page or category without an icon +- Choose an icon that semantically matches the page content +- After adding a new icon to `sidebarIcons.js`, use it immediately in the page frontmatter or `_category_.json` diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..570c321 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +node scripts/check-sidebar-icons.js --staged diff --git a/package-lock.json b/package-lock.json index 49740f7..5252460 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "@docusaurus/types": "3.9.2", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/typography": "^0.5.19", + "husky": "^9.1.7", "tailwindcss": "^4.2.2" }, "engines": { @@ -11514,6 +11515,22 @@ "node": ">=10.17.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/hyperdyperid": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", diff --git a/package.json b/package.json index 92cda78..78571d5 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "clear": "docusaurus clear", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids" + "write-heading-ids": "docusaurus write-heading-ids", + "check-icons": "node scripts/check-sidebar-icons.js", + "prepare": "husky" }, "dependencies": { "@docusaurus/core": "3.9.2", @@ -32,6 +34,7 @@ "@docusaurus/types": "3.9.2", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/typography": "^0.5.19", + "husky": "^9.1.7", "tailwindcss": "^4.2.2" }, "browserslist": { diff --git a/scripts/check-sidebar-icons.js b/scripts/check-sidebar-icons.js new file mode 100644 index 0000000..67359b0 --- /dev/null +++ b/scripts/check-sidebar-icons.js @@ -0,0 +1,135 @@ +#!/usr/bin/env node + +const { execSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); + +const DOCS_DIR = path.resolve(__dirname, "../docs"); +const ICON_MAP_FILE = path.resolve( + __dirname, + "../src/utils/sidebarIcons.js" +); + +const stagedOnly = process.argv.includes("--staged"); + +function getRegisteredIcons() { + const content = fs.readFileSync(ICON_MAP_FILE, "utf8"); + const mapMatch = content.match(/const iconMap\s*=\s*\{([^}]+)\}/); + if (!mapMatch) { + console.error("Could not parse iconMap from sidebarIcons.js"); + process.exit(2); + } + return mapMatch[1] + .split(",") + .map((s) => s.trim()) + .filter(Boolean); +} + +function getStagedDocsFiles() { + const output = execSync("git diff --cached --name-only --diff-filter=ACM", { + encoding: "utf8", + }); + return output + .split("\n") + .map((f) => f.trim()) + .filter(Boolean) + .filter((f) => f.startsWith("docs/")) + .map((f) => path.resolve(__dirname, "..", f)); +} + +function walkDir(dir, pattern) { + let results = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + results = results.concat(walkDir(fullPath, pattern)); + } else if (pattern.test(entry.name)) { + results.push(fullPath); + } + } + return results; +} + +function extractFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return null; + + const yaml = match[1]; + const iconMatch = yaml.match(/^\s*icon:\s*(.+)$/m); + const hasSidebarCustomProps = /sidebar_custom_props:/.test(yaml); + + return { + hasSidebarCustomProps, + icon: iconMatch ? iconMatch[1].trim() : null, + }; +} + +const registeredIcons = getRegisteredIcons(); +const errors = []; + +let mdFiles; +let categoryFiles; + +if (stagedOnly) { + const staged = getStagedDocsFiles(); + mdFiles = staged.filter((f) => /\.mdx?$/.test(f)); + categoryFiles = staged.filter((f) => f.endsWith("_category_.json")); +} else { + mdFiles = walkDir(DOCS_DIR, /\.mdx?$/); + categoryFiles = walkDir(DOCS_DIR, /^_category_\.json$/); +} + +for (const file of mdFiles) { + const content = fs.readFileSync(file, "utf8"); + const fm = extractFrontmatter(content); + const rel = path.relative(process.cwd(), file); + + if (!fm) { + errors.push(`${rel}: missing frontmatter entirely`); + continue; + } + if (!fm.hasSidebarCustomProps || !fm.icon) { + errors.push(`${rel}: missing sidebar_custom_props.icon in frontmatter`); + continue; + } + if (!registeredIcons.includes(fm.icon)) { + errors.push( + `${rel}: icon "${fm.icon}" is not registered in src/utils/sidebarIcons.js` + ); + } +} + +for (const file of categoryFiles) { + const rel = path.relative(process.cwd(), file); + let json; + try { + json = JSON.parse(fs.readFileSync(file, "utf8")); + } catch { + errors.push(`${rel}: invalid JSON`); + continue; + } + if (!json.customProps?.icon) { + errors.push(`${rel}: missing customProps.icon`); + continue; + } + if (!registeredIcons.includes(json.customProps.icon)) { + errors.push( + `${rel}: icon "${json.customProps.icon}" is not registered in src/utils/sidebarIcons.js` + ); + } +} + +if (errors.length > 0) { + console.error("\n Sidebar icon check failed:\n"); + for (const err of errors) { + console.error(` - ${err}`); + } + console.error( + "\n Every doc page and category must have an icon from src/utils/sidebarIcons.js.\n" + + " See .cursor/rules/docs-icons.mdc for details.\n" + ); + process.exit(1); +} else { + const scope = stagedOnly ? "staged" : "all"; + console.log(` All ${scope} doc pages and categories have valid sidebar icons.`); +} From cc49949879914abc5faffb74a8c960c0ab053f32 Mon Sep 17 00:00:00 2001 From: vaishnavs0 Date: Thu, 2 Apr 2026 12:02:26 +0530 Subject: [PATCH 3/4] improve: use lucide react icons --- src/components/DocPageCopyDropdown/index.js | 70 ++----------------- src/components/HomepageFeatures/index.js | 15 ++-- src/components/SidebarThemeToggle/index.js | 66 ++--------------- src/css/custom.css | 20 ++---- src/theme/DocCard/index.js | 5 +- src/theme/DocSidebarItem/Category/index.js | 5 +- src/theme/Icon/Close/index.js | 18 ++--- src/theme/Icon/Menu/index.js | 16 ++--- src/theme/SearchBar/index.js | 21 +----- .../TOCCollapsible/CollapseButton/index.js | 6 ++ .../CollapseButton/styles.module.css | 21 +----- 11 files changed, 48 insertions(+), 215 deletions(-) diff --git a/src/components/DocPageCopyDropdown/index.js b/src/components/DocPageCopyDropdown/index.js index 6941dd7..4914e70 100644 --- a/src/components/DocPageCopyDropdown/index.js +++ b/src/components/DocPageCopyDropdown/index.js @@ -3,69 +3,7 @@ import { useDoc } from "@docusaurus/plugin-content-docs/client"; import { usePluginData } from "@docusaurus/useGlobalData"; import useBaseUrl from "@docusaurus/useBaseUrl"; import { AI_PROVIDERS, buildDocPageAiPrompt } from "@site/src/data/aiProviders"; - -function IconCopy(props) { - return ( - - - - - ); -} - -function IconCheck(props) { - return ( - - - - ); -} - -function IconChevron(props) { - return ( - - - - ); -} +import { Copy, Check, ChevronDown } from "lucide-react"; const menuItemCls = "flex w-full items-center group gap-3 rounded-md px-2.5 py-2 text-left no-underline! cursor-pointer border-none bg-transparent text-inherit font-inherit hover:bg-neutral-100 dark:hover:bg-neutral-900 disabled:opacity-45 disabled:cursor-not-allowed"; @@ -170,7 +108,7 @@ export default function DocPageCopyDropdown() { : "Markdown not available for this page" } > - {copiedMd ? : } + {copiedMd ? : } {copiedMd ? "Copied!" : "Copy page"} Ask AI - Structure guides, API notes, and examples in one place so teams can ship @@ -15,7 +16,7 @@ const FeatureList = [ }, { title: 'Organized by design', - Svg: require('@site/static/img/icon-stack.svg').default, + Icon: Layers, description: ( <> Sidebars, versioning, and search-friendly layouts help readers find the @@ -25,7 +26,7 @@ const FeatureList = [ }, { title: 'Easy to extend', - Svg: require('@site/static/img/icon-sparkle.svg').default, + Icon: Sparkles, description: ( <> Built on React and MDX—customize components and theme details when you @@ -35,11 +36,11 @@ const FeatureList = [ }, ]; -function Feature({Svg, title, description}) { +function Feature({Icon, title, description}) { return (
    - +
    {title} @@ -54,8 +55,8 @@ export default function HomepageFeatures() {
    - {FeatureList.map((props, idx) => ( - + {FeatureList.map(({Icon, ...rest}, idx) => ( + ))}
    diff --git a/src/components/SidebarThemeToggle/index.js b/src/components/SidebarThemeToggle/index.js index d6379ac..837eed1 100644 --- a/src/components/SidebarThemeToggle/index.js +++ b/src/components/SidebarThemeToggle/index.js @@ -1,64 +1,6 @@ import React from 'react'; import {useColorMode} from '@docusaurus/theme-common'; - -function IconSystem(props) { - return ( - - - - - ); -} - -function IconSun(props) { - return ( - - - - - ); -} - -function IconMoon(props) { - return ( - - - - ); -} +import {Monitor, Sun, Moon} from 'lucide-react'; export default function SidebarThemeToggle() { const {colorModeChoice, setColorMode} = useColorMode(); @@ -74,7 +16,7 @@ export default function SidebarThemeToggle() { onClick={() => setColorMode(null)} aria-pressed={colorModeChoice === null} title="System"> - +
    ); diff --git a/src/css/custom.css b/src/css/custom.css index 69c03bf..792f8d7 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -732,6 +732,10 @@ main > .container.padding-top--md.padding-bottom--lg, color var(--ifm-transition-fast) var(--ifm-transition-timing-default); } +.menu__list-item-collapsible .clean-btn.menu__caret::before { + display: none; +} + .menu__list-item-collapsible:has(.menu__link--active) .clean-btn.menu__caret { color: var(--color-emerald-700); } @@ -745,22 +749,6 @@ main > .container.padding-top--md.padding-bottom--lg, color: var(--color-emerald-400); } -.menu__list-item-collapsible .clean-btn.menu__caret::before { - width: 0.875rem; - height: 0.875rem; - background: none; - background-color: currentColor; - mask-image: var(--ifm-menu-link-sublist-icon); - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - -webkit-mask-image: var(--ifm-menu-link-sublist-icon); - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - -webkit-mask-size: contain; - filter: none; -} - /* ────────────────────────────────── Code blocks ─────────────────────── */ .theme-code-block { border: 1px solid var(--color-neutral-200); diff --git a/src/theme/DocCard/index.js b/src/theme/DocCard/index.js index f782847..26f3ce0 100644 --- a/src/theme/DocCard/index.js +++ b/src/theme/DocCard/index.js @@ -9,6 +9,7 @@ import {usePluralForm} from '@docusaurus/theme-common'; import isInternalUrl from '@docusaurus/isInternalUrl'; import {translate} from '@docusaurus/Translate'; import Heading from '@theme/Heading'; +import {FolderOpen, FileText, ExternalLink} from 'lucide-react'; import styles from './styles.module.css'; function useCategoryItemsPlural() { @@ -72,7 +73,7 @@ function CardCategory({item}) { } title={item.label} description={item.description ?? categoryItemsPlural(item.items.length)} /> @@ -80,7 +81,7 @@ function CardCategory({item}) { } function CardLink({item}) { - const icon = isInternalUrl(item.href) ? '📄️' : '🔗'; + const icon = isInternalUrl(item.href) ? : ; const doc = useDocById(item.docId ?? undefined); return ( + > + + ); } diff --git a/src/theme/Icon/Close/index.js b/src/theme/Icon/Close/index.js index bed0e15..cd5861a 100644 --- a/src/theme/Icon/Close/index.js +++ b/src/theme/Icon/Close/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import {X} from 'lucide-react'; export default function IconClose({ width = 22, @@ -8,22 +9,13 @@ export default function IconClose({ ...restProps }) { return ( - + {...restProps} + /> ); } diff --git a/src/theme/Icon/Menu/index.js b/src/theme/Icon/Menu/index.js index eb443d6..ff1d28e 100644 --- a/src/theme/Icon/Menu/index.js +++ b/src/theme/Icon/Menu/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import {Menu} from 'lucide-react'; export default function IconMenu({ width = 22, @@ -7,21 +8,12 @@ export default function IconMenu({ ...restProps }) { return ( - + {...restProps} + /> ); } diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js index 2601f93..bc7ab4e 100644 --- a/src/theme/SearchBar/index.js +++ b/src/theme/SearchBar/index.js @@ -3,24 +3,7 @@ import {createPortal} from 'react-dom'; import {useLocation} from '@docusaurus/router'; import useIsBrowser from '@docusaurus/useIsBrowser'; import OriginalSearchBar from '@theme-original/SearchBar'; - -function SearchIcon() { - return ( - - - - - ); -} +import {Search} from 'lucide-react'; function SearchModal({onClose, children}) { const overlayRef = useRef(null); @@ -111,7 +94,7 @@ export default function SearchBarWrapper(props) { onClick={() => setIsOpen(true)} type="button" aria-label="Search"> - + Search {isMac ? '⌘' : 'Ctrl'} diff --git a/src/theme/TOCCollapsible/CollapseButton/index.js b/src/theme/TOCCollapsible/CollapseButton/index.js index 9588855..51e4855 100644 --- a/src/theme/TOCCollapsible/CollapseButton/index.js +++ b/src/theme/TOCCollapsible/CollapseButton/index.js @@ -1,6 +1,7 @@ import React from 'react'; import clsx from 'clsx'; import Translate from '@docusaurus/Translate'; +import {ChevronDown} from 'lucide-react'; import styles from './styles.module.css'; export default function TOCCollapsibleCollapseButton({collapsed, ...props}) { @@ -22,6 +23,11 @@ export default function TOCCollapsibleCollapseButton({collapsed, ...props}) { On this page + ); } diff --git a/src/theme/TOCCollapsible/CollapseButton/styles.module.css b/src/theme/TOCCollapsible/CollapseButton/styles.module.css index 09e1501..1365aa9 100644 --- a/src/theme/TOCCollapsible/CollapseButton/styles.module.css +++ b/src/theme/TOCCollapsible/CollapseButton/styles.module.css @@ -12,7 +12,6 @@ align-items: center; padding: 0.4rem 0.8rem; width: 100%; - /* Chevron uses `currentColor` in ::after — match sidebar caret */ color: var(--color-neutral-400); } @@ -20,28 +19,14 @@ color: var(--ifm-font-color-base); } -/* Match sidebar `.menu__caret::before`: same SVG mask, no bitmap background */ -.tocCollapsibleButton::after { - content: ""; +.tocCollapsibleChevron { flex-shrink: 0; - width: 1.25rem; - height: 1.25rem; - background: none; - background-color: currentColor; - mask-image: var(--ifm-menu-link-sublist-icon); - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - -webkit-mask-image: var(--ifm-menu-link-sublist-icon); - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - -webkit-mask-size: contain; + color: currentColor; transform: rotate(180deg); transition: transform var(--ifm-transition-fast) var(--ifm-transition-timing-default); - filter: none; } -.tocCollapsibleButtonExpanded::after { +.tocCollapsibleButtonExpanded .tocCollapsibleChevron { transform: none; } From 1417355720a286baed8afd32dccee683b9b96677 Mon Sep 17 00:00:00 2001 From: vaishnavs0 Date: Thu, 2 Apr 2026 12:14:02 +0530 Subject: [PATCH 4/4] added fallback icon --- src/utils/sidebarIcons.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/sidebarIcons.js b/src/utils/sidebarIcons.js index 1b90cc2..e5ded46 100644 --- a/src/utils/sidebarIcons.js +++ b/src/utils/sidebarIcons.js @@ -24,6 +24,7 @@ import { Activity, ClipboardList, Handshake, + Hash, } from "lucide-react"; const iconMap = { @@ -55,5 +56,5 @@ const iconMap = { }; export function getSidebarIcon(name) { - return iconMap[name] ?? null; + return iconMap[name] ?? Hash; }