// generates src/styles/sidebar-icons.css from lucide-astro's icons. // sidebar entries opt in via `attrs: { "data-icon": "" }` in // astro.config.mjs. to add an icon, extend the map below and run: // // node scripts/gen-sidebar-icons.mjs import { readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; // data-icon name -> lucide-astro component const ICONS = { rocket: "Rocket", "at-sign": "AtSign", globe: "Globe", "life-buoy": "LifeBuoy", server: "Server", "hard-drive": "HardDrive", workflow: "Workflow", play: "Play", "key-round": "KeyRound", network: "Network", webhook: "Webhook", cable: "Cable", "arrow-up-circle": "ArrowUpCircle", hammer: "Hammer", "git-pull-request": "GitPullRequest", }; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const svgFor = (component) => { const source = readFileSync( join(root, "node_modules/lucide-astro/dist", `${component}.astro`), "utf8", ); const body = source .split("\n") .filter((line) => line.trim().startsWith("<") && !line.includes("Layout")) .map((line) => line.trim()) .join(""); return ( '' + body + "" ); }; let css = `/* GENERATED by scripts/gen-sidebar-icons.mjs — do not edit by hand */ #starlight__sidebar a[data-icon]::before { content: ""; display: inline-block; width: 1rem; height: 1rem; margin-inline-end: 0.4em; vertical-align: -0.19em; background-color: currentColor; -webkit-mask-size: 100%; mask-size: 100%; } `; for (const [name, component] of Object.entries(ICONS)) { const url = `url("data:image/svg+xml,${encodeURIComponent(svgFor(component))}")`; css += ` #starlight__sidebar a[data-icon="${name}"]::before { -webkit-mask-image: ${url}; mask-image: ${url}; } `; } writeFileSync(join(root, "src/styles/sidebar-icons.css"), css); console.log(`wrote src/styles/sidebar-icons.css (${Object.keys(ICONS).length} icons)`);