-
Notifications
You must be signed in to change notification settings - Fork 710
/
Copy pathtemplates.ts
116 lines (96 loc) · 3.86 KB
/
templates.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
import { fileURLToPath } from 'node:url'
import { kebabCase } from 'scule'
import { addTemplate, addTypeTemplate } from '@nuxt/kit'
import type { Nuxt, NuxtTemplate, NuxtTypeTemplate } from '@nuxt/schema'
import type { Resolver } from '@nuxt/kit'
import type { ModuleOptions } from './module'
import * as theme from './theme'
export function buildTemplates(options: ModuleOptions) {
return Object.entries(theme).reduce((acc, [key, component]) => {
acc[key] = typeof component === 'function' ? component(options as Required<ModuleOptions>) : component
return acc
}, {} as Record<string, any>)
}
export function getTemplates(options: ModuleOptions, uiConfig: Record<string, any>) {
const templates: NuxtTemplate[] = []
for (const component in theme) {
templates.push({
filename: `ui/${kebabCase(component)}.ts`,
write: true,
getContents: async () => {
const template = (theme as any)[component]
const result = typeof template === 'function' ? template(options) : template
const variants = Object.keys(result.variants || {})
let json = JSON.stringify(result, null, 2)
for (const variant of variants) {
json = json.replace(new RegExp(`("${variant}": "[^"]+")`, 'g'), '$1 as const')
json = json.replace(new RegExp(`("${variant}": \\[\\s*)((?:"[^"]+",?\\s*)+)(\\])`, 'g'), (_, before, match, after) => {
const replaced = match.replace(/("[^"]+")/g, '$1 as const')
return `${before}${replaced}${after}`
})
}
// For local development, directly import from theme
if (process.env.DEV) {
return [
`import template from ${JSON.stringify(fileURLToPath(new URL(`./theme/${kebabCase(component)}`, import.meta.url)))}`,
`const result = typeof template === 'function' ? template(${JSON.stringify(options)}) : template`,
`const json = ${json}`,
`export default result as typeof json`
].join('\n')
}
return `export default ${json}`
}
})
}
templates.push({
filename: 'ui/index.ts',
write: true,
getContents: () => Object.keys(theme).map(component => `export { default as ${component} } from './${kebabCase(component)}'`).join('\n')
})
// FIXME: `typeof colors[number]` should include all colors from the theme
templates.push({
filename: 'types/ui.d.ts',
getContents: () => `import * as ui from '#build/ui'
import type { DeepPartial } from '#ui/types/utils'
import colors from 'tailwindcss/colors'
const icons = ${JSON.stringify(uiConfig.icons)};
type NeutralColor = 'slate' | 'gray' | 'zinc' | 'neutral' | 'stone'
type Color = Exclude<keyof typeof colors, 'inherit' | 'current' | 'transparent' | 'black' | 'white' | NeutralColor>
type AppConfigUI = {
colors?: {
${options.theme?.colors?.map(color => `${color}?: Color`).join('\n\t\t')}
neutral?: NeutralColor
}
icons?: Partial<typeof icons>
} & DeepPartial<typeof ui>
declare module '@nuxt/schema' {
interface AppConfigInput {
ui?: AppConfigUI
}
}
export {}
`
})
templates.push({
filename: 'ui-image-component.ts',
write: true,
getContents: ({ app }) => {
const image = app?.components?.find(c => c.pascalName === 'NuxtImg' && !c.filePath.includes('nuxt/dist/app'))
return image ? `export { default } from "${image.filePath}"` : 'export default "img"'
}
})
return templates
}
export function addTemplates(options: ModuleOptions, nuxt: Nuxt, resolve: Resolver['resolve']) {
const templates = getTemplates(options, nuxt.options.appConfig.ui)
for (const template of templates) {
if (template.filename!.endsWith('.d.ts')) {
addTypeTemplate(template as NuxtTypeTemplate)
} else {
addTemplate(template)
}
}
nuxt.hook('prepare:types', ({ references }) => {
references.push({ path: resolve('./runtime/types/app.config.d.ts') })
})
}