You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

101 lines
2.6 KiB

import glob from "fast-glob";
import path from "path";
import fs from "fs/promises";
import svgson from "svgson";
import { mkdir_to } from "../lib/builderator.js";
export const description = "Builds the sprite.svg sheet for icons based on the files in static/icons and what you use."
export const options = [
["--all-icons <glob>", "glob pattern with all .svg icons", "./static/icons/*.svg"],
["--sprite-sheet <filename>", "output sprite sheet with all icons", "./public/icon-sprites.svg"],
["--icons-index <filename>", "index.json file, be sure you know what you're doing", "./public/icons/index.json"],
["--prod-list <filename>", "JSON array file listing the icons to include for production"]
];
const load_svgs = async (svg_files) => {
const results = [];
// why use a for loop? because map don't async
for(let fname of svg_files) {
const name = path.basename(fname, ".svg");
const contents = (await fs.readFile(fname)).toString();
const parsed = await svgson.parse(contents);
results.push({name, contents, parsed });
}
return results;
}
const symbolize = (svgs) => {
const symbols = svgs.map(({name, parsed }) => {
return {
name: 'symbol',
type: 'element',
attributes: {
id: name,
viewBox: '0 0 24 24'
},
children: parsed.children,
}
});
return symbols;
}
const sprite_sheet = async (symbols) => {
const svg_doc = {
name: 'svg',
type: 'element',
attributes: {
xmlns: 'http://www.w3.org/2000/svg',
version: '1.1',
},
children: [
{
name: 'defs',
type: 'element',
children: symbols,
},
],
}
const xml_meta = `<?xml version="1.0" encoding="utf-8"?>\n`;
const svg_xml = await svgson.stringify(svg_doc);
return [xml_meta, svg_xml].join("");
}
export const main = async (opts) => {
// list the svg files
let svg_files;
if(opts.prodList) {
svg_files = JSON.parse(await fs.readFile(opts.prodList));
} else {
svg_files = glob.sync(opts.allIcons);
}
// load all of the icons from their svgs
const svg_contents = await load_svgs(svg_files);
// convert to linkable symbols
const symbols = symbolize(svg_contents);
// craft the svg doc
const svg_doc = await sprite_sheet(symbols);
// write out the sprite sheet
await fs.writeFile(opts.spriteSheet, svg_doc);
mkdir_to(opts.iconsIndex);
// write out the json sprite list
const sprite_list = svg_contents.map(({name}) => name);
await fs.writeFile(opts.iconsIndex, JSON.stringify(sprite_list));
if(!opts.dontExit) {
process.exit(0);
}
}