@movk/nuxt-docs 1.3.12 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.config.ts +9 -7
- package/app/app.vue +4 -2
- package/app/components/content/CommitChangelog.vue +1 -1
- package/app/components/header/HeaderLogo.vue +2 -54
- package/app/components/theme-picker/ThemePicker.vue +273 -6
- package/app/error.vue +3 -1
- package/app/plugins/theme.ts +29 -0
- package/app/utils/theme.ts +136 -0
- package/nuxt.config.ts +11 -0
- package/package.json +6 -6
- package/server/api/github/commits.get.ts +35 -18
package/app/app.config.ts
CHANGED
|
@@ -2,19 +2,21 @@ import type { ButtonProps } from '@nuxt/ui'
|
|
|
2
2
|
|
|
3
3
|
export default defineAppConfig({
|
|
4
4
|
toaster: {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
position: 'bottom-right' as const,
|
|
6
|
+
duration: 5000,
|
|
7
|
+
max: 5,
|
|
8
|
+
expand: true
|
|
9
9
|
},
|
|
10
10
|
theme: {
|
|
11
11
|
radius: 0.25,
|
|
12
|
-
blackAsPrimary: false
|
|
12
|
+
blackAsPrimary: false,
|
|
13
|
+
icons: 'lucide',
|
|
14
|
+
font: 'Public Sans'
|
|
13
15
|
},
|
|
14
16
|
ui: {
|
|
15
17
|
colors: {
|
|
16
|
-
primary: '
|
|
17
|
-
neutral: '
|
|
18
|
+
primary: 'green',
|
|
19
|
+
neutral: 'slate'
|
|
18
20
|
},
|
|
19
21
|
contentNavigation: {
|
|
20
22
|
slots: {
|
package/app/app.vue
CHANGED
|
@@ -13,6 +13,7 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
|
|
13
13
|
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
|
14
14
|
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
|
15
15
|
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
|
16
|
+
const font = computed(() => `:root { --font-sans: '${appConfig.theme.font}', sans-serif; }`)
|
|
16
17
|
|
|
17
18
|
useHead({
|
|
18
19
|
meta: [
|
|
@@ -21,7 +22,8 @@ useHead({
|
|
|
21
22
|
],
|
|
22
23
|
style: [
|
|
23
24
|
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
|
24
|
-
{ innerHTML: blackAsPrimary, id: 'nuxt-ui-black-as-primary', tagPriority: -2 }
|
|
25
|
+
{ innerHTML: blackAsPrimary, id: 'nuxt-ui-black-as-primary', tagPriority: -2 },
|
|
26
|
+
{ innerHTML: font, id: 'nuxt-ui-font', tagPriority: -2 }
|
|
25
27
|
]
|
|
26
28
|
})
|
|
27
29
|
|
|
@@ -55,7 +57,7 @@ provide('navigation', rootNavigation)
|
|
|
55
57
|
<Footer />
|
|
56
58
|
|
|
57
59
|
<ClientOnly>
|
|
58
|
-
<LazyUContentSearch :files="files" :navigation="rootNavigation" :fuse="{ resultLimit: 1000 }"/>
|
|
60
|
+
<LazyUContentSearch :files="files" :navigation="rootNavigation" :fuse="{ resultLimit: 1000 }" />
|
|
59
61
|
</ClientOnly>
|
|
60
62
|
</template>
|
|
61
63
|
</div>
|
|
@@ -55,7 +55,7 @@ const filePath = computed(() => {
|
|
|
55
55
|
|
|
56
56
|
const { data: commits } = await useLazyFetch<Commit[]>('/api/github/commits', {
|
|
57
57
|
key: `commit-changelog-${props.name ?? routeName.value}-${props.author ?? 'all'}`,
|
|
58
|
-
query: { path: filePath.value, author: props.author }
|
|
58
|
+
query: { path: [filePath.value], author: props.author }
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
// 格式化提交消息
|
|
@@ -1,57 +1,5 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
const { header } = useAppConfig()
|
|
3
|
-
</script>
|
|
4
|
-
|
|
5
1
|
<template>
|
|
6
|
-
<NuxtLink
|
|
7
|
-
:
|
|
8
|
-
class="flex items-center gap-2 font-bold text-xl text-highlighted min-w-0 focus-visible:outline-primary shrink-0"
|
|
9
|
-
:aria-label="header.title"
|
|
10
|
-
>
|
|
11
|
-
<svg
|
|
12
|
-
width="256"
|
|
13
|
-
height="256"
|
|
14
|
-
viewBox="0 0 256 256"
|
|
15
|
-
fill="none"
|
|
16
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
-
class="w-auto h-10 shrink-0"
|
|
18
|
-
>
|
|
19
|
-
<circle
|
|
20
|
-
cx="128"
|
|
21
|
-
cy="128"
|
|
22
|
-
r="120"
|
|
23
|
-
fill="var(--ui-primary)"
|
|
24
|
-
/>
|
|
25
|
-
<g fill="white" opacity="0.95">
|
|
26
|
-
<path
|
|
27
|
-
d="M38.5 175.6 c-1.5 -1 -1.9 -2.7 -1.9 -7.7 0 -5.5 0.4 -7.1 3.1 -11.4 1.8 -2.7 4.8 -6.3 6.8 -7.8 1.9 -1.5 3.5 -3.2 3.5 -3.8 0 -1.2 -5.8 -0.4 -11.5 1.6 -11.7 4.1 -16.3 3.7 -19 -1.5 -2.6 -5 -1.2 -8.4 4.2 -11 6.6 -3.1 10.4 -3.5 14.3 -1.5 2.1 1.1 4.1 1.4 5.9 0.9 1.4 -0.4 3.5 -0.9 4.6 -1.1 4.9 -0.9 12.3 -3.8 16 -6.3 13.7 -9.4 18.6 -11.7 34 -16 6.6 -1.9 11.9 -2.4 31.3 -3.1 l23.4 -0.8 8.4 -8.5 c5.7 -5.8 9.5 -8.8 11.9 -9.5 1.9 -0.5 5.8 -2.4 8.7 -4.1 4.5 -2.8 5.4 -3 7.5 -1.9 2 1.1 2.9 0.9 6.2 -0.9 6.4 -3.6 7.6 -2.5 4.4 4.3 l-1.7 3.5 3.3 4.1 c2.8 3.5 3.2 4.6 2.7 7.7 -0.3 2 0 5.1 0.6 6.8 1.8 5 -0.4 8.9 -6.3 11.6 -2.9 1.4 -4.5 2.6 -4 3.3 0.4 0.5 1.6 3.5 2.6 6.5 2.8 8.8 1.9 8.2 13.5 8.5 10.2 0.2 21.7 1.9 25.3 3.7 2 1 2.3 5.1 0.3 6.7 -0.7 0.6 -5.1 1.5 -9.7 2.1 -4.6 0.5 -12.7 1.9 -17.9 3 -8.5 1.8 -12.8 2 -42 1.9 -17.9 -0.1 -35 -0.3 -38 -0.5 -3 -0.1 -10.7 -0.6 -17.1 -1 -9.7 -0.6 -12.4 -0.4 -17 1.1 -7.2 2.3 -7.3 2.4 -5.5 4.4 2.2 2.5 3.1 7.8 1.6 9.6 -2.7 3.3 -9.3 1.2 -17.4 -5.5 -5.6 -4.7 -8.8 -5 -15.6 -1.7 -4.4 2.2 -4.5 2.3 -4.8 7.6 -0.2 3.7 -0.9 5.9 -2 6.8 -2.3 1.7 -10.3 1.6 -12.7 -0.1z"
|
|
28
|
-
/>
|
|
29
|
-
</g>
|
|
30
|
-
<g fill="white" opacity="0.98">
|
|
31
|
-
<path
|
|
32
|
-
d="M142 209.3 c-0.7 -1.6 -2.3 -5.7 -3.5 -9.3 -1.3 -3.6 -2.6 -7.2 -3 -8.1 -0.4 -1.1 0 -1.8 1.4 -2.2 1.7 -0.4 2.4 0.4 4.3 5.4 1.3 3.2 2.5 5.9 2.8 5.9 0.3 0 1.9 -2.6 3.5 -5.8 2.1 -4 3.7 -5.8 5.3 -6 1.2 -0.2 2.2 -0.1 2.2 0.3 0 0.5 -10.8 21.5 -11.5 22.3 -0.1 0.1 -0.8 -1 -1.5 -2.5z"
|
|
33
|
-
/>
|
|
34
|
-
<path
|
|
35
|
-
d="M84.5 201.3 c1 -12.9 1.6 -13.8 4.8 -6.9 1.5 3.1 2.9 5.6 3.3 5.6 0.3 0 3.1 -2.2 6.2 -5 3 -2.7 5.7 -4.8 5.9 -4.7 0.3 0.4 3.1 19.1 2.9 19.4 -0.1 0.2 -1.3 0.4 -2.7 0.5 -2.2 0.3 -2.4 0 -2.7 -4.9 -0.2 -2.9 -0.6 -5.3 -0.9 -5.3 -0.3 0 -2.3 1.4 -4.4 3.1 -3.7 2.9 -4.1 3 -5.8 1.5 -1.7 -1.6 -1.9 -1.6 -2.5 -0.1 -0.3 0.9 -0.6 2.8 -0.6 4.1 0 1.8 -0.5 2.4 -2.1 2.4 -2 0 -2.1 -0.3 -1.4 -9.7z"
|
|
36
|
-
/>
|
|
37
|
-
<path
|
|
38
|
-
d="M115.9 209.5 c-5.9 -3.2 -6.4 -12.8 -0.9 -17.7 3.4 -3.1 5.6 -3.4 10.3 -1.5 4.3 1.8 5.9 4 6 7.9 0.1 6.4 -1.2 10.4 -3.9 11.6 -3.3 1.6 -8.3 1.4 -11.5 -0.3z m9.6 -4.5 c2.1 -2.4 2.4 -7.2 0.5 -9.4 -2 -2.5 -7.7 -2.1 -9.1 0.6 -3.9 7.3 3.3 14.7 8.6 8.8z"
|
|
39
|
-
/>
|
|
40
|
-
<path
|
|
41
|
-
d="M158 200 c0 -11 0 -11 2.4 -11 2.3 0 2.4 0.3 1.9 3.6 -0.6 3.5 -0.5 3.6 1.6 2.5 1.2 -0.7 2.7 -2 3.3 -3.1 0.9 -1.4 1.5 -1.6 2.6 -0.8 1 0.9 0.6 1.9 -2.5 5 l-3.8 3.9 2.5 1.9 c1.4 1.1 3.7 2.5 5.3 3.2 3 1.4 3.3 2.1 1.4 3.6 -0.9 0.8 -2.4 0.3 -5.7 -1.9 l-4.5 -3.1 -0.3 3.6 c-0.3 2.8 -0.8 3.6 -2.3 3.6 -1.8 0 -1.9 -0.8 -1.9 -11z"
|
|
42
|
-
/>
|
|
43
|
-
</g>
|
|
44
|
-
<circle
|
|
45
|
-
cx="128"
|
|
46
|
-
cy="128"
|
|
47
|
-
r="118"
|
|
48
|
-
stroke="white"
|
|
49
|
-
stroke-width="1.5"
|
|
50
|
-
fill="none"
|
|
51
|
-
opacity="0.15"
|
|
52
|
-
/>
|
|
53
|
-
</svg>
|
|
54
|
-
|
|
55
|
-
<p class="font-medium text-highlighted">{{ header.title }}</p>
|
|
2
|
+
<NuxtLink to="/">
|
|
3
|
+
<UUser :avatar="{ src: 'https://docs.mhaibaraai.cn/avatar.png' }" name="Movk Nuxt Docs" />
|
|
56
4
|
</NuxtLink>
|
|
57
5
|
</template>
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { omit } from '@movk/core'
|
|
3
3
|
import colors from 'tailwindcss/colors'
|
|
4
|
+
import { useClipboard } from '@vueuse/core'
|
|
5
|
+
import { themeIcons } from '../../utils/theme'
|
|
4
6
|
|
|
5
7
|
const appConfig = useAppConfig()
|
|
6
8
|
const colorMode = useColorMode()
|
|
7
9
|
const site = useSiteConfig()
|
|
8
10
|
|
|
11
|
+
const { copy: copyCSS, copied: copiedCSS } = useClipboard()
|
|
12
|
+
const { copy: copyAppConfig, copied: copiedAppConfig } = useClipboard()
|
|
13
|
+
|
|
9
14
|
const neutralColors = ['slate', 'gray', 'zinc', 'neutral', 'stone']
|
|
10
15
|
const neutral = computed({
|
|
11
16
|
get() {
|
|
@@ -59,10 +64,131 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
59
64
|
appConfig.theme.blackAsPrimary = value
|
|
60
65
|
window.localStorage.setItem(`${site.name}-ui-black-as-primary`, String(value))
|
|
61
66
|
}
|
|
67
|
+
|
|
68
|
+
const fonts = ['Public Sans', 'DM Sans', 'Geist', 'Inter', 'Poppins', 'Outfit', 'Raleway']
|
|
69
|
+
const font = computed({
|
|
70
|
+
get() {
|
|
71
|
+
return appConfig.theme.font
|
|
72
|
+
},
|
|
73
|
+
set(option) {
|
|
74
|
+
appConfig.theme.font = option
|
|
75
|
+
window.localStorage.setItem(`${site.name}-ui-font`, appConfig.theme.font)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const icons = [{
|
|
80
|
+
label: 'Lucide',
|
|
81
|
+
icon: 'i-lucide-feather',
|
|
82
|
+
value: 'lucide'
|
|
83
|
+
}, {
|
|
84
|
+
label: 'Phosphor',
|
|
85
|
+
icon: 'i-ph-phosphor-logo',
|
|
86
|
+
value: 'phosphor'
|
|
87
|
+
}, {
|
|
88
|
+
label: 'Tabler',
|
|
89
|
+
icon: 'i-tabler-brand-tabler',
|
|
90
|
+
value: 'tabler'
|
|
91
|
+
}]
|
|
92
|
+
const icon = computed({
|
|
93
|
+
get() {
|
|
94
|
+
return appConfig.theme.icons
|
|
95
|
+
},
|
|
96
|
+
set(option) {
|
|
97
|
+
appConfig.theme.icons = option
|
|
98
|
+
appConfig.ui.icons = themeIcons[option as keyof typeof themeIcons] as any
|
|
99
|
+
window.localStorage.setItem(`${site.name}-ui-icons`, appConfig.theme.icons)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const hasCSSChanges = computed(() => {
|
|
104
|
+
return appConfig.theme.radius !== 0.25
|
|
105
|
+
|| appConfig.theme.blackAsPrimary
|
|
106
|
+
|| appConfig.theme.font !== 'Public Sans'
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const hasAppConfigChanges = computed(() => {
|
|
110
|
+
return appConfig.ui.colors.primary !== 'green'
|
|
111
|
+
|| appConfig.ui.colors.neutral !== 'slate'
|
|
112
|
+
|| appConfig.theme.icons !== 'lucide'
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
function exportCSS() {
|
|
116
|
+
const lines = [
|
|
117
|
+
'@import "tailwindcss";',
|
|
118
|
+
'@import "@nuxt/ui";'
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
if (appConfig.theme.font !== 'Public Sans') {
|
|
122
|
+
lines.push('', '@theme {', ` --font-sans: '${appConfig.theme.font}', sans-serif;`, '}')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const rootLines: string[] = []
|
|
126
|
+
if (appConfig.theme.radius !== 0.25) {
|
|
127
|
+
rootLines.push(` --ui-radius: ${appConfig.theme.radius}rem;`)
|
|
128
|
+
}
|
|
129
|
+
if (appConfig.theme.blackAsPrimary) {
|
|
130
|
+
rootLines.push(' --ui-primary: black;')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (rootLines.length) {
|
|
134
|
+
lines.push('', ':root {', ...rootLines, '}')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (appConfig.theme.blackAsPrimary) {
|
|
138
|
+
lines.push('', '.dark {', ' --ui-primary: white;', '}')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
copyCSS(lines.join('\n'))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function exportAppConfig() {
|
|
145
|
+
const config: Record<string, any> = {}
|
|
146
|
+
|
|
147
|
+
if (appConfig.ui.colors.primary !== 'green' || appConfig.ui.colors.neutral !== 'slate') {
|
|
148
|
+
config.ui = { colors: {} }
|
|
149
|
+
if (appConfig.ui.colors.primary !== 'green') {
|
|
150
|
+
config.ui.colors.primary = appConfig.ui.colors.primary
|
|
151
|
+
}
|
|
152
|
+
if (appConfig.ui.colors.neutral !== 'slate') {
|
|
153
|
+
config.ui.colors.neutral = appConfig.ui.colors.neutral
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (appConfig.theme.icons !== 'lucide') {
|
|
158
|
+
const iconSet = appConfig.theme.icons
|
|
159
|
+
const icons = themeIcons[iconSet as keyof typeof themeIcons]
|
|
160
|
+
config.ui = config.ui || {}
|
|
161
|
+
config.ui.icons = icons
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const configString = JSON.stringify(config, null, 2)
|
|
165
|
+
.replace(/"([^"]+)":/g, '$1:')
|
|
166
|
+
.replace(/"/g, '\'')
|
|
167
|
+
|
|
168
|
+
const output = `export default defineAppConfig(${configString})`
|
|
169
|
+
|
|
170
|
+
copyAppConfig(output)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function resetTheme() {
|
|
174
|
+
primary.value = 'green'
|
|
175
|
+
neutral.value = 'slate'
|
|
176
|
+
radius.value = 0.25
|
|
177
|
+
font.value = 'Public Sans'
|
|
178
|
+
icon.value = 'lucide'
|
|
179
|
+
setBlackAsPrimary(false)
|
|
180
|
+
|
|
181
|
+
window.localStorage.removeItem(`${site.name}-ui-primary`)
|
|
182
|
+
window.localStorage.removeItem(`${site.name}-ui-neutral`)
|
|
183
|
+
window.localStorage.removeItem(`${site.name}-ui-radius`)
|
|
184
|
+
window.localStorage.removeItem(`${site.name}-ui-font`)
|
|
185
|
+
window.localStorage.removeItem(`${site.name}-ui-icons`)
|
|
186
|
+
window.localStorage.removeItem(`${site.name}-ui-black-as-primary`)
|
|
187
|
+
}
|
|
62
188
|
</script>
|
|
63
189
|
|
|
64
190
|
<template>
|
|
65
|
-
<UPopover :ui="{ content: 'w-72 px-6 py-4 flex flex-col gap-4' }">
|
|
191
|
+
<UPopover :ui="{ content: 'w-72 px-6 py-4 flex flex-col gap-4 overflow-y-auto max-h-[calc(100vh-5rem)]' }">
|
|
66
192
|
<template #default="{ open }">
|
|
67
193
|
<UButton
|
|
68
194
|
icon="i-lucide-swatch-book"
|
|
@@ -76,8 +202,19 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
76
202
|
|
|
77
203
|
<template #content>
|
|
78
204
|
<fieldset>
|
|
79
|
-
<legend class="text-[11px] leading-none font-semibold mb-2">
|
|
205
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
80
206
|
Primary
|
|
207
|
+
|
|
208
|
+
<UButton
|
|
209
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#colors"
|
|
210
|
+
size="xs"
|
|
211
|
+
color="neutral"
|
|
212
|
+
variant="link"
|
|
213
|
+
target="_blank"
|
|
214
|
+
icon="i-lucide-circle-help"
|
|
215
|
+
class="p-0 -my-0.5"
|
|
216
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
217
|
+
/>
|
|
81
218
|
</legend>
|
|
82
219
|
|
|
83
220
|
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
@@ -99,8 +236,19 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
99
236
|
</fieldset>
|
|
100
237
|
|
|
101
238
|
<fieldset>
|
|
102
|
-
<legend class="text-[11px] leading-none font-semibold mb-2">
|
|
239
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
103
240
|
Neutral
|
|
241
|
+
|
|
242
|
+
<UButton
|
|
243
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#text"
|
|
244
|
+
size="xs"
|
|
245
|
+
color="neutral"
|
|
246
|
+
variant="link"
|
|
247
|
+
target="_blank"
|
|
248
|
+
icon="i-lucide-circle-help"
|
|
249
|
+
class="p-0 -my-0.5"
|
|
250
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
251
|
+
/>
|
|
104
252
|
</legend>
|
|
105
253
|
|
|
106
254
|
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
@@ -116,8 +264,19 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
116
264
|
</fieldset>
|
|
117
265
|
|
|
118
266
|
<fieldset>
|
|
119
|
-
<legend class="text-[11px] leading-none font-semibold mb-2">
|
|
267
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
120
268
|
Radius
|
|
269
|
+
|
|
270
|
+
<UButton
|
|
271
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#radius"
|
|
272
|
+
size="xs"
|
|
273
|
+
color="neutral"
|
|
274
|
+
variant="link"
|
|
275
|
+
target="_blank"
|
|
276
|
+
icon="i-lucide-circle-help"
|
|
277
|
+
class="p-0 -my-0.5"
|
|
278
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
279
|
+
/>
|
|
121
280
|
</legend>
|
|
122
281
|
|
|
123
282
|
<div class="grid grid-cols-5 gap-1 -mx-2">
|
|
@@ -133,8 +292,77 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
133
292
|
</fieldset>
|
|
134
293
|
|
|
135
294
|
<fieldset>
|
|
136
|
-
<legend class="text-[11px] leading-none font-semibold mb-2">
|
|
137
|
-
|
|
295
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
296
|
+
Font
|
|
297
|
+
|
|
298
|
+
<UButton
|
|
299
|
+
to="https://ui.nuxt.com/docs/getting-started/integrations/fonts"
|
|
300
|
+
size="xs"
|
|
301
|
+
color="neutral"
|
|
302
|
+
variant="link"
|
|
303
|
+
target="_blank"
|
|
304
|
+
icon="i-lucide-circle-help"
|
|
305
|
+
class="p-0 -my-0.5"
|
|
306
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
307
|
+
/>
|
|
308
|
+
</legend>
|
|
309
|
+
|
|
310
|
+
<div class="-mx-2">
|
|
311
|
+
<USelect
|
|
312
|
+
v-model="font"
|
|
313
|
+
size="sm"
|
|
314
|
+
color="neutral"
|
|
315
|
+
icon="i-lucide-type"
|
|
316
|
+
:items="fonts"
|
|
317
|
+
class="w-full ring-default rounded-sm hover:bg-elevated/50 text-[11px] data-[state=open]:bg-elevated/50"
|
|
318
|
+
:ui="{ trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200' }"
|
|
319
|
+
/>
|
|
320
|
+
</div>
|
|
321
|
+
</fieldset>
|
|
322
|
+
|
|
323
|
+
<fieldset>
|
|
324
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
325
|
+
Icons
|
|
326
|
+
|
|
327
|
+
<UButton
|
|
328
|
+
to="https://ui.nuxt.com/docs/getting-started/integrations/icons"
|
|
329
|
+
size="xs"
|
|
330
|
+
color="neutral"
|
|
331
|
+
variant="link"
|
|
332
|
+
target="_blank"
|
|
333
|
+
icon="i-lucide-circle-help"
|
|
334
|
+
class="p-0 -my-0.5"
|
|
335
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
336
|
+
/>
|
|
337
|
+
</legend>
|
|
338
|
+
|
|
339
|
+
<div class="-mx-2">
|
|
340
|
+
<USelect
|
|
341
|
+
v-model="icon"
|
|
342
|
+
size="sm"
|
|
343
|
+
color="neutral"
|
|
344
|
+
:icon="icons.find(i => i.value === icon)?.icon"
|
|
345
|
+
:items="icons"
|
|
346
|
+
class="w-full ring-default rounded-sm hover:bg-elevated/50 capitalize text-[11px] data-[state=open]:bg-elevated/50"
|
|
347
|
+
:ui="{ item: 'capitalize text-[11px]', trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200' }"
|
|
348
|
+
/>
|
|
349
|
+
</div>
|
|
350
|
+
</fieldset>
|
|
351
|
+
|
|
352
|
+
<fieldset>
|
|
353
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
354
|
+
Color Mode
|
|
355
|
+
|
|
356
|
+
<UButton
|
|
357
|
+
to="https://ui.nuxt.com/docs/getting-started/integrations/color-mode"
|
|
358
|
+
size="xs"
|
|
359
|
+
color="neutral"
|
|
360
|
+
variant="link"
|
|
361
|
+
target="_blank"
|
|
362
|
+
icon="i-lucide-circle-help"
|
|
363
|
+
class="p-0 -my-0.5"
|
|
364
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
365
|
+
/>
|
|
138
366
|
</legend>
|
|
139
367
|
|
|
140
368
|
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
@@ -147,6 +375,45 @@ function setBlackAsPrimary(value: boolean) {
|
|
|
147
375
|
/>
|
|
148
376
|
</div>
|
|
149
377
|
</fieldset>
|
|
378
|
+
|
|
379
|
+
<fieldset v-if="hasCSSChanges || hasAppConfigChanges">
|
|
380
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none">
|
|
381
|
+
Export
|
|
382
|
+
</legend>
|
|
383
|
+
|
|
384
|
+
<div class="flex items-center justify-between gap-1 -mx-2">
|
|
385
|
+
<UButton
|
|
386
|
+
v-if="hasCSSChanges"
|
|
387
|
+
color="neutral"
|
|
388
|
+
variant="soft"
|
|
389
|
+
size="sm"
|
|
390
|
+
label="main.css"
|
|
391
|
+
class="flex-1 text-[11px]"
|
|
392
|
+
:icon="copiedCSS ? 'i-lucide-copy-check' : 'i-lucide-copy'"
|
|
393
|
+
@click="exportCSS"
|
|
394
|
+
/>
|
|
395
|
+
<UButton
|
|
396
|
+
v-if="hasAppConfigChanges"
|
|
397
|
+
color="neutral"
|
|
398
|
+
variant="soft"
|
|
399
|
+
size="sm"
|
|
400
|
+
label="app.config.ts"
|
|
401
|
+
:icon="copiedAppConfig ? 'i-lucide-copy-check' : 'i-lucide-copy'"
|
|
402
|
+
class="flex-1 text-[11px]"
|
|
403
|
+
@click="exportAppConfig"
|
|
404
|
+
/>
|
|
405
|
+
<UTooltip text="Reset theme">
|
|
406
|
+
<UButton
|
|
407
|
+
color="neutral"
|
|
408
|
+
variant="outline"
|
|
409
|
+
size="sm"
|
|
410
|
+
icon="i-lucide-rotate-ccw"
|
|
411
|
+
class="ms-auto ring-default hover:bg-elevated/50"
|
|
412
|
+
@click="resetTheme"
|
|
413
|
+
/>
|
|
414
|
+
</UTooltip>
|
|
415
|
+
</div>
|
|
416
|
+
</fieldset>
|
|
150
417
|
</template>
|
|
151
418
|
</UPopover>
|
|
152
419
|
</template>
|
package/app/error.vue
CHANGED
|
@@ -18,6 +18,7 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
|
|
18
18
|
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
|
19
19
|
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
|
20
20
|
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
|
21
|
+
const font = computed(() => `:root { --font-sans: '${appConfig.theme.font}', sans-serif; }`)
|
|
21
22
|
|
|
22
23
|
useHead({
|
|
23
24
|
meta: [
|
|
@@ -26,7 +27,8 @@ useHead({
|
|
|
26
27
|
],
|
|
27
28
|
style: [
|
|
28
29
|
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
|
29
|
-
{ innerHTML: blackAsPrimary, id: 'nuxt-ui-black-as-primary', tagPriority: -2 }
|
|
30
|
+
{ innerHTML: blackAsPrimary, id: 'nuxt-ui-black-as-primary', tagPriority: -2 },
|
|
31
|
+
{ innerHTML: font, id: 'nuxt-ui-font', tagPriority: -2 }
|
|
30
32
|
]
|
|
31
33
|
})
|
|
32
34
|
|
package/app/plugins/theme.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { themeIcons } from '../utils/theme'
|
|
2
|
+
|
|
1
3
|
export default defineNuxtPlugin({
|
|
2
4
|
enforce: 'post',
|
|
3
5
|
setup() {
|
|
@@ -26,12 +28,32 @@ export default defineNuxtPlugin({
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
function updateFont() {
|
|
32
|
+
const font = localStorage.getItem(`${site.name}-ui-font`)
|
|
33
|
+
if (font) {
|
|
34
|
+
appConfig.theme.font = font
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
updateColor('primary')
|
|
30
39
|
updateColor('neutral')
|
|
31
40
|
updateRadius()
|
|
32
41
|
updateBlackAsPrimary()
|
|
42
|
+
updateFont()
|
|
33
43
|
}
|
|
34
44
|
|
|
45
|
+
onNuxtReady(() => {
|
|
46
|
+
function updateIcons() {
|
|
47
|
+
const icons = localStorage.getItem(`${site.name}-ui-icons`)
|
|
48
|
+
if (icons) {
|
|
49
|
+
appConfig.theme.icons = icons
|
|
50
|
+
appConfig.ui.icons = themeIcons[icons as keyof typeof themeIcons] as any
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
updateIcons()
|
|
55
|
+
})
|
|
56
|
+
|
|
35
57
|
if (import.meta.server) {
|
|
36
58
|
useHead({
|
|
37
59
|
script: [{
|
|
@@ -75,6 +97,13 @@ export default defineNuxtPlugin({
|
|
|
75
97
|
document.querySelector('style#nuxt-ui-black-as-primary').innerHTML = '';
|
|
76
98
|
}
|
|
77
99
|
`.replace(/\s+/g, ' ')
|
|
100
|
+
}, {
|
|
101
|
+
innerHTML: `
|
|
102
|
+
if (localStorage.getItem('${site.name}-ui-font')) {
|
|
103
|
+
const font = localStorage.getItem('${site.name}-ui-font');
|
|
104
|
+
document.querySelector('style#nuxt-ui-font').innerHTML = ':root { --font-sans: \\'' + font + '\\', sans-serif; }';
|
|
105
|
+
}
|
|
106
|
+
`.replace(/\s+/g, ' ')
|
|
78
107
|
}]
|
|
79
108
|
})
|
|
80
109
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export const themeIcons = {
|
|
2
|
+
lucide: {
|
|
3
|
+
arrowDown: 'i-lucide-arrow-down',
|
|
4
|
+
arrowLeft: 'i-lucide-arrow-left',
|
|
5
|
+
arrowRight: 'i-lucide-arrow-right',
|
|
6
|
+
arrowUp: 'i-lucide-arrow-up',
|
|
7
|
+
caution: 'i-lucide-circle-alert',
|
|
8
|
+
check: 'i-lucide-check',
|
|
9
|
+
chevronDoubleLeft: 'i-lucide-chevrons-left',
|
|
10
|
+
chevronDoubleRight: 'i-lucide-chevrons-right',
|
|
11
|
+
chevronDown: 'i-lucide-chevron-down',
|
|
12
|
+
chevronLeft: 'i-lucide-chevron-left',
|
|
13
|
+
chevronRight: 'i-lucide-chevron-right',
|
|
14
|
+
chevronUp: 'i-lucide-chevron-up',
|
|
15
|
+
close: 'i-lucide-x',
|
|
16
|
+
copy: 'i-lucide-copy',
|
|
17
|
+
copyCheck: 'i-lucide-copy-check',
|
|
18
|
+
dark: 'i-lucide-moon',
|
|
19
|
+
drag: 'i-lucide-grip-vertical',
|
|
20
|
+
ellipsis: 'i-lucide-ellipsis',
|
|
21
|
+
error: 'i-lucide-circle-x',
|
|
22
|
+
external: 'i-lucide-arrow-up-right',
|
|
23
|
+
eye: 'i-lucide-eye',
|
|
24
|
+
eyeOff: 'i-lucide-eye-off',
|
|
25
|
+
file: 'i-lucide-file',
|
|
26
|
+
folder: 'i-lucide-folder',
|
|
27
|
+
folderOpen: 'i-lucide-folder-open',
|
|
28
|
+
hash: 'i-lucide-hash',
|
|
29
|
+
info: 'i-lucide-info',
|
|
30
|
+
light: 'i-lucide-sun',
|
|
31
|
+
loading: 'i-lucide-loader-circle',
|
|
32
|
+
menu: 'i-lucide-menu',
|
|
33
|
+
minus: 'i-lucide-minus',
|
|
34
|
+
panelClose: 'i-lucide-panel-left-close',
|
|
35
|
+
panelOpen: 'i-lucide-panel-left-open',
|
|
36
|
+
plus: 'i-lucide-plus',
|
|
37
|
+
reload: 'i-lucide-rotate-ccw',
|
|
38
|
+
search: 'i-lucide-search',
|
|
39
|
+
stop: 'i-lucide-square',
|
|
40
|
+
success: 'i-lucide-circle-check',
|
|
41
|
+
system: 'i-lucide-monitor',
|
|
42
|
+
tip: 'i-lucide-lightbulb',
|
|
43
|
+
upload: 'i-lucide-upload',
|
|
44
|
+
warning: 'i-lucide-triangle-alert'
|
|
45
|
+
},
|
|
46
|
+
phosphor: {
|
|
47
|
+
arrowDown: 'i-ph-arrow-down',
|
|
48
|
+
arrowLeft: 'i-ph-arrow-left',
|
|
49
|
+
arrowRight: 'i-ph-arrow-right',
|
|
50
|
+
arrowUp: 'i-ph-arrow-up',
|
|
51
|
+
caution: 'i-ph-warning-circle',
|
|
52
|
+
check: 'i-ph-check',
|
|
53
|
+
chevronDoubleLeft: 'i-ph-caret-double-left',
|
|
54
|
+
chevronDoubleRight: 'i-ph-caret-double-right',
|
|
55
|
+
chevronDown: 'i-ph-caret-down',
|
|
56
|
+
chevronLeft: 'i-ph-caret-left',
|
|
57
|
+
chevronRight: 'i-ph-caret-right',
|
|
58
|
+
chevronUp: 'i-ph-caret-up',
|
|
59
|
+
close: 'i-ph-x',
|
|
60
|
+
copy: 'i-ph-copy',
|
|
61
|
+
copyCheck: 'i-ph-check-circle',
|
|
62
|
+
dark: 'i-ph-moon',
|
|
63
|
+
drag: 'i-ph-dots-six-vertical',
|
|
64
|
+
ellipsis: 'i-ph-dots-three',
|
|
65
|
+
error: 'i-ph-x-circle',
|
|
66
|
+
external: 'i-ph-arrow-up-right',
|
|
67
|
+
eye: 'i-ph-eye',
|
|
68
|
+
eyeOff: 'i-ph-eye-slash',
|
|
69
|
+
file: 'i-ph-file',
|
|
70
|
+
folder: 'i-ph-folder',
|
|
71
|
+
folderOpen: 'i-ph-folder-open',
|
|
72
|
+
hash: 'i-ph-hash',
|
|
73
|
+
info: 'i-ph-info',
|
|
74
|
+
light: 'i-ph-sun',
|
|
75
|
+
loading: 'i-ph-circle-notch',
|
|
76
|
+
menu: 'i-ph-list',
|
|
77
|
+
minus: 'i-ph-minus',
|
|
78
|
+
panelClose: 'i-ph-caret-left',
|
|
79
|
+
panelOpen: 'i-ph-caret-right',
|
|
80
|
+
plus: 'i-ph-plus',
|
|
81
|
+
reload: 'i-ph-arrow-counter-clockwise',
|
|
82
|
+
search: 'i-ph-magnifying-glass',
|
|
83
|
+
stop: 'i-ph-square',
|
|
84
|
+
success: 'i-ph-check-circle',
|
|
85
|
+
system: 'i-ph-monitor',
|
|
86
|
+
tip: 'i-ph-lightbulb',
|
|
87
|
+
upload: 'i-ph-upload',
|
|
88
|
+
warning: 'i-ph-warning'
|
|
89
|
+
},
|
|
90
|
+
tabler: {
|
|
91
|
+
arrowDown: 'i-tabler-arrow-down',
|
|
92
|
+
arrowLeft: 'i-tabler-arrow-left',
|
|
93
|
+
arrowRight: 'i-tabler-arrow-right',
|
|
94
|
+
arrowUp: 'i-tabler-arrow-up',
|
|
95
|
+
caution: 'i-tabler-alert-square-rounded',
|
|
96
|
+
check: 'i-tabler-check',
|
|
97
|
+
chevronDoubleLeft: 'i-tabler-chevrons-left',
|
|
98
|
+
chevronDoubleRight: 'i-tabler-chevrons-right',
|
|
99
|
+
chevronDown: 'i-tabler-chevron-down',
|
|
100
|
+
chevronLeft: 'i-tabler-chevron-left',
|
|
101
|
+
chevronRight: 'i-tabler-chevron-right',
|
|
102
|
+
chevronUp: 'i-tabler-chevron-up',
|
|
103
|
+
close: 'i-tabler-x',
|
|
104
|
+
copy: 'i-tabler-copy',
|
|
105
|
+
copyCheck: 'i-tabler-copy-check',
|
|
106
|
+
dark: 'i-tabler-moon',
|
|
107
|
+
drag: 'i-tabler-grip-vertical',
|
|
108
|
+
ellipsis: 'i-tabler-dots',
|
|
109
|
+
error: 'i-tabler-square-rounded-x',
|
|
110
|
+
external: 'i-tabler-external-link',
|
|
111
|
+
eye: 'i-tabler-eye',
|
|
112
|
+
eyeOff: 'i-tabler-eye-off',
|
|
113
|
+
file: 'i-tabler-file',
|
|
114
|
+
folder: 'i-tabler-folder',
|
|
115
|
+
folderOpen: 'i-tabler-folder-open',
|
|
116
|
+
hash: 'i-tabler-hash',
|
|
117
|
+
info: 'i-tabler-info-square-rounded',
|
|
118
|
+
light: 'i-tabler-sun',
|
|
119
|
+
loading: 'i-tabler-loader-2',
|
|
120
|
+
menu: 'i-tabler-menu',
|
|
121
|
+
minus: 'i-tabler-minus',
|
|
122
|
+
panelClose: 'i-tabler-layout-sidebar-left-collapse',
|
|
123
|
+
panelOpen: 'i-tabler-layout-sidebar-left-expand',
|
|
124
|
+
plus: 'i-tabler-plus',
|
|
125
|
+
reload: 'i-tabler-reload',
|
|
126
|
+
search: 'i-tabler-search',
|
|
127
|
+
stop: 'i-tabler-player-stop',
|
|
128
|
+
success: 'i-tabler-square-rounded-check',
|
|
129
|
+
system: 'i-tabler-device-desktop',
|
|
130
|
+
tip: 'i-tabler-bulb',
|
|
131
|
+
upload: 'i-tabler-upload',
|
|
132
|
+
warning: 'i-tabler-alert-triangle'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export type ThemeIcons = keyof typeof themeIcons
|
package/nuxt.config.ts
CHANGED
|
@@ -73,6 +73,17 @@ export default defineNuxtConfig({
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
|
+
fonts: {
|
|
77
|
+
families: [
|
|
78
|
+
{ name: 'Public Sans', provider: 'google', global: true },
|
|
79
|
+
{ name: 'DM Sans', provider: 'google', global: true },
|
|
80
|
+
{ name: 'Geist', provider: 'google', global: true },
|
|
81
|
+
{ name: 'Inter', provider: 'google', global: true },
|
|
82
|
+
{ name: 'Poppins', provider: 'google', global: true },
|
|
83
|
+
{ name: 'Outfit', provider: 'google', global: true },
|
|
84
|
+
{ name: 'Raleway', provider: 'google', global: true }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
76
87
|
icon: {
|
|
77
88
|
provider: 'iconify'
|
|
78
89
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@movk/nuxt-docs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "An elegant documentation theme for Nuxt, powered by Nuxt UI and Nuxt Content.",
|
|
7
7
|
"author": "YiXuan <mhaibaraai@gmail.com>",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@iconify-json/lucide": "^1.2.
|
|
31
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
30
|
+
"@iconify-json/lucide": "^1.2.81",
|
|
31
|
+
"@iconify-json/simple-icons": "^1.2.63",
|
|
32
32
|
"@iconify-json/vscode-icons": "^1.2.37",
|
|
33
33
|
"@movk/core": "^1.0.2",
|
|
34
34
|
"@nuxt/content": "^3.9.0",
|
|
35
35
|
"@nuxt/image": "^2.0.0",
|
|
36
36
|
"@nuxt/kit": "^4.2.2",
|
|
37
|
-
"@nuxt/ui": "^4.
|
|
38
|
-
"@nuxtjs/seo": "^3.
|
|
37
|
+
"@nuxt/ui": "^4.3.0",
|
|
38
|
+
"@nuxtjs/seo": "^3.3.0",
|
|
39
39
|
"@octokit/rest": "^22.0.1",
|
|
40
40
|
"@vueuse/core": "^14.1.0",
|
|
41
41
|
"@vueuse/nuxt": "^14.1.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"pkg-types": "^2.3.0",
|
|
51
51
|
"prettier": "^3.7.4",
|
|
52
52
|
"scule": "^1.3.0",
|
|
53
|
-
"tailwindcss": "^4.1.
|
|
53
|
+
"tailwindcss": "^4.1.18",
|
|
54
54
|
"ufo": "^1.6.1"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -5,8 +5,10 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
5
5
|
return []
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
const { path, author } = getQuery(event) as { path: string, author
|
|
9
|
-
|
|
8
|
+
const { path, author } = getQuery(event) as { path: string | string[], author: string }
|
|
9
|
+
const paths = Array.isArray(path) ? path : [path]
|
|
10
|
+
|
|
11
|
+
if (!paths.length || !paths[0]) {
|
|
10
12
|
throw createError({
|
|
11
13
|
statusCode: 400,
|
|
12
14
|
statusMessage: 'Path is required'
|
|
@@ -15,26 +17,41 @@ export default defineCachedEventHandler(async (event) => {
|
|
|
15
17
|
|
|
16
18
|
const { github } = useAppConfig()
|
|
17
19
|
const octokit = new Octokit({ auth: process.env.NUXT_GITHUB_TOKEN })
|
|
18
|
-
const commits = await octokit.paginate(octokit.rest.repos.listCommits, {
|
|
19
|
-
sha: github.branch,
|
|
20
|
-
owner: github.owner,
|
|
21
|
-
repo: github.name,
|
|
22
|
-
path,
|
|
23
|
-
since: github.since,
|
|
24
|
-
per_page: github.per_page,
|
|
25
|
-
until: github.until,
|
|
26
|
-
...(author && { author })
|
|
27
|
-
})
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
const allCommits = await Promise.all(
|
|
22
|
+
paths.map(path =>
|
|
23
|
+
octokit.paginate(octokit.rest.repos.listCommits, {
|
|
24
|
+
sha: github.branch,
|
|
25
|
+
owner: github.owner,
|
|
26
|
+
repo: github.name,
|
|
27
|
+
path,
|
|
28
|
+
since: github.since,
|
|
29
|
+
per_page: github.per_page,
|
|
30
|
+
until: github.until,
|
|
31
|
+
author
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const uniqueCommits = new Map<string, { sha: string, date: string, message: string }>()
|
|
37
|
+
for (const commits of allCommits) {
|
|
38
|
+
for (const commit of commits) {
|
|
39
|
+
if (!uniqueCommits.has(commit.sha)) {
|
|
40
|
+
uniqueCommits.set(commit.sha, {
|
|
41
|
+
sha: commit.sha,
|
|
42
|
+
date: commit.commit.author?.date ?? '',
|
|
43
|
+
message: (commit.commit.message?.split('\n')[0] ?? '')
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return Array.from(uniqueCommits.values()).sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
34
50
|
}, {
|
|
35
51
|
maxAge: 60 * 60,
|
|
36
52
|
getKey: (event) => {
|
|
37
53
|
const { path, author } = getQuery(event)
|
|
38
|
-
|
|
54
|
+
const paths = Array.isArray(path) ? path : [path]
|
|
55
|
+
return `commits-${paths.join(',')}${author ? `-${author}` : ''}`
|
|
39
56
|
}
|
|
40
57
|
})
|