-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtailwind.config.ts
140 lines (120 loc) · 3.35 KB
/
tailwind.config.ts
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
133
134
135
136
137
138
139
140
import fs from 'node:fs'
import path from 'node:path'
import { dynamicIconsPlugin, iconsPlugin } from '@egoist/tailwindcss-icons'
import {
cleanupSVG,
importDirectorySync,
isEmptyColor,
parseColors,
runSVGO,
} from '@iconify/tools'
import { compareColors, stringToColor } from '@iconify/utils/lib/colors'
import { generateFileName, isValidFontFile } from './src/utils/index'
import type { Config } from 'tailwindcss'
async function generateFontFamily(dir: string, prefix?: string): Promise<Record<string, string[]>> {
const files = await fs.promises.readdir(dir, { withFileTypes: true })
const fontFiles: Record<string, string[]> = {}
await Promise.all(
files.map(async (file) => {
const filePath = path.join(dir, file.name)
if (file.isDirectory()) {
const subFonts = await generateFontFamily(filePath, file.name)
Object.assign(fontFiles, subFonts)
}
else if (file.isFile() && isValidFontFile(file)) {
const name = generateFileName(file, prefix)
fontFiles[name.toLowerCase()] = [name]
}
}),
)
return fontFiles
}
function getCollections(dir: string) {
// Import icons
const iconSet = importDirectorySync(dir, {
includeSubDirs: false,
})
// Validate, clean up, fix palette and optimise
iconSet.forEachSync((name, type) => {
if (type !== 'icon')
return
const svg = iconSet.toSVG(name)
if (!svg) {
// Invalid icon
iconSet.remove(name)
return
}
// Clean up and optimise icons
try {
// Clean up icon code
cleanupSVG(svg)
// Change color to `currentColor`
// Skip this step if icon has hardcoded palette
const blackColor = stringToColor('black')!
const whiteColor = stringToColor('white')!
parseColors(svg, {
defaultColor: 'currentColor',
callback: (attr, colorStr, color) => {
if (!color) {
// Color cannot be parsed!
throw new Error(`Invalid color: "${colorStr}" in attribute ${attr}`)
}
if (isEmptyColor(color)) {
// Color is empty: 'none' or 'transparent'. Return as is
return color
}
// Change black to 'currentColor'
if (compareColors(color, blackColor))
return 'currentColor'
// Remove shapes with white color
if (compareColors(color, whiteColor))
return 'remove'
// Icon is not monotone
return color
},
})
// Optimise
runSVGO(svg)
}
catch (err) {
// Invalid icon
console.error(`Error parsing ${name}:`, err)
iconSet.remove(name)
return
}
// Update icon
iconSet.fromSVG(name, svg)
})
// Export
return iconSet.export()
}
export default {
theme: {
extend: {
fontFamily: {
...(await generateFontFamily('./src/fonts')),
},
},
},
plugins: [
// example: i-vue-logo
iconsPlugin({
// prefix: 'icon',
collections: {
vue: getCollections('./src/icons/vue'),
},
extraProperties: {
display: 'inline-block',
verticalAlign: 'middle',
},
}),
// example: icon-[heroicons--check-solid]
dynamicIconsPlugin({
prefix: 'iconify',
extraProperties: {
display: 'inline-block',
verticalAlign: 'middle',
},
}),
],
} satisfies Config