/
index.ts
118 lines (101 loc) · 3.24 KB
/
index.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
import type { Preset } from '@unocss/core'
import { toArray } from '@unocss/core'
import { GoogleFontsProvider } from './providers/google'
import { NoneProvider } from './providers/none'
import type { WebFontMeta, WebFontsOptions, WebFontsProviders } from './types'
export * from './types'
const layerName = '__webfonts__'
export function normalizedFontMeta(meta: WebFontMeta | string, defaultProvider: WebFontsProviders): WebFontMeta {
if (typeof meta !== 'string') {
meta.provider = meta.provider ?? defaultProvider
return meta
}
const [name, weights = ''] = meta.split(':')
return {
name,
weights: weights.split(/[,;]\s*/).filter(Boolean),
provider: defaultProvider,
}
}
const providers = {
google: GoogleFontsProvider,
none: NoneProvider,
}
const preset = (options: WebFontsOptions = {}): Preset<any> => {
const {
provider: defaultProvider = 'google',
extendTheme = true,
inlineImports = true,
themeKey = 'fontFamily',
} = options
const fontObject = Object.fromEntries(
Object.entries(options.fonts || {})
.map(([name, meta]) => [name, toArray(meta).map(m => normalizedFontMeta(m, defaultProvider))]),
)
const fonts = Object.values(fontObject).flatMap(i => i)
const importCache: Record<string, string> = {}
async function importUrl(url: string) {
if (inlineImports) {
if (!importCache[url]) {
try {
const { $fetch } = await import('ohmyfetch')
importCache[url] = await $fetch(url, { headers: {} })
}
catch (e) {
console.error('Failed to fetch web fonts')
console.error(e)
if (typeof process !== 'undefined' && process.env.CI)
throw e
}
}
return importCache[url]
}
else {
return `@import url('${url}')`
}
}
const preset: Preset<any> = {
name: '@unocss/preset-web-fonts',
layers: {
[layerName]: -20,
},
preflights: [
{
async getCSS() {
const names = new Set(fonts.map(i => i.provider || defaultProvider))
const preflights: (string | undefined)[] = []
for (const name of names) {
const fontsForProvider = fonts.filter(i => i.provider === name)
const provider = providers[name]
if (provider.getImportUrl) {
const url = provider.getImportUrl(fontsForProvider)
if (url)
preflights.push(await importUrl(url))
}
preflights.push(provider.getPreflight?.(fontsForProvider))
}
return preflights.filter(Boolean).join('\n')
},
layer: layerName,
},
],
}
if (extendTheme) {
preset.extendTheme = (theme) => {
if (!theme[themeKey])
theme[themeKey] = {}
const obj = Object.fromEntries(
Object.entries(fontObject)
.map(([name, fonts]) => [name, fonts.map(f => providers[f.provider || defaultProvider].getFontName(f))]),
)
for (const key of Object.keys(obj)) {
if (typeof theme[themeKey][key] === 'string')
theme[themeKey][key] = obj[key].map(i => `${i},`).join('') + theme[themeKey][key]
else
theme[themeKey][key] = obj[key].join(',')
}
}
}
return preset
}
export default preset