Skip to content

Instantly share code, notes, and snippets.

@cogk
Created September 20, 2023 19:10
Show Gist options
  • Save cogk/19a8c225c42278fb86e4c0c9ba7834da to your computer and use it in GitHub Desktop.
Save cogk/19a8c225c42278fb86e4c0c9ba7834da to your computer and use it in GitHub Desktop.
const SVGSpriter = require("svg-sprite");
const { readFile, writeFile } = require("fs");
const { promisify } = require("util");
const path = require("path");
const readFilePromise = promisify(readFile);
const writeFilePromise = promisify(writeFile);
// Common svg-sprite config options and their default values
/** @type {import("svg-sprite").Config} */
const config = {
dest: ".", // Main output directory
log: "", // Logging verbosity (default: no logging)
shape: {
// SVG shape related options
// transform: ['svgo'], // List of transformations / optimizations
meta: null, // Path to YAML file with meta / accessibility data
},
svg: {
// xmlDeclaration: true, // Add XML declaration to SVG sprite
// doctypeDeclaration: true, // Add DOCTYPE declaration to SVG sprite
// namespaceIDs: true, // Add namespace token to all IDs in SVG shapes
// namespaceIDPrefix: '', // Add a prefix to the automatically generated namespaceIDs
// namespaceClassnames: true, // Add namespace token to all CSS class names in SVG shapes
// dimensionAttributes: true // Width and height attributes on the sprite
},
mode: {
symbol: {
inline: true, // Prepare for inline embedding
},
},
};
// Get paths of all SVG files in the current directory
async function grabSources() {
const paths = ["./frappe/public/icons/timeless/icons.svg"];
const promises = paths.map(async (relativePath) => {
const file = path.resolve(relativePath);
const svg = await readFilePromise(file, "utf-8");
if (svg.includes("<symbol")) {
// Grab all <symbol>s and generate a sprite for each
const symbols = svg.split("<symbol").slice(1); // Ignore the start of the file
for (let i = 0; i < symbols.length; i++) {
let xml = symbols[i];
// Remove the closing tag
xml = xml.split("</symbol>")[0].trim();
// Remove xmlns attribute
xml = xml.replace(/xmlns="[^"]+"/, "");
// const viewBox = xml.match(/viewBox="([^"]+)"/)[1];
// xml = `<svg viewBox="${viewBox}"><g fill="none" stroke="none" ${xml}</g></svg>`;
xml = `<svg ${xml}</svg>`;
symbols[i] = xml;
}
const out = [];
for (const symbol of symbols) {
const name = symbol.match(/id="([^"]+)"/)[1];
out.push({ file: file + "#" + name, name: "#" + name, svg: symbol });
}
return out;
}
const name = null;
return { file, name, svg };
});
const sources = await Promise.all(promises);
return sources.flat();
}
async function main() {
// Create spriter instance (see below for `config` examples)
const spriter = new SVGSpriter(config);
// Add SVG source files
for (const source of await grabSources()) {
spriter.add(source.file, source.name, source.svg);
}
// Or compile the sprite async
const { result } = await spriter.compileAsync();
/* Write `result` files to disk (or do whatever with them ...) */
const resource = result.symbol.sprite;
await writeFilePromise("frappe/www/built.svg", resource.contents);
}
// eslint-disable-next-line no-console
main()
.then(() => {
console.log("Done");
})
.catch((e) => {
console.error(e);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment