-
Notifications
You must be signed in to change notification settings - Fork 1
/
generator.js
120 lines (99 loc) · 3.33 KB
/
generator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const fs = require('fs')
const path = require('path')
const axios = require('axios')
const GOOGLE_FONTS_URL =
'https://fonts.google.com/metadata/icons?key=material_symbols&incomplete=true'
const ICON_FAMILIES = [
{ id: 'materialsymbolsoutlined', postfix: 'Outlined' },
{ id: 'materialsymbolsrounded', postfix: 'Rounded' },
{ id: 'materialsymbolssharp', postfix: 'Sharp' },
]
const getIncludedFamilies = (unsupportedFamilies) => {
const unsupportedFamilyIds = unsupportedFamilies.map((family) =>
family.replace(/\s+/g, '').toLowerCase(),
)
return ICON_FAMILIES.filter(
(family) => !unsupportedFamilyIds.includes(family.id),
)
}
;(async () => {
generatePropsFile()
const res = await axios.get(GOOGLE_FONTS_URL)
// remove )]}' from the response
const data = res.data.substring(4)
const icons = await JSON.parse(data)
for (let i = 0; i < icons.icons.length; i++) {
await generateComponentsForAllFamilies(icons.icons[i])
}
})()
function generatePropsFile() {
const typesFile = `
import React from 'react'
export interface IconProps extends React.SVGProps<SVGSVGElement> {
title?: string
}
`
fs.writeFileSync(path.join(__dirname, 'src', 'types.ts'), typesFile)
}
async function generateComponentsForAllFamilies(icon) {
const families = getIncludedFamilies(icon.unsupported_families)
for (let i = 0; i < families.length; i++) {
await Promise.all([
generateComponent(icon, families[i]),
generateComponent(icon, families[i], true),
])
}
}
async function generateComponent(icon, family, filled = false) {
try {
const name = formatName(icon.name, family.postfix, filled)
const svg = await downloadSVG(icon.name, family.id, filled)
console.log(`Downloading ${name}`)
await fs.writeFileSync(
path.join(__dirname, 'src', `${name}.tsx`),
mapSVGToTemplate(name, svg),
)
} catch {
console.log('Error generating component for', icon.name)
//process.abort()
}
}
function formatName(string, familyPostfix, filled) {
const formattedString = string
.replace(/_/g, ' ')
.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
})
.replace(/ /g, '')
return 'Icon' + formattedString + familyPostfix + (filled ? 'Filled' : '')
}
async function downloadSVG(icon, familyId, filled) {
const filledConfig = filled ? 'fill1' : 'default'
const svg = await axios
.get(
`https://fonts.gstatic.com/s/i/short-term/release/${familyId}/${icon}/${filledConfig}/24px.svg`,
)
.catch((err) => console.log(err))
return svg.data
.replace('height="24"', '')
.replace('width="24"', '{...props}')
.replace(/class/g, 'className')
.replace(/enable-background/g, 'enableBackground')
.replace(/clip-rule/g, 'clipRule')
.replace(/fill-rule/g, 'fillRule')
.replace('>', '>{props.title && <title>{props.title}</title>}')
.replace(/style="enableBackground:(.*?);?"/g, 'enableBackground="$1"')
.replace(/style="fill:(.*?);?"/g, 'fill="$1"')
.replace(/xmlns:xlink/g, 'xmlnsXlink')
.replace(/xlink:href/g, 'xlinkHref')
}
function mapSVGToTemplate(name, svg) {
return `
import React from 'react'
import { IconProps } from './types'
const ${name}: React.FC<IconProps> = ({ ...props }) => (
${svg}
)
export { ${name} as default }
`
}