2024-07-28 22:55:15 -06:00
|
|
|
import fs from "fs";
|
|
|
|
import path from "path";
|
|
|
|
import { optimize } from "svgo";
|
|
|
|
import { fileURLToPath } from "url";
|
|
|
|
import { dirname } from "path";
|
|
|
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
|
const __dirname = dirname(__filename);
|
|
|
|
|
|
|
|
const svgoConfig = {
|
|
|
|
plugins: [
|
|
|
|
{ name: "removeTitle", active: true },
|
|
|
|
{ name: "removeAttrs", params: { attrs: "(data-name)" } },
|
|
|
|
{ name: "removeDimensions", active: true },
|
|
|
|
{ name: "convertColors", params: { currentColor: true } },
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
const iconMetadataPath = path.resolve(__dirname, "./iconMetadata.json");
|
|
|
|
const iconMetadata = JSON.parse(fs.readFileSync(iconMetadataPath, "utf-8"));
|
|
|
|
|
2024-07-28 23:41:19 -06:00
|
|
|
const mapSvgAttributes = (svgContent) => {
|
|
|
|
return svgContent
|
|
|
|
.replace(/fill-rule/g, "fillRule")
|
|
|
|
.replace(/clip-rule/g, "clipRule");
|
|
|
|
};
|
|
|
|
|
2024-07-28 23:07:58 -06:00
|
|
|
const generateIconComponent = (
|
|
|
|
name,
|
|
|
|
svgContent,
|
|
|
|
description = "",
|
|
|
|
usage = ""
|
|
|
|
) => `
|
2024-07-28 22:55:15 -06:00
|
|
|
import * as React from 'react';
|
|
|
|
|
|
|
|
interface IconProps extends React.SVGAttributes<SVGElement> {
|
|
|
|
children?: never;
|
|
|
|
color?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ${description}
|
|
|
|
*
|
|
|
|
* @usage
|
|
|
|
* ${usage}
|
|
|
|
*/
|
|
|
|
export const ${name}Icon = React.forwardRef<SVGSVGElement, IconProps>(
|
|
|
|
({ color = 'currentColor', ...props }, forwardedRef) => {
|
|
|
|
return (
|
2024-07-28 23:41:19 -06:00
|
|
|
${mapSvgAttributes(svgContent).replace(
|
|
|
|
"<svg",
|
|
|
|
"<svg {...props} ref={forwardedRef}"
|
|
|
|
)}
|
2024-07-28 22:55:15 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
${name}Icon.displayName = '${name}Icon';
|
|
|
|
`;
|
|
|
|
|
|
|
|
const generateIndexFile = (components, iconType) => {
|
|
|
|
const exports = components
|
|
|
|
.map((name) => `export { ${name}Icon } from './${name}Icon';`)
|
|
|
|
.join("\n");
|
|
|
|
const indexPath = path.resolve(__dirname, `../src/${iconType}/index.ts`);
|
|
|
|
fs.writeFileSync(indexPath, exports, "utf-8");
|
|
|
|
};
|
|
|
|
|
|
|
|
const processIcons = async (iconType) => {
|
|
|
|
const svgDir = path.resolve(__dirname, `../src/svgs/${iconType}`);
|
|
|
|
const componentDir = path.resolve(__dirname, `../src/${iconType}`);
|
|
|
|
|
|
|
|
if (!fs.existsSync(componentDir)) {
|
|
|
|
fs.mkdirSync(componentDir, { recursive: true });
|
|
|
|
}
|
|
|
|
|
|
|
|
const components = [];
|
|
|
|
|
|
|
|
const files = fs.readdirSync(svgDir);
|
|
|
|
|
|
|
|
for (const file of files) {
|
|
|
|
const filePath = path.resolve(svgDir, file);
|
|
|
|
const svgContent = fs.readFileSync(filePath, "utf-8");
|
|
|
|
const { data } = await optimize(svgContent, svgoConfig);
|
|
|
|
|
|
|
|
const componentName = file
|
|
|
|
.replace(".svg", "")
|
|
|
|
.replace(/(^\w|-\w)/g, clearAndUpper);
|
|
|
|
const metadata = iconMetadata[componentName];
|
|
|
|
if (!metadata) {
|
2024-07-28 23:07:58 -06:00
|
|
|
console.warn(
|
|
|
|
`Metadata for ${componentName} not found, generating without metadata.`
|
|
|
|
);
|
2024-07-28 22:55:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
components.push(componentName);
|
|
|
|
const componentContent = generateIconComponent(
|
|
|
|
componentName,
|
|
|
|
data,
|
2024-07-28 23:07:58 -06:00
|
|
|
metadata ? metadata.description : "",
|
|
|
|
metadata ? metadata.usage : ""
|
2024-07-28 22:55:15 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
const componentPath = path.resolve(
|
|
|
|
componentDir,
|
|
|
|
`${componentName}Icon.tsx`
|
|
|
|
);
|
|
|
|
fs.writeFileSync(componentPath, componentContent, "utf-8");
|
|
|
|
}
|
|
|
|
|
|
|
|
generateIndexFile(components, iconType);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clearAndUpper = (text) => text.replace(/-/, "").toUpperCase();
|
|
|
|
|
|
|
|
(async () => {
|
|
|
|
await processIcons("solid");
|
|
|
|
await processIcons("outline");
|
|
|
|
})();
|