simple-content-site 2.3.1 → 3.1.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/components/LanguageSelect.vue +1 -1
- package/app/composables/useSiteI18n.ts +1 -2
- package/app/composables/useSitePage.ts +18 -41
- package/app/pages/[[lang]]/[...slug].vue +15 -6
- package/content.config.ts +14 -7
- package/modules/config.ts +45 -49
- package/modules/content.ts +13 -0
- package/modules/css.ts +8 -3
- package/modules/routing.ts +1 -2
- package/nuxt.config.ts +3 -7
- package/package.json +15 -12
- package/server/routes/raw/[...slug].md.get.ts +2 -2
|
@@ -5,7 +5,6 @@ export const useSiteI18n = () => {
|
|
|
5
5
|
const config = useRuntimeConfig().public
|
|
6
6
|
const isEnabled = ref(!!config.i18n && config.i18n.locales?.length > 0)
|
|
7
7
|
// todo: reading the strategy like this might cause issues in the future.
|
|
8
|
-
// @ts-expect-error Due to the above comment
|
|
9
8
|
const strategy = ref(config.i18n?.strategy || 'prefix_except_default')
|
|
10
9
|
|
|
11
10
|
if (!isEnabled.value) {
|
|
@@ -25,7 +24,7 @@ export const useSiteI18n = () => {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
const { locale, t } = useI18n()
|
|
28
|
-
const filteredLocales = (config.
|
|
27
|
+
const filteredLocales = (config.scs as { filteredLocales: LocaleObject<string>[] })?.filteredLocales || []
|
|
29
28
|
|
|
30
29
|
return {
|
|
31
30
|
isEnabled,
|
|
@@ -1,59 +1,36 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { findPageHeadline } from '@nuxt/content/utils'
|
|
1
|
+
import type { Collections, PagesCollectionItem } from '@nuxt/content'
|
|
3
2
|
import { kebabCase } from 'scule'
|
|
3
|
+
import { joinURL, withLeadingSlash } from 'ufo'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
immediate?: boolean
|
|
7
|
-
}
|
|
8
|
-
export const useSitePage = async (opts?: SitePageOptions) => {
|
|
9
|
-
const route = useRoute()
|
|
5
|
+
export const useSitePage = () => {
|
|
10
6
|
const { locale, isEnabled, defaultLocale, strategy } = useSiteI18n()
|
|
11
|
-
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
|
12
7
|
|
|
13
|
-
const collectionName = computed(() => {
|
|
14
|
-
if (!isEnabled.value || !defaultLocale.value) {
|
|
15
|
-
return 'pages'
|
|
8
|
+
const collectionName = computed<keyof Collections>(() => {
|
|
9
|
+
if (!isEnabled.value || !defaultLocale.value || !locale.value) {
|
|
10
|
+
return 'pages' as keyof Collections
|
|
16
11
|
}
|
|
17
|
-
return `pages_${locale.value}`
|
|
12
|
+
return `pages_${locale.value}` as keyof Collections
|
|
18
13
|
})
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
const getKeyForPath = (path: string) => {
|
|
16
|
+
const prefix = toValue(collectionName.value).replaceAll('_', '-')
|
|
17
|
+
const suffix = kebabCase(withLeadingSlash(path).replaceAll('/', '--'))
|
|
18
|
+
return `${prefix}:${suffix}`
|
|
19
|
+
}
|
|
21
20
|
|
|
22
21
|
const findByPath = async (path: string) => {
|
|
23
|
-
if (strategy.value === 'prefix_except_default' && locale.value === defaultLocale.value) {
|
|
24
|
-
const
|
|
25
|
-
if (path !==
|
|
26
|
-
|
|
27
|
-
path = `${prefix}${path}`
|
|
22
|
+
if (isEnabled.value && strategy.value === 'prefix_except_default' && locale.value === defaultLocale.value) {
|
|
23
|
+
const localePrefix = withLeadingSlash(locale.value)
|
|
24
|
+
if (path !== localePrefix && !path.startsWith(`${localePrefix}/`)) {
|
|
25
|
+
path = joinURL(localePrefix, path)
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
|
-
return await queryCollection(collectionName.value
|
|
28
|
+
return await queryCollection(collectionName.value).path(withLeadingSlash(path)).first() as PagesCollectionItem
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
const { data: page, refresh } = await useAsyncData(() => kebabCase(route.path), async () => {
|
|
34
|
-
const match = await findByPath(route.path)
|
|
35
|
-
return match ? match : undefined
|
|
36
|
-
}, {
|
|
37
|
-
immediate: opts?.immediate,
|
|
38
|
-
})
|
|
39
|
-
// watch(() => route.path, async (path) => {
|
|
40
|
-
// const match = await findByPath(path)
|
|
41
|
-
// page.value = match ? match : undefined
|
|
42
|
-
// })
|
|
43
|
-
|
|
44
|
-
const title = computed(() => page.value?.seo?.title || page.value?.title || undefined)
|
|
45
|
-
const description = computed(() => page.value?.seo?.description || page.value?.description || undefined)
|
|
46
|
-
const headline = computed(() => findPageHeadline(navigation?.value, page.value?.path))
|
|
47
|
-
const exists = computed(() => page.value !== undefined)
|
|
48
|
-
|
|
49
31
|
return {
|
|
50
|
-
page,
|
|
51
|
-
title,
|
|
52
|
-
description,
|
|
53
|
-
headline,
|
|
54
|
-
exists,
|
|
55
32
|
collectionName,
|
|
56
33
|
findByPath,
|
|
57
|
-
|
|
34
|
+
getKeyForPath,
|
|
58
35
|
}
|
|
59
36
|
}
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ContentNavigationItem } from '@nuxt/content'
|
|
3
3
|
import { findPageHeadline } from '@nuxt/content/utils'
|
|
4
|
-
import { addPrerenderPath } from '../../utils/prerender'
|
|
4
|
+
// import { addPrerenderPath } from '../../utils/prerender'
|
|
5
5
|
import { useSitePage } from '#imports'
|
|
6
|
+
import { withLeadingSlash } from 'ufo'
|
|
6
7
|
|
|
7
8
|
definePageMeta({
|
|
8
9
|
layout: 'page',
|
|
9
10
|
})
|
|
10
11
|
|
|
11
12
|
const route = useRoute()
|
|
12
|
-
const {
|
|
13
|
-
|
|
13
|
+
const { findByPath, getKeyForPath } = useSitePage()
|
|
14
|
+
|
|
15
|
+
const { data: page } = await useAsyncData(() => getKeyForPath(route.path), async () => {
|
|
16
|
+
console.log('fetching page', route.path)
|
|
17
|
+
return await findByPath(withLeadingSlash(route.path) || '/')
|
|
18
|
+
}, {
|
|
19
|
+
immediate: true,
|
|
20
|
+
})
|
|
14
21
|
|
|
15
22
|
if (!page.value) {
|
|
16
23
|
throw createError({
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
status: 404,
|
|
25
|
+
message: 'Page not found',
|
|
19
26
|
fatal: true,
|
|
20
27
|
})
|
|
21
28
|
}
|
|
22
29
|
|
|
30
|
+
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
|
31
|
+
|
|
23
32
|
// Add the page path to the prerender list
|
|
24
|
-
addPrerenderPath(`/raw${route.path}.md`)
|
|
33
|
+
// addPrerenderPath(`/raw${route.path}.md`)
|
|
25
34
|
|
|
26
35
|
const title = page.value.seo?.title || page.value.title
|
|
27
36
|
const description = page.value.seo?.description || page.value.description
|
package/content.config.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod/v4'
|
|
1
2
|
import type { DefinedCollection } from '@nuxt/content'
|
|
2
|
-
import { defineContentConfig, defineCollection,
|
|
3
|
+
import { defineContentConfig, defineCollection, property } from '@nuxt/content'
|
|
3
4
|
import { useNuxt } from '@nuxt/kit'
|
|
4
5
|
import { joinURL } from 'ufo'
|
|
5
6
|
|
|
6
7
|
const { options } = useNuxt()
|
|
7
8
|
const cwd = joinURL(options.rootDir, 'content')
|
|
9
|
+
|
|
10
|
+
// @ts-expect-error cannot be typed?
|
|
11
|
+
const contentExcluded = options?.scs?.excludeContent || []
|
|
12
|
+
|
|
8
13
|
// @ts-expect-error cannot be typed?
|
|
9
14
|
const locales = options.i18n?.locales
|
|
10
15
|
// todo: might be required for diff strategies for the collections
|
|
@@ -29,10 +34,10 @@ const createLinkSchema = () => z.object({
|
|
|
29
34
|
class: z.string().optional(),
|
|
30
35
|
label: z.string().nonempty(),
|
|
31
36
|
to: z.string().nonempty(),
|
|
32
|
-
icon: z.string().optional().editor({ input: 'icon' }),
|
|
37
|
+
icon: property(z.string().optional()).editor({ input: 'icon' }),
|
|
33
38
|
size: sizeEnum.optional(),
|
|
34
39
|
trailing: z.boolean().optional(),
|
|
35
|
-
trailingIcon: z.string().optional().editor({ input: 'icon' }),
|
|
40
|
+
trailingIcon: property(z.string().optional()).editor({ input: 'icon' }),
|
|
36
41
|
target: z.string().optional(),
|
|
37
42
|
color: colorEnum.optional(),
|
|
38
43
|
variant: variantEnum.optional(),
|
|
@@ -42,10 +47,10 @@ const createNavigationSchema = () => z.object({
|
|
|
42
47
|
label: z.string().nonempty(),
|
|
43
48
|
class: z.string().optional(),
|
|
44
49
|
to: z.string().nonempty(),
|
|
45
|
-
icon: z.string().optional().editor({ input: 'icon' }),
|
|
50
|
+
icon: property(z.string().optional()).editor({ input: 'icon' }),
|
|
46
51
|
size: sizeEnum.optional(),
|
|
47
52
|
trailing: z.boolean().optional(),
|
|
48
|
-
trailingIcon: z.string().optional().editor({ input: 'icon' }),
|
|
53
|
+
trailingIcon: property(z.string().optional()).editor({ input: 'icon' }),
|
|
49
54
|
target: z.string().optional(),
|
|
50
55
|
color: colorEnum.optional(),
|
|
51
56
|
variant: variantEnum.optional(),
|
|
@@ -96,11 +101,12 @@ const buildI18nCollections = () => {
|
|
|
96
101
|
type: 'page',
|
|
97
102
|
source: {
|
|
98
103
|
cwd,
|
|
99
|
-
include: `${code}
|
|
104
|
+
include: `${code}/**/**.{md,yml}`,
|
|
100
105
|
prefix: `/${code}`,
|
|
101
106
|
exclude: [
|
|
102
107
|
`${code}/header.yml`,
|
|
103
108
|
`${code}/footer.yml`,
|
|
109
|
+
...contentExcluded,
|
|
104
110
|
],
|
|
105
111
|
},
|
|
106
112
|
schema: createPageSchema(),
|
|
@@ -132,10 +138,11 @@ const buildDefaultCollections = () => {
|
|
|
132
138
|
type: 'page',
|
|
133
139
|
source: {
|
|
134
140
|
cwd,
|
|
135
|
-
include: '
|
|
141
|
+
include: '**/**.{md,yml}',
|
|
136
142
|
exclude: [
|
|
137
143
|
'header.yml',
|
|
138
144
|
'footer.yml',
|
|
145
|
+
...contentExcluded,
|
|
139
146
|
],
|
|
140
147
|
},
|
|
141
148
|
schema: createPageSchema(),
|
package/modules/config.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { createResolver, defineNuxtModule, addPlugin } from '@nuxt/kit'
|
|
1
|
+
import { createResolver, defineNuxtModule, addPlugin, logger } from '@nuxt/kit'
|
|
2
2
|
import { defu } from 'defu'
|
|
3
3
|
import { existsSync } from 'node:fs'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import { inferSiteURL, getPackageJsonMetadata } from '../utils/meta'
|
|
6
6
|
import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
interface SimpleContentSiteOptions {
|
|
9
|
+
excludeContent?: string[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const log = logger.withTag('SimpleContentSite')
|
|
13
|
+
|
|
14
|
+
export default defineNuxtModule<SimpleContentSiteOptions>({
|
|
9
15
|
meta: {
|
|
10
|
-
name: '
|
|
16
|
+
name: 'scs',
|
|
17
|
+
},
|
|
18
|
+
defaults: {
|
|
19
|
+
excludeContent: [],
|
|
11
20
|
},
|
|
12
21
|
async setup(_options, nuxt) {
|
|
22
|
+
const { resolve } = createResolver(import.meta.url)
|
|
13
23
|
const dir = nuxt.options.rootDir
|
|
14
24
|
const url = inferSiteURL()
|
|
15
25
|
const meta = await getPackageJsonMetadata(dir)
|
|
16
26
|
const gitInfo = await getLocalGitInfo(dir) || getGitEnv()
|
|
17
|
-
const siteName = nuxt.options
|
|
18
|
-
|
|
19
|
-
// nuxt.options.llms = defu(nuxt.options.llms, {
|
|
20
|
-
// domain: url,
|
|
21
|
-
// title: siteName,
|
|
22
|
-
// description: meta.description || '',
|
|
23
|
-
// full: {
|
|
24
|
-
// title: siteName,
|
|
25
|
-
// description: meta.description || '',
|
|
26
|
-
// },
|
|
27
|
-
// })
|
|
27
|
+
const siteName = (typeof nuxt.options.site === 'object' && nuxt.options.site?.name) || meta.name || gitInfo?.name || ''
|
|
28
28
|
|
|
29
29
|
nuxt.options.site = defu(nuxt.options.site, {
|
|
30
30
|
url,
|
|
@@ -49,12 +49,31 @@ export default defineNuxtModule({
|
|
|
49
49
|
branch: getGitBranch(),
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// ...
|
|
53
|
+
nuxt.options.i18n = defu(nuxt.options.i18n, {
|
|
54
|
+
strategy: 'prefix_except_default',
|
|
55
|
+
}) as typeof nuxt.options.i18n
|
|
56
|
+
|
|
57
|
+
// ensure we redirect from index if the strategy requires.
|
|
58
|
+
|
|
59
|
+
// todo: exposing the strategy like this might cause issues in the future.
|
|
60
|
+
// So it will be better to expose the i18n redirect plugin instead from a module.
|
|
61
|
+
nuxt.options.runtimeConfig.public.i18n = defu(nuxt.options.runtimeConfig.public.i18n, {
|
|
62
|
+
strategy: (nuxt.options.i18n ? nuxt.options.i18n.strategy : undefined) || 'prefix_except_default',
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const i18nStrategy = nuxt.options.runtimeConfig.public.i18n.strategy as string
|
|
66
|
+
|
|
67
|
+
if (i18nStrategy && !['prefix_except_default', 'no_prefix'].includes(i18nStrategy)) {
|
|
68
|
+
console.log(`[I18n] Adding redirect plugin for root since strategy is: ${i18nStrategy}`)
|
|
69
|
+
addPlugin({
|
|
70
|
+
src: resolve('../runtime/plugins/i18n-redirect'),
|
|
71
|
+
mode: 'client',
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
55
75
|
if (nuxt.options.i18n && nuxt.options.i18n.locales) {
|
|
56
76
|
const { resolve } = createResolver(import.meta.url)
|
|
57
|
-
const { resolve: resolveRoot } = createResolver(dir)
|
|
58
77
|
|
|
59
78
|
// Filter locales to only include existing ones
|
|
60
79
|
const filteredLocales = nuxt.options.i18n.locales.filter((locale) => {
|
|
@@ -69,63 +88,40 @@ export default defineNuxtModule({
|
|
|
69
88
|
const hasContentFolder = existsSync(contentPath)
|
|
70
89
|
|
|
71
90
|
if (!hasLocaleFile) {
|
|
72
|
-
|
|
91
|
+
log.warn(`Locale file not found: ${localeCode}.json - skipping locale "${localeCode}"`)
|
|
73
92
|
}
|
|
74
93
|
|
|
75
94
|
if (!hasContentFolder) {
|
|
76
|
-
|
|
95
|
+
log.warn(`Content folder not found: content/${localeCode}/ - skipping locale "${localeCode}"`)
|
|
77
96
|
}
|
|
78
97
|
|
|
79
98
|
return hasLocaleFile && hasContentFolder
|
|
80
99
|
})
|
|
81
100
|
|
|
82
|
-
//
|
|
83
|
-
nuxt.options.i18n = defu(nuxt.options.i18n, {
|
|
84
|
-
strategy: 'prefix_except_default',
|
|
85
|
-
}) as typeof nuxt.options.i18n
|
|
86
|
-
|
|
87
|
-
// todo: exposing the strategy like this might cause issues in the future.
|
|
88
|
-
// So it will be better to expose the i18n redirect plugin instead from a module.
|
|
89
|
-
nuxt.options.runtimeConfig.public.i18n = defu(nuxt.options.runtimeConfig.public.i18n, {
|
|
90
|
-
strategy: nuxt.options.i18n.strategy,
|
|
91
|
-
})
|
|
92
|
-
|
|
93
101
|
// Expose filtered locales
|
|
94
|
-
nuxt.options.runtimeConfig.public.
|
|
102
|
+
nuxt.options.runtimeConfig.public.scs = {
|
|
95
103
|
filteredLocales,
|
|
96
104
|
}
|
|
97
105
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
console.log(`[I18n] Adding redirect plugin for root since strategy is: ${nuxt.options.i18n.strategy}`)
|
|
101
|
-
addPlugin({
|
|
102
|
-
src: resolve('../runtime/plugins/i18n-redirect'),
|
|
103
|
-
mode: 'client',
|
|
104
|
-
})
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
nuxt.hook('i18n:registerModule', (register) => {
|
|
106
|
+
// @ts-expect-error This is messed up...
|
|
107
|
+
nuxt.hook('i18n:registerModule', (register: never) => {
|
|
108
108
|
const langDir = resolve('../i18n/locales')
|
|
109
109
|
|
|
110
110
|
const locales = filteredLocales?.map((locale) => {
|
|
111
|
-
// Possibly load custom translations.
|
|
112
|
-
const localeCode = typeof locale === 'string' ? locale : locale.code
|
|
113
|
-
const customLocalePath = resolveRoot('i18n/locales', `${localeCode}.json`)
|
|
114
|
-
const hasCustomLocale = existsSync(customLocalePath)
|
|
115
|
-
const files = hasCustomLocale ? [customLocalePath, `${localeCode}.json`] : [`${localeCode}.json`]
|
|
116
111
|
return typeof locale === 'string'
|
|
117
112
|
? {
|
|
118
113
|
code: locale,
|
|
119
114
|
name: locale,
|
|
120
|
-
|
|
115
|
+
file: `${locale}.json`,
|
|
121
116
|
}
|
|
122
117
|
: {
|
|
123
118
|
code: locale.code,
|
|
124
119
|
name: locale.name || locale.code,
|
|
125
|
-
|
|
120
|
+
file: `${locale.code}.json`,
|
|
126
121
|
}
|
|
127
122
|
})
|
|
128
123
|
|
|
124
|
+
// @ts-expect-error This is amessed up too
|
|
129
125
|
register({
|
|
130
126
|
langDir,
|
|
131
127
|
locales,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineNuxtModule } from '@nuxt/kit'
|
|
2
|
+
|
|
3
|
+
// const { resolve } = createResolver(import.meta.url)
|
|
4
|
+
|
|
5
|
+
export default defineNuxtModule({
|
|
6
|
+
meta: {
|
|
7
|
+
// todo: rename this module to fit it's purpose
|
|
8
|
+
name: 'routing',
|
|
9
|
+
},
|
|
10
|
+
async setup(_options) {
|
|
11
|
+
console.log('content module setup -> Should bootstrap content?! or can i make it work from a separate content.config.ts?')
|
|
12
|
+
},
|
|
13
|
+
})
|
package/modules/css.ts
CHANGED
|
@@ -14,19 +14,24 @@ export default defineNuxtModule({
|
|
|
14
14
|
const uiPath = resolveModulePath('@nuxt/ui', { from: import.meta.url, conditions: ['style'] })
|
|
15
15
|
const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
|
|
16
16
|
const layerDir = resolver.resolve('../app')
|
|
17
|
+
// const assistantDir = resolver.resolve('../modules/assistant')
|
|
17
18
|
|
|
18
19
|
const cssTemplate = addTemplate({
|
|
19
|
-
filename: '
|
|
20
|
+
filename: 'simple-content-site.css',
|
|
20
21
|
getContents: () => {
|
|
21
22
|
return `@import ${JSON.stringify(tailwindPath)};
|
|
22
23
|
@import ${JSON.stringify(uiPath)};
|
|
23
24
|
|
|
24
25
|
@source "${contentDir.replace(/\\/g, '/')}/**/*";
|
|
25
26
|
@source "${layerDir.replace(/\\/g, '/')}/**/*";
|
|
26
|
-
@source "../../app.config.ts"
|
|
27
|
+
@source "../../app.config.ts";
|
|
28
|
+
`
|
|
29
|
+
// @source "${assistantDir.replace(/\\/g, '/')}/**/*";
|
|
27
30
|
},
|
|
28
31
|
})
|
|
29
32
|
|
|
30
|
-
nuxt.options.css
|
|
33
|
+
if (Array.isArray(nuxt.options.css)) {
|
|
34
|
+
nuxt.options.css.unshift(cssTemplate.dst)
|
|
35
|
+
}
|
|
31
36
|
},
|
|
32
37
|
})
|
package/modules/routing.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver } from '@nuxt/kit'
|
|
2
2
|
|
|
3
|
+
const { resolve } = createResolver(import.meta.url)
|
|
3
4
|
export default defineNuxtModule({
|
|
4
5
|
meta: {
|
|
5
6
|
// todo: rename this module to fit it's purpose
|
|
6
7
|
name: 'routing',
|
|
7
8
|
},
|
|
8
9
|
async setup(_options, nuxt) {
|
|
9
|
-
const { resolve } = createResolver(import.meta.url)
|
|
10
|
-
|
|
11
10
|
// Ensure useSiteI18n is available in the app
|
|
12
11
|
nuxt.hook('imports:extend', (imports) => {
|
|
13
12
|
const loadComposableIfNotFound = (composableName: string) => {
|
package/nuxt.config.ts
CHANGED
|
@@ -48,14 +48,10 @@ export default defineNuxtConfig({
|
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
|
+
// future: {
|
|
52
|
+
// compatibilityVersion: 5,
|
|
53
|
+
// },
|
|
51
54
|
compatibilityDate: '2025-07-22',
|
|
52
|
-
nitro: {
|
|
53
|
-
prerender: {
|
|
54
|
-
crawlLinks: true,
|
|
55
|
-
failOnError: false,
|
|
56
|
-
autoSubfolderIndex: false,
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
55
|
hooks: {
|
|
60
56
|
'nitro:config'(nitroConfig) {
|
|
61
57
|
const nuxt = useNuxt()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simple-content-site",
|
|
3
3
|
"description": "Nuxt layer for simple website with basic functions.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -22,27 +22,30 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@iconify-json/lucide": "^1.2.
|
|
26
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
27
|
-
"@iconify-json/vscode-icons": "^1.2.
|
|
28
|
-
"@nuxt/content": "^3.
|
|
29
|
-
"@nuxt/image": "^
|
|
25
|
+
"@iconify-json/lucide": "^1.2.86",
|
|
26
|
+
"@iconify-json/simple-icons": "^1.2.67",
|
|
27
|
+
"@iconify-json/vscode-icons": "^1.2.40",
|
|
28
|
+
"@nuxt/content": "^3.11.0",
|
|
29
|
+
"@nuxt/image": "^2.0.0",
|
|
30
30
|
"@nuxt/kit": "^4.2.2",
|
|
31
|
-
"@nuxt/ui": "^4.
|
|
31
|
+
"@nuxt/ui": "^4.4.0",
|
|
32
32
|
"@nuxtjs/i18n": "^10.2.1",
|
|
33
|
-
"@nuxtjs/mdc": "^0.
|
|
33
|
+
"@nuxtjs/mdc": "^0.20.0",
|
|
34
34
|
"@nuxtjs/robots": "^5.6.7",
|
|
35
|
-
"@vueuse/core": "^
|
|
35
|
+
"@vueuse/core": "^14.1.0",
|
|
36
|
+
"@nuxt/fonts": "^0.14.0",
|
|
36
37
|
"defu": "^6.1.4",
|
|
37
38
|
"exsolve": "^1.0.8",
|
|
38
39
|
"git-url-parse": "^16.1.0",
|
|
39
40
|
"minimark": "^0.2.0",
|
|
40
|
-
"motion-v": "^1.
|
|
41
|
+
"motion-v": "^1.9.0",
|
|
41
42
|
"nuxt-og-image": "^5.1.13",
|
|
42
43
|
"pkg-types": "^2.3.0",
|
|
43
44
|
"scule": "^1.3.0",
|
|
44
|
-
"tailwindcss": "^4.1.
|
|
45
|
-
"ufo": "^1.6.
|
|
45
|
+
"tailwindcss": "^4.1.18",
|
|
46
|
+
"ufo": "^1.6.3",
|
|
47
|
+
"zod": "^4.3.5",
|
|
48
|
+
"zod-to-json-schema": "^3.25.1"
|
|
46
49
|
},
|
|
47
50
|
"peerDependencies": {
|
|
48
51
|
"better-sqlite3": "12.x",
|
|
@@ -6,7 +6,7 @@ import type { Collections } from '@nuxt/content'
|
|
|
6
6
|
export default eventHandler(async (event) => {
|
|
7
7
|
const slug = getRouterParams(event)['slug.md']
|
|
8
8
|
if (!slug?.endsWith('.md')) {
|
|
9
|
-
throw createError({
|
|
9
|
+
throw createError({ status: 404, message: 'Page not found', fatal: true })
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const path = withLeadingSlash(slug.replace('.md', ''))
|
|
@@ -31,7 +31,7 @@ export default eventHandler(async (event) => {
|
|
|
31
31
|
|
|
32
32
|
const page = await queryCollection(event, collectionName as keyof Omit<Collections, 'header' | 'footer'>).path(path).first()
|
|
33
33
|
if (!page) {
|
|
34
|
-
throw createError({
|
|
34
|
+
throw createError({ status: 404, message: 'Page not found', fatal: true })
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Add title and description to the top of the page if missing
|