iconsax-astro
Version:
iconsax icon pack for Astro framework
206 lines (177 loc) • 5.72 kB
JavaScript
import { optimize as optimizeSvg } from 'svgo';
import fs from 'fs/promises';
import ps from 'path/posix';
const toAstroComponent = (svgColl, title) => `
---
export { Props } from './Props';
let {
size,
title,
color,
width = size,
height = size,
type,
fill = 'none',
stroke = 'none',
...props
} = {
'fill-rule': 'evenodd',
'title': '${title}',
'viewBox': '0 0 24 24',
...Astro.props
}
const styleDictionary = {
'bold': '${svgColl[0][1]}',
'broken': '${svgColl[1][1]}',
'bulk': '${svgColl[2][1]}',
'linear': '${svgColl[3][1]}',
'outline': '${svgColl[4][1]}',
'twotone': '${svgColl[5][1]}'
}
switch (type) {
case 'bold':
case 'bulk':
case 'outline':
fill = color;
break;
case 'broken':
case 'linear':
case 'twotone':
stroke = color;
break;
default:
stroke = color;
break;
}
const toAttributeSize = (size: number) => String(size).replace(/(?<=[0-9])x$/, 'em');
if (!size) {
size = '24px';
width = size;
height = size;
}
size = toAttributeSize(size);
width = toAttributeSize(width);
height = toAttributeSize(height);
let svg = '<title>${title}</title>';
svg += styleDictionary[type] ? styleDictionary[type] : styleDictionary['linear'];
---
<svg set:html={svg} width={width} height={height} fill={fill} stroke={stroke} {...props}></svg>
`;
const toInnerSvg = (input) =>
optimizeSvg(input, {
plugins: [
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeXMLNS',
'removeEditorsNSData',
'cleanupAttrs',
'minifyStyles',
'convertStyleToAttrs',
'cleanupIds',
'removeRasterImages',
'removeUselessDefs',
'cleanupNumericValues',
'cleanupListOfValues',
'convertColors',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeViewBox',
'cleanupEnableBackground',
'removeHiddenElems',
'removeEmptyText',
'convertShapeToPath',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
'convertPathData',
'convertTransform',
'removeEmptyAttrs',
'removeEmptyContainers',
'mergePaths',
'removeUnusedNS',
'sortAttrs',
'removeTitle',
'removeDesc',
'removeDimensions',
'removeStyleElement',
'removeScriptElement',
],
})
.data.replace(/^<svg[^>]*>|<\/svg>$/g, '')
.replace(/ fill="#292D32"/g, '')
.replace(/ stroke="#292D32"/g, '')
.replace(/ fill="#000"/g, '')
.replace(/ stroke="#000"/g, '')
.replace(/ (clip|fill)-rule="evenodd"/g, '')
.replace(/\/>/g, ' />');
// paths
const currentDir = ps.resolve('.'); // current directory
const iconsDir = ps.resolve(currentDir, 'icons'); // icons directory
const distDir = ps.resolve(currentDir, 'dist'); // distribution directory
// Content of the main entry `index.ts` file
let contentOfIndexJS = '';
// clean the distribution directory
await fs.rm(distDir, { force: true, recursive: true });
await fs.mkdir(distDir, { recursive: true });
// icons data
const icons = [];
// copy the attribute typings file
await fs.copyFile(ps.resolve(currentDir, 'Props.ts'), ps.resolve(distDir, 'Props.ts'));
// convert the SVG files into Astro components
for (let filepath of await fs.readdir(iconsDir, { encoding: 'utf8' })) {
console.log('Handling', filepath, '...');
// read each child folder
const childDir = ps.resolve(iconsDir, filepath);
if ((await fs.stat(childDir)).isDirectory()) {
// base name of the icon is a name of the folder
const name = filepath;
// format the title
const title = name
.replace(
// uppercase alphabetic characters after the start or a dash
/(?<=^|-)([a-z])/g,
(_0, $1) => $1.toUpperCase(),
)
.replace(
// replace non-alphanumeric characters with space
/[^A-Za-z0-9]+/g,
' ',
);
// base name is the title without spaces
const baseName = title.replace(/ /g, '');
// collection of icon types (bold, broken, bulk, linear, outline, twotone)
let svgCollection = [];
// read icons from the child folder
for (let childFilepath of await fs.readdir(childDir, { encoding: 'utf8' })) {
if (!childFilepath.endsWith('.svg')) continue;
// get full path of the icon
childFilepath = ps.resolve(childDir, childFilepath);
// generate inner content of the SVG
const innerSvg = toInnerSvg(await fs.readFile(childFilepath, 'utf8'));
// get the icon type
const type = ps.basename(childFilepath, '.svg');
// add the icon to the collection
svgCollection.push([type, innerSvg]);
// sort the collection by the icon type
svgCollection.sort((a, b) => a[0].localeCompare(b[0]));
}
// generate the Astro component
await fs.writeFile(
ps.resolve(distDir, `${baseName}.astro`),
toAstroComponent(svgCollection, title),
'utf8',
);
// add the Astro component to the index file
contentOfIndexJS += `export { default as ${baseName} } from './${baseName}.astro';\n`;
// add the icon to the list
icons.push({ name, title, baseName });
}
}
// write to the main entry `index.ts` file
await fs.writeFile(ps.resolve(distDir, 'index.ts'), contentOfIndexJS, 'utf8');
// copy types.d.ts file
await fs.copyFile(ps.resolve(currentDir, 'types.d.ts'), ps.resolve(distDir, 'types.d.ts'));
console.log('Build completed successfully.');