-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerator.js
More file actions
132 lines (109 loc) · 3.56 KB
/
Copy pathgenerator.js
File metadata and controls
132 lines (109 loc) · 3.56 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
import fs from 'fs'
import path from 'path'
import axios from '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()
generateIndexFile()
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('src', 'types.ts'), typesFile)
}
function generateIndexFile() {
return fs.writeFileSync(path.join('src', 'index.ts'), '')
}
function appendToIndexFile(iconName) {
return fs.appendFileSync(
path.join('src', 'index.ts'),
`export * from './${iconName}.js'\n`,
)
}
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('src', `${name}.tsx`),
mapSVGToTemplate(name, svg),
)
await appendToIndexFile(name)
} 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.js'
export const ${name}: React.FC<IconProps> = ({ ...props }) => (
${svg}
)
`
}