Skip to content

Instantly share code, notes, and snippets.

@JuKra00
Last active March 5, 2026 07:32
Show Gist options
  • Select an option

  • Save JuKra00/1bb0f5050eddc122e839d068bfba6300 to your computer and use it in GitHub Desktop.

Select an option

Save JuKra00/1bb0f5050eddc122e839d068bfba6300 to your computer and use it in GitHub Desktop.
Node script to generate sprite and kirby plugin for svg icons
#!/usr/bin/env node
import svgstore from "svgstore"
import fs from "node:fs/promises"
import path from "node:path"
import { glob } from "glob"
import { optimize } from "svgo"
import yargs from "yargs"
const color = {
magenta: (text) => `\x1b[35m${text}\x1b[0m`,
green: (text) => `\x1b[1;32m${text}\x1b[0m`,
red: (text) => `\x1b[31m${text}\x1b[0m`
}
const argv = yargs(process.argv.slice(2))
.usage("Usage: $0 -i [string] -o [string] -p [string]")
.demandOption(["i", "o"])
.describe("i", "Input path to folder containing .svg, e.g. src/svg/")
.describe("o", "Output path of sprite, e.g. public/sprite.svg")
.describe("p", "Project abbreviation, e.g. moinframe")
.default("p", "moinframe")
.help().argv
async function createSvgSprite(inputPath, outputPath, projectAbbreviation) {
try {
const files = await glob(path.join(process.cwd(), inputPath, "*.svg"))
const sprite = svgstore({
svgAttrs: {
style: "display: none;",
"aria-hidden": "true",
xmlns: "http://www.w3.org/2000/svg"
},
copyAttrs: ["width", "height"]
})
const panelIcons = {}
console.info(color.magenta("Transforming svgs to sprite"))
for (const filePath of files) {
const name = path.basename(filePath, ".svg")
console.info(`${name}.svg`)
const raw = await fs.readFile(filePath, "utf8")
const resized = raw
.replace(/width="\d*"/, 'width="100%"')
.replace(/height="\d*"/, 'height="100%"')
const { data } = optimize(resized, getOptimizationOptions())
const withTitle = data.replace(
/(<svg [^>]*>)/,
`$1<title id="${name}-icon">${name}</title>`
)
sprite.add(`symbol-${name}`, withTitle, {
symbolAttrs: {
"aria-labelledby": `${name}-icon`,
role: "img"
}
})
panelIcons[name] = withTitle
}
await createCmsPluginFile(panelIcons, projectAbbreviation)
await fs.writeFile(path.join(process.cwd(), outputPath), sprite.toString({ inline: true }))
console.info("")
console.info(color.green("All done!"))
} catch (error) {
console.error(color.red(`Error creating SVG sprite: ${error.message}`))
}
}
async function createCmsPluginFile(panelIcons, projectAbbreviation) {
const content = `panel.plugin('${projectAbbreviation}/icons', {
icons: ${JSON.stringify(panelIcons, null, 2)}
});`
const directoryPath = path.join(process.cwd(), `site/plugins/${projectAbbreviation}-icons`)
await fs.mkdir(directoryPath, { recursive: true })
await fs.writeFile(path.join(directoryPath, "index.js"), content)
console.info("")
console.info(color.magenta(`Added icons to panel using plugin "${projectAbbreviation}-icons"`))
}
function getOptimizationOptions() {
return {
plugins: [
{
name: "preset-default",
params: {
overrides: {}
}
},
{
name: "addCurrentColor",
fn: () => ({
element: {
enter: (node) => {
if (node.attributes.fill) {
node.attributes.fill = "currentColor"
}
if (node.attributes.stroke) {
node.attributes.stroke = "currentColor"
}
}
}
})
}
]
}
}
createSvgSprite(argv.i, argv.o, argv.p)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment