tools/__tasks__/compile/images/icons.mjs (117 lines of code) (raw):

import { paths } from '../../config.mjs'; import fs from 'node:fs'; import path from 'node:path'; import glob from 'glob'; import btoa from 'btoa'; import { optimize, extendDefaultPlugins } from 'svgo'; import mkdirp from 'mkdirp'; import { fileURLToPath } from 'node:url'; const getSVG = (iconPath) => new Promise((resolve, reject) => { // eslint-disable-next-line consistent-return fs.readFile(iconPath, { encoding: 'utf-8' }, (err, data) => { if (err) return reject(err); try { resolve({ name: path.parse(iconPath).name, data: optimize(data, { plugins: [ { name: 'preset-default', params: { overrides: { removeViewBox: false, }, }, }, ], }), }); } catch (e) { return reject(e); } }); }); const sortSVGs = (svgs) => svgs.sort((a, b) => { const aInfo = a.data.info; const bInfo = b.data.info; if (aInfo.height !== bInfo.height) { return aInfo.height - bInfo.height; } else if (aInfo.width !== bInfo.width) { return bInfo.width - aInfo.width; } return a.name.localeCompare(b.name); }); const generateSassForSVG = (svg) => { const { name, data: fileData, data: { info: { width = 0, height = 0 }, }, } = svg; return ` %svg-i-${name}, .svg-i-${name} { background-image: url(data:image/svg+xml;base64,${btoa( fileData.data, )}); background-position: 0 0; width: ${width}px; height: ${height}px; } .svg .i-${name} { @extend %svg-i-${name} !optional; } `.replace(/ {8}/g, ''); }; const saveSass = (sass, dest, fileName) => new Promise((resolve, reject) => { fs.writeFile( path.join(dest, fileName), ` // THIS FILE WAS AUTOMATICALLY GENERATED BY // ${path.relative(paths.root, fileURLToPath(import.meta.url))} // DO NOT EDIT IT! @if ($svg-support) { ${sass} } ` .trim() .replace(/ {16}/g, ''), (err) => { if (err) return reject(err); return resolve(); }, ); }); /** @type {import('listr2').ListrTask} */ const task = { title: 'Create sprites', task: (ctx, task) => task.newListr( ['commercial', 'global', 'membership', 'video'].map((target) => ({ title: `Spriting ${target}`, task: () => { const srcPath = path.join(paths.src, 'images', target); const destPath = path.join( paths.src, 'stylesheets', 'icons', ); const fileName = `_${target}-icons-svg.scss`; const iconPaths = glob.sync(path.join(srcPath, '*.svg')); mkdirp.sync(destPath); return Promise.all(iconPaths.map(getSVG)) .then(sortSVGs) .then((svgs) => svgs.map(generateSassForSVG).join('').trim(), ) .then((sass) => saveSass(sass, destPath, fileName)); }, })), { concurrent: !!ctx.verbose ? false : true }, ), }; export default task;