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.
102 lines
2.6 KiB
102 lines
2.6 KiB
2 years ago
|
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);
|
||
|
}
|
||
|
}
|