simple-content-site 1.0.2
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 +29 -0
- package/app/app.vue +77 -0
- package/app/components/IconMenuToggle.vue +83 -0
- package/app/components/LanguageSelect.vue +82 -0
- package/app/components/OgImage/OgImageDocs.vue +76 -0
- package/app/components/OgImage/OgImageLanding.vue +73 -0
- package/app/components/app/AppFooter.vue +11 -0
- package/app/components/app/AppFooterLeft.vue +5 -0
- package/app/components/app/AppFooterRight.vue +30 -0
- package/app/components/app/AppHeader.vue +82 -0
- package/app/components/app/AppHeaderBody.vue +13 -0
- package/app/components/app/AppHeaderCTA.vue +3 -0
- package/app/components/app/AppHeaderCenter.vue +10 -0
- package/app/components/app/AppHeaderLogo.vue +16 -0
- package/app/components/docs/DocsAsideLeftBody.vue +12 -0
- package/app/components/docs/DocsAsideLeftTop.vue +3 -0
- package/app/components/docs/DocsAsideRightBottom.vue +18 -0
- package/app/components/docs/DocsPageHeaderLinks.vue +74 -0
- package/app/composables/useDocusI18n.ts +33 -0
- package/app/error.vue +76 -0
- package/app/layouts/default.vue +5 -0
- package/app/layouts/page.vue +7 -0
- package/app/pages/[[lang]]/[...slug].vue +56 -0
- package/app/plugins/i18n.ts +16 -0
- package/app/templates/landing.vue +44 -0
- package/app/types/index.d.ts +39 -0
- package/app/utils/navigation.ts +7 -0
- package/app/utils/prerender.ts +12 -0
- package/content.config.ts +74 -0
- package/i18n/locales/ar.json +22 -0
- package/i18n/locales/be.json +23 -0
- package/i18n/locales/bn.json +22 -0
- package/i18n/locales/ca.json +22 -0
- package/i18n/locales/ckb.json +18 -0
- package/i18n/locales/cs.json +22 -0
- package/i18n/locales/da.json +22 -0
- package/i18n/locales/de.json +22 -0
- package/i18n/locales/el.json +22 -0
- package/i18n/locales/en.json +22 -0
- package/i18n/locales/et.json +22 -0
- package/i18n/locales/fr.json +22 -0
- package/i18n/locales/he.json +22 -0
- package/i18n/locales/hi.json +22 -0
- package/i18n/locales/hy.json +22 -0
- package/i18n/locales/it.json +22 -0
- package/i18n/locales/ja.json +22 -0
- package/i18n/locales/kk.json +22 -0
- package/i18n/locales/km.json +22 -0
- package/i18n/locales/ko.json +22 -0
- package/i18n/locales/ky.json +22 -0
- package/i18n/locales/lb.json +22 -0
- package/i18n/locales/ms.json +22 -0
- package/i18n/locales/nb.json +22 -0
- package/i18n/locales/pl.json +23 -0
- package/i18n/locales/ru.json +23 -0
- package/i18n/locales/sl.json +22 -0
- package/i18n/locales/sv.json +22 -0
- package/i18n/locales/uk.json +22 -0
- package/i18n/locales/ur.json +22 -0
- package/i18n/locales/vi.json +22 -0
- package/modules/config.ts +116 -0
- package/modules/css.ts +32 -0
- package/modules/routing.ts +41 -0
- package/nuxt.config.ts +75 -0
- package/nuxt.schema.ts +218 -0
- package/package.json +52 -0
- package/server/routes/raw/[...slug].md.get.ts +45 -0
- package/utils/git.ts +110 -0
- package/utils/meta.ts +29 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default defineAppConfig({
|
|
2
|
+
ui: {
|
|
3
|
+
colors: {
|
|
4
|
+
primary: 'emerald',
|
|
5
|
+
neutral: 'zinc',
|
|
6
|
+
},
|
|
7
|
+
commandPalette: {
|
|
8
|
+
slots: {
|
|
9
|
+
input: '[&_.iconify]:size-4 [&_.iconify]:mx-0.5',
|
|
10
|
+
itemLeadingIcon: 'size-4 mx-0.5',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
contentNavigation: {
|
|
14
|
+
slots: {
|
|
15
|
+
linkLeadingIcon: 'size-4 mr-1',
|
|
16
|
+
linkTrailing: 'hidden',
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: 'link',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
pageLinks: {
|
|
23
|
+
slots: {
|
|
24
|
+
linkLeadingIcon: 'size-4',
|
|
25
|
+
linkLabelExternalIcon: 'size-2.5',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
})
|
package/app/app.vue
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PageCollections } from '@nuxt/content'
|
|
3
|
+
import * as nuxtUiLocales from '@nuxt/ui/locale'
|
|
4
|
+
|
|
5
|
+
const { seo } = useAppConfig()
|
|
6
|
+
const site = useSiteConfig()
|
|
7
|
+
const { locale, locales, isEnabled, switchLocalePath } = useDocusI18n()
|
|
8
|
+
|
|
9
|
+
const lang = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.code || 'en')
|
|
10
|
+
const dir = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.dir || 'ltr')
|
|
11
|
+
const collectionName = computed(() => isEnabled.value ? `pages_${locale.value}` : 'pages')
|
|
12
|
+
|
|
13
|
+
useHead({
|
|
14
|
+
meta: [
|
|
15
|
+
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
|
16
|
+
],
|
|
17
|
+
link: [
|
|
18
|
+
{ rel: 'icon', href: '/favicon.ico' },
|
|
19
|
+
],
|
|
20
|
+
htmlAttrs: {
|
|
21
|
+
lang,
|
|
22
|
+
dir,
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
useSeoMeta({
|
|
27
|
+
titleTemplate: seo.titleTemplate,
|
|
28
|
+
title: seo.title,
|
|
29
|
+
description: seo.description,
|
|
30
|
+
ogSiteName: site.name,
|
|
31
|
+
twitterCard: 'summary_large_image',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
if (isEnabled.value) {
|
|
35
|
+
const route = useRoute()
|
|
36
|
+
const defaultLocale = useRuntimeConfig().public.i18n.defaultLocale!
|
|
37
|
+
onMounted(() => {
|
|
38
|
+
const currentLocale = route.path.split('/')[1]
|
|
39
|
+
if (!locales.some(locale => locale.code === currentLocale)) {
|
|
40
|
+
return navigateTo(switchLocalePath(defaultLocale) as string)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { data: navigation } = await useAsyncData(() => `navigation_${collectionName.value}`, () => queryCollectionNavigation(collectionName.value as keyof PageCollections), {
|
|
46
|
+
transform: (data) => {
|
|
47
|
+
const rootResult = data.find(item => item.path === '/pages')?.children || data || []
|
|
48
|
+
|
|
49
|
+
return rootResult.find(item => item.path === `/${locale.value}`)?.children || rootResult
|
|
50
|
+
},
|
|
51
|
+
watch: [locale],
|
|
52
|
+
})
|
|
53
|
+
const { data: files } = useLazyAsyncData(`search_${collectionName.value}`, () => queryCollectionSearchSections(collectionName.value as keyof PageCollections), {
|
|
54
|
+
server: false,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
provide('navigation', navigation)
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<UApp :locale="nuxtUiLocales[locale as keyof typeof nuxtUiLocales]">
|
|
62
|
+
<NuxtLoadingIndicator color="var(--ui-primary)" />
|
|
63
|
+
|
|
64
|
+
<AppHeader v-if="$route.meta.header !== false" />
|
|
65
|
+
<NuxtLayout>
|
|
66
|
+
<NuxtPage />
|
|
67
|
+
</NuxtLayout>
|
|
68
|
+
<AppFooter v-if="$route.meta.footer !== false" />
|
|
69
|
+
|
|
70
|
+
<ClientOnly>
|
|
71
|
+
<LazyUContentSearch
|
|
72
|
+
:files="files"
|
|
73
|
+
:navigation="navigation"
|
|
74
|
+
/>
|
|
75
|
+
</ClientOnly>
|
|
76
|
+
</UApp>
|
|
77
|
+
</template>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { motion } from 'motion-v'
|
|
3
|
+
import type { VariantType } from 'motion-v'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
open: boolean
|
|
7
|
+
}>()
|
|
8
|
+
|
|
9
|
+
const variants: { [k: string]: VariantType | ((custom: unknown) => VariantType) } = {
|
|
10
|
+
normal: {
|
|
11
|
+
rotate: 0,
|
|
12
|
+
y: 0,
|
|
13
|
+
opacity: 1,
|
|
14
|
+
},
|
|
15
|
+
close: (custom: unknown) => {
|
|
16
|
+
const c = custom as number
|
|
17
|
+
return {
|
|
18
|
+
rotate: c === 1 ? 45 : c === 3 ? -45 : 0,
|
|
19
|
+
y: c === 1 ? 6 : c === 3 ? -6 : 0,
|
|
20
|
+
opacity: c === 2 ? 0 : 1,
|
|
21
|
+
transition: {
|
|
22
|
+
type: 'spring',
|
|
23
|
+
stiffness: 260,
|
|
24
|
+
damping: 20,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const state = computed(() => props.open ? 'close' : 'normal')
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<UButton
|
|
35
|
+
size="sm"
|
|
36
|
+
variant="ghost"
|
|
37
|
+
color="neutral"
|
|
38
|
+
class="-me-1.5"
|
|
39
|
+
square
|
|
40
|
+
>
|
|
41
|
+
<svg
|
|
42
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
43
|
+
class="size-5"
|
|
44
|
+
viewBox="0 0 24 24"
|
|
45
|
+
fill="none"
|
|
46
|
+
stroke="currentColor"
|
|
47
|
+
stroke-width="2"
|
|
48
|
+
stroke-linecap="round"
|
|
49
|
+
stroke-linejoin="round"
|
|
50
|
+
>
|
|
51
|
+
<motion.line
|
|
52
|
+
x1="4"
|
|
53
|
+
y1="6"
|
|
54
|
+
x2="20"
|
|
55
|
+
y2="6"
|
|
56
|
+
:variants="variants"
|
|
57
|
+
:animate="state"
|
|
58
|
+
:custom="1"
|
|
59
|
+
class="outline-none"
|
|
60
|
+
/>
|
|
61
|
+
<motion.line
|
|
62
|
+
x1="4"
|
|
63
|
+
y1="12"
|
|
64
|
+
x2="20"
|
|
65
|
+
y2="12"
|
|
66
|
+
:variants="variants"
|
|
67
|
+
:animate="state"
|
|
68
|
+
:custom="2"
|
|
69
|
+
class="outline-none"
|
|
70
|
+
/>
|
|
71
|
+
<motion.line
|
|
72
|
+
x1="4"
|
|
73
|
+
y1="18"
|
|
74
|
+
x2="20"
|
|
75
|
+
y2="18"
|
|
76
|
+
:variants="variants"
|
|
77
|
+
:animate="state"
|
|
78
|
+
:custom="3"
|
|
79
|
+
class="outline-none"
|
|
80
|
+
/>
|
|
81
|
+
</svg>
|
|
82
|
+
</UButton>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const { locale, locales, switchLocalePath } = useDocusI18n()
|
|
3
|
+
|
|
4
|
+
function getEmojiFlag(locale: string): string {
|
|
5
|
+
const languageToCountry: Record<string, string> = {
|
|
6
|
+
ar: 'sa', // Arabic -> Saudi Arabia
|
|
7
|
+
bn: 'bd', // Bengali -> Bangladesh
|
|
8
|
+
ca: 'es', // Catalan -> Spain
|
|
9
|
+
ckb: 'iq', // Central Kurdish -> Iraq
|
|
10
|
+
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
|
11
|
+
da: 'dk', // Danish -> Denmark
|
|
12
|
+
el: 'gr', // Greek -> Greece
|
|
13
|
+
en: 'gb', // English -> Great Britain
|
|
14
|
+
et: 'ee', // Estonian -> Estonia
|
|
15
|
+
he: 'il', // Hebrew -> Israel
|
|
16
|
+
hi: 'in', // Hindi -> India
|
|
17
|
+
hy: 'am', // Armenian -> Armenia
|
|
18
|
+
ja: 'jp', // Japanese -> Japan
|
|
19
|
+
kk: 'kz', // Kazakh -> Kazakhstan
|
|
20
|
+
km: 'kh', // Khmer -> Cambodia
|
|
21
|
+
ko: 'kr', // Korean -> South Korea
|
|
22
|
+
ky: 'kg', // Kyrgyz -> Kyrgyzstan
|
|
23
|
+
lb: 'lu', // Luxembourgish -> Luxembourg
|
|
24
|
+
ms: 'my', // Malay -> Malaysia
|
|
25
|
+
nb: 'no', // Norwegian Bokmål -> Norway
|
|
26
|
+
sl: 'si', // Slovenian -> Slovenia
|
|
27
|
+
sv: 'se', // Swedish -> Sweden
|
|
28
|
+
uk: 'ua', // Ukrainian -> Ukraine
|
|
29
|
+
ur: 'pk', // Urdu -> Pakistan
|
|
30
|
+
vi: 'vn', // Vietnamese -> Vietnam
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale
|
|
34
|
+
const countryCode = languageToCountry[baseLanguage] || locale.replace(/^.*-/, '').slice(0, 2)
|
|
35
|
+
|
|
36
|
+
return countryCode.toUpperCase()
|
|
37
|
+
.split('')
|
|
38
|
+
.map(char => String.fromCodePoint(0x1F1A5 + char.charCodeAt(0)))
|
|
39
|
+
.join('')
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<UPopover
|
|
45
|
+
mode="hover"
|
|
46
|
+
:content="{ align: 'end' }"
|
|
47
|
+
>
|
|
48
|
+
<UButton
|
|
49
|
+
color="neutral"
|
|
50
|
+
variant="ghost"
|
|
51
|
+
class="size-8"
|
|
52
|
+
>
|
|
53
|
+
<template #trailing>
|
|
54
|
+
<span class="text-lg">
|
|
55
|
+
{{ getEmojiFlag(locale) }}
|
|
56
|
+
</span>
|
|
57
|
+
</template>
|
|
58
|
+
</UButton>
|
|
59
|
+
|
|
60
|
+
<template #content>
|
|
61
|
+
<ul class="flex flex-col">
|
|
62
|
+
<li
|
|
63
|
+
v-for="localeItem in locales"
|
|
64
|
+
:key="localeItem.code"
|
|
65
|
+
>
|
|
66
|
+
<NuxtLink
|
|
67
|
+
class="flex justify-between py-1.5 px-2 gap-1 hover:bg-muted"
|
|
68
|
+
:to="switchLocalePath(localeItem.code) as string"
|
|
69
|
+
:aria-label="localeItem.name"
|
|
70
|
+
>
|
|
71
|
+
<span class="text-sm">
|
|
72
|
+
{{ localeItem.name }}
|
|
73
|
+
</span>
|
|
74
|
+
<span class="size-5 text-center">
|
|
75
|
+
{{ getEmojiFlag(localeItem.code) }}
|
|
76
|
+
</span>
|
|
77
|
+
</NuxtLink>
|
|
78
|
+
</li>
|
|
79
|
+
</ul>
|
|
80
|
+
</template>
|
|
81
|
+
</UPopover>
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{ title?: string, description?: string, headline?: string }>(), {
|
|
3
|
+
title: 'title',
|
|
4
|
+
description: 'description',
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
const title = computed(() => (props.title || '').slice(0, 60))
|
|
8
|
+
const description = computed(() => (props.description || '').slice(0, 200))
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="w-full h-full flex flex-col justify-center bg-neutral-900">
|
|
13
|
+
<svg
|
|
14
|
+
class="absolute right-0 top-0 opacity-50"
|
|
15
|
+
width="629"
|
|
16
|
+
height="593"
|
|
17
|
+
viewBox="0 0 629 593"
|
|
18
|
+
fill="none"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
>
|
|
21
|
+
<g filter="url(#filter0_f_199_94966)">
|
|
22
|
+
<path
|
|
23
|
+
d="M628.5 -578L639.334 -94.4223L806.598 -548.281L659.827 -87.387L965.396 -462.344L676.925 -74.0787L1087.69 -329.501L688.776 -55.9396L1160.22 -164.149L694.095 -34.9354L1175.13 15.7948L692.306 -13.3422L1130.8 190.83L683.602 6.50012L1032.04 341.989L668.927 22.4412L889.557 452.891L649.872 32.7537L718.78 511.519L628.5 36.32L538.22 511.519L607.128 32.7537L367.443 452.891L588.073 22.4412L224.955 341.989L573.398 6.50012L126.198 190.83L564.694 -13.3422L81.8734 15.7948L562.905 -34.9354L96.7839 -164.149L568.224 -55.9396L169.314 -329.501L580.075 -74.0787L291.604 -462.344L597.173 -87.387L450.402 -548.281L617.666 -94.4223L628.5 -578Z"
|
|
24
|
+
fill="white"
|
|
25
|
+
/>
|
|
26
|
+
</g>
|
|
27
|
+
<defs>
|
|
28
|
+
<filter
|
|
29
|
+
id="filter0_f_199_94966"
|
|
30
|
+
x="0.873535"
|
|
31
|
+
y="-659"
|
|
32
|
+
width="1255.25"
|
|
33
|
+
height="1251.52"
|
|
34
|
+
filterUnits="userSpaceOnUse"
|
|
35
|
+
color-interpolation-filters="sRGB"
|
|
36
|
+
>
|
|
37
|
+
<feFlood
|
|
38
|
+
flood-opacity="0"
|
|
39
|
+
result="BackgroundImageFix"
|
|
40
|
+
/>
|
|
41
|
+
<feBlend
|
|
42
|
+
mode="normal"
|
|
43
|
+
in="SourceGraphic"
|
|
44
|
+
in2="BackgroundImageFix"
|
|
45
|
+
result="shape"
|
|
46
|
+
/>
|
|
47
|
+
<feGaussianBlur
|
|
48
|
+
stdDeviation="40.5"
|
|
49
|
+
result="effect1_foregroundBlur_199_94966"
|
|
50
|
+
/>
|
|
51
|
+
</filter>
|
|
52
|
+
</defs>
|
|
53
|
+
</svg>
|
|
54
|
+
|
|
55
|
+
<div class="pl-[100px]">
|
|
56
|
+
<p
|
|
57
|
+
v-if="headline"
|
|
58
|
+
class="uppercase text-[24px] text-emerald-500 mb-4 font-semibold"
|
|
59
|
+
>
|
|
60
|
+
{{ headline }}
|
|
61
|
+
</p>
|
|
62
|
+
<h1
|
|
63
|
+
v-if="title"
|
|
64
|
+
class="m-0 text-[75px] font-semibold mb-4 text-white flex items-center"
|
|
65
|
+
>
|
|
66
|
+
<span>{{ title }}</span>
|
|
67
|
+
</h1>
|
|
68
|
+
<p
|
|
69
|
+
v-if="description"
|
|
70
|
+
class="text-[32px] text-neutral-300 leading-tight w-[700px]"
|
|
71
|
+
>
|
|
72
|
+
{{ description }}
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{ title?: string, description?: string, headline?: string }>(), {
|
|
3
|
+
title: 'title',
|
|
4
|
+
description: 'description',
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
const title = computed(() => (props.title || '').slice(0, 60))
|
|
8
|
+
const description = computed(() => (props.description || '').slice(0, 200))
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="w-full h-full flex items-center justify-center bg-neutral-900">
|
|
13
|
+
<svg
|
|
14
|
+
class="absolute right-0 top-0 opacity-50 "
|
|
15
|
+
width="629"
|
|
16
|
+
height="593"
|
|
17
|
+
viewBox="0 0 629 593"
|
|
18
|
+
fill="none"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
>
|
|
21
|
+
<g filter="url(#filter0_f_199_94966)">
|
|
22
|
+
<path
|
|
23
|
+
d="M628.5 -578L639.334 -94.4223L806.598 -548.281L659.827 -87.387L965.396 -462.344L676.925 -74.0787L1087.69 -329.501L688.776 -55.9396L1160.22 -164.149L694.095 -34.9354L1175.13 15.7948L692.306 -13.3422L1130.8 190.83L683.602 6.50012L1032.04 341.989L668.927 22.4412L889.557 452.891L649.872 32.7537L718.78 511.519L628.5 36.32L538.22 511.519L607.128 32.7537L367.443 452.891L588.073 22.4412L224.955 341.989L573.398 6.50012L126.198 190.83L564.694 -13.3422L81.8734 15.7948L562.905 -34.9354L96.7839 -164.149L568.224 -55.9396L169.314 -329.501L580.075 -74.0787L291.604 -462.344L597.173 -87.387L450.402 -548.281L617.666 -94.4223L628.5 -578Z"
|
|
24
|
+
fill="white"
|
|
25
|
+
/>
|
|
26
|
+
</g>
|
|
27
|
+
<defs>
|
|
28
|
+
<filter
|
|
29
|
+
id="filter0_f_199_94966"
|
|
30
|
+
x="0.873535"
|
|
31
|
+
y="-659"
|
|
32
|
+
width="1255.25"
|
|
33
|
+
height="1251.52"
|
|
34
|
+
filterUnits="userSpaceOnUse"
|
|
35
|
+
color-interpolation-filters="sRGB"
|
|
36
|
+
>
|
|
37
|
+
<feFlood
|
|
38
|
+
flood-opacity="0"
|
|
39
|
+
result="BackgroundImageFix"
|
|
40
|
+
/>
|
|
41
|
+
<feBlend
|
|
42
|
+
mode="normal"
|
|
43
|
+
in="SourceGraphic"
|
|
44
|
+
in2="BackgroundImageFix"
|
|
45
|
+
result="shape"
|
|
46
|
+
/>
|
|
47
|
+
<feGaussianBlur
|
|
48
|
+
stdDeviation="40.5"
|
|
49
|
+
result="effect1_foregroundBlur_199_94966"
|
|
50
|
+
/>
|
|
51
|
+
</filter>
|
|
52
|
+
</defs>
|
|
53
|
+
</svg>
|
|
54
|
+
|
|
55
|
+
<div class="flex flex-col justify-center p-8">
|
|
56
|
+
<div class="flex justify-center mb-8">
|
|
57
|
+
<AppHeaderLogo white />
|
|
58
|
+
</div>
|
|
59
|
+
<h1
|
|
60
|
+
v-if="title"
|
|
61
|
+
class="flex justify-center m-0 text-5xl font-semibold mb-4 text-white"
|
|
62
|
+
>
|
|
63
|
+
<span>{{ title }}</span>
|
|
64
|
+
</h1>
|
|
65
|
+
<p
|
|
66
|
+
v-if="description"
|
|
67
|
+
class="text-center text-2xl text-neutral-300 leading-tight"
|
|
68
|
+
>
|
|
69
|
+
{{ description }}
|
|
70
|
+
</p>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const appConfig = useAppConfig()
|
|
3
|
+
|
|
4
|
+
const links = computed(() => [
|
|
5
|
+
...Object.entries(appConfig.socials || {}).map(([key, url]) => ({
|
|
6
|
+
'icon': `i-simple-icons-${key}`,
|
|
7
|
+
'to': url,
|
|
8
|
+
'target': '_blank',
|
|
9
|
+
'aria-label': `${key} social link`,
|
|
10
|
+
})),
|
|
11
|
+
appConfig.github && appConfig.github.url && {
|
|
12
|
+
'icon': 'i-simple-icons-github',
|
|
13
|
+
'to': appConfig.github.url,
|
|
14
|
+
'target': '_blank',
|
|
15
|
+
'aria-label': 'GitHub repository',
|
|
16
|
+
},
|
|
17
|
+
].filter(Boolean))
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<template v-if="links.length">
|
|
22
|
+
<UButton
|
|
23
|
+
v-for="(link, index) of links"
|
|
24
|
+
:key="index"
|
|
25
|
+
size="sm"
|
|
26
|
+
v-bind="{ color: 'neutral', variant: 'ghost', ...link }"
|
|
27
|
+
/>
|
|
28
|
+
</template>
|
|
29
|
+
<UColorModeButton />
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useDocusI18n } from '../../composables/useDocusI18n'
|
|
3
|
+
|
|
4
|
+
const appConfig = useAppConfig()
|
|
5
|
+
const site = useSiteConfig()
|
|
6
|
+
|
|
7
|
+
const { localePath, isEnabled, locales } = useDocusI18n()
|
|
8
|
+
|
|
9
|
+
const links = computed(() => appConfig.github && appConfig.github.url
|
|
10
|
+
? [
|
|
11
|
+
{
|
|
12
|
+
'icon': 'i-simple-icons-github',
|
|
13
|
+
'to': appConfig.github.url,
|
|
14
|
+
'target': '_blank',
|
|
15
|
+
'aria-label': 'GitHub',
|
|
16
|
+
},
|
|
17
|
+
]
|
|
18
|
+
: [])
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<UHeader
|
|
23
|
+
:ui="{ center: 'flex-1' }"
|
|
24
|
+
:to="localePath('/')"
|
|
25
|
+
:title="appConfig.header?.title || site.name"
|
|
26
|
+
>
|
|
27
|
+
<AppHeaderCenter />
|
|
28
|
+
|
|
29
|
+
<template #title>
|
|
30
|
+
<AppHeaderLogo class="h-6 w-auto shrink-0" />
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<template #right>
|
|
34
|
+
<AppHeaderCTA />
|
|
35
|
+
|
|
36
|
+
<template v-if="isEnabled && locales.length > 1">
|
|
37
|
+
<ClientOnly>
|
|
38
|
+
<LanguageSelect />
|
|
39
|
+
|
|
40
|
+
<template #fallback>
|
|
41
|
+
<div class="h-8 w-8 animate-pulse bg-neutral-200 dark:bg-neutral-800 rounded-md" />
|
|
42
|
+
</template>
|
|
43
|
+
</ClientOnly>
|
|
44
|
+
|
|
45
|
+
<USeparator
|
|
46
|
+
orientation="vertical"
|
|
47
|
+
class="h-8"
|
|
48
|
+
/>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<UContentSearchButton class="lg:hidden" />
|
|
52
|
+
|
|
53
|
+
<ClientOnly>
|
|
54
|
+
<UColorModeButton />
|
|
55
|
+
|
|
56
|
+
<template #fallback>
|
|
57
|
+
<div class="h-8 w-8 animate-pulse bg-neutral-200 dark:bg-neutral-800 rounded-md" />
|
|
58
|
+
</template>
|
|
59
|
+
</ClientOnly>
|
|
60
|
+
|
|
61
|
+
<template v-if="links?.length">
|
|
62
|
+
<UButton
|
|
63
|
+
v-for="(link, index) of links"
|
|
64
|
+
:key="index"
|
|
65
|
+
v-bind="{ color: 'neutral', variant: 'ghost', ...link }"
|
|
66
|
+
/>
|
|
67
|
+
</template>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<template #toggle="{ open, toggle }">
|
|
71
|
+
<IconMenuToggle
|
|
72
|
+
:open="open"
|
|
73
|
+
class="lg:hidden"
|
|
74
|
+
@click="toggle"
|
|
75
|
+
/>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<template #body>
|
|
79
|
+
<AppHeaderBody />
|
|
80
|
+
</template>
|
|
81
|
+
</UHeader>
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ContentNavigationItem } from '@nuxt/content'
|
|
3
|
+
|
|
4
|
+
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<UContentNavigation
|
|
9
|
+
highlight
|
|
10
|
+
variant="link"
|
|
11
|
+
:navigation="navigation"
|
|
12
|
+
/>
|
|
13
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const appConfig = useAppConfig()
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<UColorModeImage
|
|
7
|
+
v-if="appConfig.header?.logo?.dark || appConfig.header?.logo?.light"
|
|
8
|
+
:light="appConfig.header?.logo?.light || appConfig.header?.logo?.dark"
|
|
9
|
+
:dark="appConfig.header?.logo?.dark || appConfig.header?.logo?.light"
|
|
10
|
+
:alt="appConfig.header?.logo?.alt || appConfig.header?.title"
|
|
11
|
+
class="h-6 w-auto shrink-0"
|
|
12
|
+
/>
|
|
13
|
+
<span v-else>
|
|
14
|
+
{{ appConfig.header?.title || '{appConfig.header.title}' }}
|
|
15
|
+
</span>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ContentNavigationItem } from '@nuxt/content'
|
|
3
|
+
|
|
4
|
+
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<UContentNavigation
|
|
9
|
+
highlight
|
|
10
|
+
:navigation="navigation"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const appConfig = useAppConfig()
|
|
3
|
+
const { t } = useDocusI18n()
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<div
|
|
8
|
+
v-if="appConfig.toc?.bottom?.links?.length"
|
|
9
|
+
class="hidden lg:block space-y-6"
|
|
10
|
+
>
|
|
11
|
+
<USeparator type="dashed" />
|
|
12
|
+
|
|
13
|
+
<UPageLinks
|
|
14
|
+
:title="appConfig.toc?.bottom?.title || t('docs.links')"
|
|
15
|
+
:links="appConfig.toc?.bottom?.links"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|