Last active
January 15, 2024 17:50
Build Icon components (JSX, React, Vue, Svelte, SVG)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import path from 'node:path' | |
import fs from 'node:fs' | |
const jsxTemplate = (code)=>` | |
export default function ({width=16, height=16}) { | |
return ( | |
${code} | |
) | |
} | |
` | |
const vueTemplate = (code)=>` | |
<script setup> | |
defineProps({ | |
width: {type: Number, default: 16}, | |
height: {type: Number, default: 16}, | |
}) | |
</script> | |
<template> | |
${code} | |
</template> | |
` | |
const svelteTemplate = (code)=>` | |
<script> | |
export let width = 16; | |
export let height = 16; | |
</script> | |
${code} | |
` | |
function buildSvgString(svg, type/*: 'vue'|'svelte'|'jsx'|'html'*/ = 'jsx'){ | |
return type === 'vue' ? | |
svg.replace(/width="(\d+)"/, 'width={{width}}').replace(/height="(\d+)"/, 'height={{height}}') : | |
type !== 'html' ? | |
svg.replace(/width="(\d+)"/, 'width={width}').replace(/height="(\d+)"/, 'height={height}') : | |
svg | |
// svg.replace(/width="(\d+)"/, 'width="100%"').replace(/height="(\d+)"/, 'height="100%"') | |
} | |
const readDirRecursive = async (filePath) => { | |
const dir = await fs.promises.readdir(filePath); | |
const files = await Promise.all(dir.map(async relativePath => { | |
const absolutePath = path.join(filePath, relativePath); | |
const stat = await fs.promises.lstat(absolutePath); | |
return stat.isDirectory() ? readDirRecursive(absolutePath) : absolutePath; | |
})); | |
return files.flat(); | |
} | |
const dir = 'data' | |
const files = await readDirRecursive(dir) | |
if(!fs.existsSync('lib')) fs.mkdirSync('lib') | |
const jsxDir = 'lib/jsx' | |
if(!fs.existsSync(jsxDir)) fs.mkdirSync(jsxDir) | |
const vueDir = 'lib/vue' | |
if(!fs.existsSync(vueDir)) fs.mkdirSync(vueDir) | |
const svelteDir = 'lib/svelte' | |
if(!fs.existsSync(svelteDir)) fs.mkdirSync(svelteDir) | |
const svgDir = 'lib/svg' | |
if(!fs.existsSync(svelteDir)) fs.mkdirSync(svelteDir) | |
let jsxIndexFile = `` | |
let vueIndexFile = `` | |
let svelteIndexFile = `` | |
let svgIndexFile = `` | |
for (const file of files) { | |
if(!file.endsWith('.svg')) continue | |
const contents = fs.readFileSync(file, 'utf8').trim() | |
const jsx = jsxTemplate(buildSvgString(contents, 'jsx')).trim() | |
const vue = vueTemplate(buildSvgString(contents, 'vue')).trim() | |
const svelte = svelteTemplate(buildSvgString(contents, 'svelte')).trim() | |
const svg = buildSvgString(contents, 'html').trim() | |
let name = file.replace(/^data\//, '').replace('.svg', ''); | |
let jsxPath = jsxDir + '/' + name + '.jsx' | |
let vuePath = vueDir + '/' + name + '.vue' | |
let sveltePath = svelteDir + '/' + name + '.svelte' | |
let svgPath = svgDir + '/' + name + '.svg' | |
try { | |
fs.mkdirSync(jsxPath.split('/').slice(0, -1).join('/'), { recursive: true }) | |
fs.mkdirSync(vuePath.split('/').slice(0, -1).join('/'), { recursive: true }) | |
fs.mkdirSync(sveltePath.split('/').slice(0, -1).join('/'), { recursive: true }) | |
fs.mkdirSync(svgPath.split('/').slice(0, -1).join('/'), { recursive: true }) | |
} catch (error) {} | |
fs.writeFileSync(jsxPath, jsx) | |
fs.writeFileSync(vuePath, vue) | |
fs.writeFileSync(sveltePath, svelte) | |
fs.writeFileSync(svgPath, svg) | |
const componentName = name.replace(/[\/\\\-.@]/g, '_') // replace invalid characters / \\ - . @ | |
jsxIndexFile += `export { default as ${componentName} } from './${name}.jsx'\n` | |
vueIndexFile += `export { default as ${componentName} } from './${name}.vue'\n` | |
svelteIndexFile += `export { default as ${componentName} } from './${name}.svelte'\n` | |
svgIndexFile += `export { default as ${componentName} } from './${name}.svg'\n` | |
console.log(file) | |
} | |
fs.writeFileSync(jsxDir + '/index.js', jsxIndexFile) | |
fs.writeFileSync(vueDir + '/index.js', vueIndexFile) | |
fs.writeFileSync(svelteDir + '/index.js', svelteIndexFile) | |
fs.writeFileSync(svgDir + '/index.js', svgIndexFile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Make a directory named
data
and run the script withnode build-icon-components.js
in the same directory.This will create a folder named
libs
with the components that can be exported in a package.json like: