mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-22 01:46:51 +01:00
generate react icon components
This commit is contained in:
parent
8a2606185b
commit
0aafe28f85
@ -6,7 +6,9 @@ import fs from 'node:fs/promises'
|
||||
import ps from 'node:path/posix'
|
||||
import ora from 'ora'
|
||||
import chalk from 'chalk'
|
||||
import { toAstroComponent, toInnerSvg } from './svg.ts'
|
||||
import { toInnerSvg } from './svg.ts'
|
||||
import { toAstroComponent } from './toAstroComponent.ts'
|
||||
import { toReactComponent } from './toReactComponent.ts'
|
||||
|
||||
// Current directory.
|
||||
const currentDir = ps.resolve('.')
|
||||
@ -31,15 +33,21 @@ export async function generateIcons(distDir: string) {
|
||||
// clean the distribution directory
|
||||
await fs.rm(distDir, { force: true, recursive: true })
|
||||
await fs.mkdir(distDir, { recursive: true })
|
||||
await fs.mkdir(`${distDir}/react`, { recursive: true })
|
||||
|
||||
// copy the attribute typings file
|
||||
await fs.copyFile(
|
||||
ps.resolve(currentDir, 'scripts/create-icons/Props.d.ts'),
|
||||
ps.resolve(distDir, 'Props.d.ts')
|
||||
)
|
||||
await fs.copyFile(
|
||||
ps.resolve(currentDir, 'scripts/create-icons/Props.d.ts'),
|
||||
ps.resolve(`${distDir}/react`, 'Props.d.ts')
|
||||
)
|
||||
|
||||
// convert the SVG files into Astro components
|
||||
// convert the SVG files into Astro & React components
|
||||
let contentOfIndexJS = '// @ts-nocheck\n'
|
||||
let contentOfIndexReactJS = '// @ts-nocheck\n'
|
||||
|
||||
for (const src of srcDirs) {
|
||||
for (let filepath of await fs.readdir(src, { encoding: 'utf8' })) {
|
||||
@ -83,16 +91,33 @@ export async function generateIcons(distDir: string) {
|
||||
'utf8'
|
||||
)
|
||||
|
||||
// write the react component to a file
|
||||
await fs.writeFile(
|
||||
ps.resolve(`${distDir}/react`, `${baseName}.tsx`),
|
||||
toReactComponent(innerSVG, title),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
// add the astro component export to the main entry `index.ts` file
|
||||
contentOfIndexJS += `\nexport { default as ${baseName} } from './${baseName}.astro'`
|
||||
|
||||
// add the react component export to the main entry `react/index.ts` file
|
||||
contentOfIndexReactJS += `\nexport { Icon as ${baseName} } from './${baseName}.tsx'`
|
||||
|
||||
icons.push({ name, baseName, title })
|
||||
}
|
||||
}
|
||||
|
||||
// write the main entry `index.ts` file
|
||||
// write the main Astro entry `index.ts` file
|
||||
await fs.writeFile(ps.resolve(distDir, 'index.ts'), contentOfIndexJS, 'utf8')
|
||||
|
||||
// write the main React entry `react/index.ts` file
|
||||
await fs.writeFile(
|
||||
ps.resolve(`${distDir}/react`, 'index.ts'),
|
||||
contentOfIndexReactJS,
|
||||
'utf8'
|
||||
)
|
||||
|
||||
spinner.succeed(
|
||||
`${chalk.bold('[create-icons]')} Generated ${
|
||||
icons.length
|
||||
|
@ -1,43 +1,5 @@
|
||||
import { optimize as optimizeSVGNative } from 'svgo'
|
||||
|
||||
export const toAstroComponent = (innerSVG: string, title: string) => `---
|
||||
import type { Props } from './Props.ts';
|
||||
export type { Props };
|
||||
|
||||
let {
|
||||
size = '24px',
|
||||
title,
|
||||
width = size,
|
||||
height = size,
|
||||
...props
|
||||
}: Props = {
|
||||
'fill': 'none',
|
||||
'title': '${title}',
|
||||
'viewBox': '0 0 24 24',
|
||||
...Astro.props
|
||||
}
|
||||
|
||||
const toAttributeSize = (size: number | string) =>
|
||||
String(size).replace(/(?<=[0-9])x$/, 'em')
|
||||
|
||||
size = toAttributeSize(size)
|
||||
width = toAttributeSize(width)
|
||||
height = toAttributeSize(height)
|
||||
---
|
||||
<style is:global>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
stroke: currentcolor;
|
||||
stroke-width: var(--border-width);
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
fill: none;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
</style>
|
||||
<svg {width} {height} {...props} class="icon">{title ? (<title>{title}</title>) : ''}${innerSVG}</svg>`
|
||||
|
||||
export const toInnerSvg = (input: string) =>
|
||||
optimizeSVGNative(input, {
|
||||
plugins: [
|
||||
|
37
scripts/create-icons/toAstroComponent.ts
Normal file
37
scripts/create-icons/toAstroComponent.ts
Normal file
@ -0,0 +1,37 @@
|
||||
export const toAstroComponent = (innerSVG: string, title: string) => `---
|
||||
import type { Props } from './Props.d.ts';
|
||||
export type { Props };
|
||||
|
||||
let {
|
||||
size = '24px',
|
||||
title,
|
||||
width = size,
|
||||
height = size,
|
||||
...props
|
||||
}: Props = {
|
||||
'fill': 'none',
|
||||
'title': '${title}',
|
||||
'viewBox': '0 0 24 24',
|
||||
...Astro.props
|
||||
}
|
||||
|
||||
const toAttributeSize = (size: number | string) =>
|
||||
String(size).replace(/(?<=[0-9])x$/, 'em')
|
||||
|
||||
size = toAttributeSize(size)
|
||||
width = toAttributeSize(width)
|
||||
height = toAttributeSize(height)
|
||||
---
|
||||
<style is:global>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
stroke: currentcolor;
|
||||
stroke-width: var(--border-width);
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
fill: none;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
</style>
|
||||
<svg width={width} height={height} {...props} class="icon">{title ? (<title>{title}</title>) : ''}${innerSVG}</svg>`
|
35
scripts/create-icons/toReactComponent.ts
Normal file
35
scripts/create-icons/toReactComponent.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export const toReactComponent = (innerSVG: string, title: string) => `
|
||||
import type { Props } from './Props.d.ts';
|
||||
|
||||
export function Icon(props: Props) {
|
||||
let {
|
||||
size = '24px',
|
||||
title,
|
||||
width = size,
|
||||
height = size
|
||||
}: Props = {
|
||||
'title': '${title}',
|
||||
...props
|
||||
}
|
||||
|
||||
const toAttributeSize = (size: number | string) =>
|
||||
String(size).replace(/(?<=[0-9])x$/, 'em')
|
||||
|
||||
size = toAttributeSize(size)
|
||||
width = toAttributeSize(width)
|
||||
height = toAttributeSize(height)
|
||||
|
||||
const style = {
|
||||
'width': '1em',
|
||||
'height': '1em',
|
||||
'stroke': 'currentcolor',
|
||||
'strokeWidth': 'var(--border-width)',
|
||||
'strokeLinecap': 'round',
|
||||
'strokeLinejoin': 'round',
|
||||
'fill': 'none',
|
||||
'verticalAlign': 'baseline'
|
||||
}
|
||||
|
||||
return <svg width={width} height={height} fill="none" viewBox="0 0 24 24" {...props} style={style}>{title ? (<title>{title}</title>) : ''}${innerSVG}</svg>
|
||||
}
|
||||
`
|
Loading…
Reference in New Issue
Block a user