docus 3.0.0-beta.4 → 3.0.0-beta.5
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/package.json +12 -19
- package/{app → theme/app}/router.options.ts +0 -0
- package/{assets → theme/assets}/css/fonts.css +0 -0
- package/theme/assets/css/main.css +104 -0
- package/{components → theme/components}/app/Container.vue +0 -0
- package/{components → theme/components}/app/Footer.vue +4 -4
- package/theme/components/app/MobileNav.vue +83 -0
- package/theme/components/app/Navbar.vue +37 -0
- package/{components → theme/components}/app/NavbarLogo.vue +4 -4
- package/{components → theme/components}/app/Page.vue +0 -0
- package/{components → theme/components}/app/PoweredByDocus.vue +0 -0
- package/{components → theme/components}/content/Alert.vue +0 -0
- package/{components → theme/components}/content/BlockHero.vue +0 -0
- package/{components → theme/components}/content/ButtonLink.vue +1 -1
- package/{components → theme/components}/content/Card.vue +0 -0
- package/{components → theme/components}/content/CardGrid.vue +0 -0
- package/{components → theme/components}/content/CodeBlock.vue +0 -0
- package/{components → theme/components}/content/CodeGroup.vue +6 -6
- package/{components → theme/components}/content/CopyButton.vue +0 -0
- package/{components → theme/components}/content/List.vue +0 -0
- package/{components → theme/components}/content/NeedContribution.vue +0 -0
- package/{components → theme/components}/content/ReadMore.vue +0 -0
- package/{components → theme/components}/content/Sandbox.vue +2 -2
- package/{components → theme/components}/content/TabsHeader.vue +2 -2
- package/{components → theme/components}/content/Terminal.vue +0 -0
- package/{components → theme/components}/content/VideoPlayer.vue +0 -0
- package/theme/components/dev/Debug.vue +63 -0
- package/{components → theme/components}/docs/DocsAside.vue +2 -2
- package/{components → theme/components}/docs/DocsAsideTree.vue +8 -6
- package/{components → theme/components}/docs/DocsHero.vue +0 -0
- package/{components → theme/components}/docs/DocsPage.vue +0 -1
- package/theme/components/docs/DocsPageContent.vue +32 -0
- package/{components → theme/components}/docs/DocsToc.vue +15 -12
- package/{components → theme/components}/globals/Icon.vue +0 -0
- package/{components → theme/components}/globals/Logo.vue +0 -0
- package/{components → theme/components}/globals/NuxtImg.vue +0 -0
- package/{components → theme/components}/globals/SocialIcons.vue +2 -2
- package/{components → theme/components}/globals/ThemeSelect.vue +0 -0
- package/{components → theme/components}/icons/IconAlgolia.vue +0 -0
- package/{components → theme/components}/icons/IconArrowLeft.vue +0 -0
- package/{components → theme/components}/icons/IconArrowRight.vue +0 -0
- package/{components → theme/components}/icons/IconBadgeCheck.vue +0 -0
- package/{components → theme/components}/icons/IconCheck.vue +0 -0
- package/{components → theme/components}/icons/IconCheckCircle.vue +0 -0
- package/{components → theme/components}/icons/IconChevronRight.vue +0 -0
- package/{components → theme/components}/icons/IconClipboardCheck.vue +0 -0
- package/{components → theme/components}/icons/IconClipboardCopy.vue +0 -0
- package/{components → theme/components}/icons/IconCodeSandbox.vue +0 -0
- package/{components → theme/components}/icons/IconCopy.vue +0 -0
- package/{components → theme/components}/icons/IconDots.vue +0 -0
- package/{components → theme/components}/icons/IconEdit.vue +0 -0
- package/{components → theme/components}/icons/IconExclamationCircle.vue +0 -0
- package/{components → theme/components}/icons/IconExclamationTriangle.vue +0 -0
- package/{components → theme/components}/icons/IconExternalLink.vue +0 -0
- package/{components → theme/components}/icons/IconGit.vue +0 -0
- package/{components → theme/components}/icons/IconGitHub.vue +0 -0
- package/{components → theme/components}/icons/IconHeart.vue +0 -0
- package/{components → theme/components}/icons/IconInformationCircle.vue +0 -0
- package/{components → theme/components}/icons/IconLighthouse.vue +0 -0
- package/{components → theme/components}/icons/IconLine.vue +0 -0
- package/{components → theme/components}/icons/IconMarkdown.vue +0 -0
- package/{components → theme/components}/icons/IconMenu.vue +0 -0
- package/{components → theme/components}/icons/IconMenuAlt.vue +0 -0
- package/{components → theme/components}/icons/IconMinus.vue +0 -0
- package/{components → theme/components}/icons/IconMoon.vue +0 -0
- package/{components → theme/components}/icons/IconNuxt.vue +0 -0
- package/{components → theme/components}/icons/IconNuxtContent.vue +0 -0
- package/{components → theme/components}/icons/IconNuxtLabs.vue +0 -0
- package/{components → theme/components}/icons/IconPlus.vue +0 -0
- package/{components → theme/components}/icons/IconPuzzle.vue +0 -0
- package/{components → theme/components}/icons/IconSSG.vue +0 -0
- package/{components → theme/components}/icons/IconSearch.vue +0 -0
- package/{components → theme/components}/icons/IconSun.vue +0 -0
- package/theme/components/icons/IconTailwind.vue +3 -0
- package/{components → theme/components}/icons/IconTocBack.vue +0 -0
- package/{components → theme/components}/icons/IconTocCurrent.vue +0 -0
- package/{components → theme/components}/icons/IconTocNext.vue +0 -0
- package/{components → theme/components}/icons/IconTranslate.vue +0 -0
- package/{components → theme/components}/icons/IconTwitter.vue +0 -0
- package/{components → theme/components}/icons/IconVite.vue +0 -0
- package/{components → theme/components}/icons/IconVue.vue +0 -0
- package/{components → theme/components}/icons/IconVueTelescope.vue +0 -0
- package/{components → theme/components}/icons/IconWindi.vue +0 -0
- package/{components → theme/components}/icons/IconX.vue +0 -0
- package/{components → theme/components}/icons/IconXCircle.vue +0 -0
- package/{components → theme/components}/icons/IconZap.vue +0 -0
- package/{components → theme/components}/prose/ProseA.vue +3 -3
- package/{components → theme/components}/prose/ProseBlockquote.vue +1 -1
- package/{components → theme/components}/prose/ProseCode.vue +3 -4
- package/{components → theme/components}/prose/ProseCodeInline.vue +2 -2
- package/{components → theme/components}/prose/ProseEm.vue +0 -0
- package/{components → theme/components}/prose/ProseH1.vue +0 -0
- package/{components → theme/components}/prose/ProseH2.vue +0 -0
- package/{components → theme/components}/prose/ProseH3.vue +0 -0
- package/{components → theme/components}/prose/ProseH4.vue +0 -0
- package/{components → theme/components}/prose/ProseHr.vue +1 -1
- package/{components → theme/components}/prose/ProseImg.vue +0 -0
- package/{components → theme/components}/prose/ProseLi.vue +2 -2
- package/{components → theme/components}/prose/ProseOl.vue +0 -0
- package/{components → theme/components}/prose/ProseP.vue +0 -0
- package/{components → theme/components}/prose/ProseStrong.vue +0 -0
- package/{components → theme/components}/prose/ProseTable.vue +0 -0
- package/{components → theme/components}/prose/ProseTbody.vue +0 -0
- package/{components → theme/components}/prose/ProseTd.vue +0 -0
- package/{components → theme/components}/prose/ProseTh.vue +1 -1
- package/{components → theme/components}/prose/ProseThead.vue +1 -1
- package/{components → theme/components}/prose/ProseTr.vue +1 -1
- package/{components → theme/components}/prose/ProseUl.vue +0 -0
- package/theme/composables/useDocus.ts +42 -0
- package/theme/composables/useMenu.ts +7 -0
- package/{composables → theme/composables}/useScrollToHeading.ts +0 -0
- package/{composables → theme/composables}/useScrollspy.ts +0 -0
- package/theme/composables/useUserAgent.ts +5 -0
- package/{composables/useTheme.ts → theme/composables/utils.ts} +0 -8
- package/{layouts → theme/layouts}/default.vue +6 -8
- package/{layouts → theme/layouts}/page.vue +7 -1
- package/theme/middleware/components.ts +25 -0
- package/theme/middleware/navigation.global.ts +12 -0
- package/theme/middleware/page.ts +8 -0
- package/theme/middleware/theme.global.ts +12 -0
- package/{nuxt.config.ts → theme/nuxt.config.ts} +83 -63
- package/theme/pages/[...slug].vue +62 -0
- package/theme/plugins/menu.ts +65 -0
- package/theme/plugins/user-agent.ts +25 -0
- package/theme/utils/components.ts +25 -0
- package/theme/utils/navigation.ts +49 -0
- package/theme/utils/plugin.ts +21 -0
- package/theme/utils/queries.ts +68 -0
- package/theme/utils/state.ts +32 -0
- package/theme/utils/theme.ts +64 -0
- package/assets/css/main.css +0 -11
- package/assets/css/tailwind.css +0 -282
- package/components/app/Navbar.vue +0 -26
- package/components/docs/DocsPageContent.vue +0 -31
- package/composables/useContent.ts +0 -156
- package/composables/useMenu.ts +0 -22
- package/pages/[...slug].vue +0 -26
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/site.webmanifest +0 -1
|
@@ -6,41 +6,72 @@ import { resolve } from 'pathe'
|
|
|
6
6
|
const themeDir = fileURLToPath(new URL('./', import.meta.url))
|
|
7
7
|
const resolveThemeDir = (path: string) => resolve(themeDir, path)
|
|
8
8
|
|
|
9
|
+
const plugins = []
|
|
10
|
+
|
|
11
|
+
const components = [
|
|
12
|
+
{
|
|
13
|
+
prefix: '',
|
|
14
|
+
path: './components/app',
|
|
15
|
+
global: true,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
prefix: '',
|
|
19
|
+
path: './components/docs',
|
|
20
|
+
global: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
prefix: '',
|
|
24
|
+
path: './components/prose',
|
|
25
|
+
global: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
prefix: '',
|
|
29
|
+
path: './components/globals',
|
|
30
|
+
global: true,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
prefix: '',
|
|
34
|
+
path: './components/content',
|
|
35
|
+
global: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
prefix: '',
|
|
39
|
+
path: './components/icons',
|
|
40
|
+
global: true,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
prefix: '',
|
|
44
|
+
path: './components/icons',
|
|
45
|
+
global: true,
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
// Only register the plugin in development as it's not needed in production
|
|
50
|
+
if (process.env.NODE_ENV === 'development') {
|
|
51
|
+
// Dev plugin
|
|
52
|
+
plugins.push({
|
|
53
|
+
src: resolveThemeDir('utils/plugin.ts'),
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Dev components
|
|
58
|
+
components.push({
|
|
59
|
+
prefix: '',
|
|
60
|
+
path: './components/dev',
|
|
61
|
+
global: true,
|
|
62
|
+
})
|
|
63
|
+
|
|
9
64
|
export default defineNuxtConfig({
|
|
65
|
+
/*
|
|
10
66
|
runtimeConfig: {
|
|
11
67
|
public: {
|
|
12
68
|
plausible: {
|
|
13
69
|
domain: process.env.PLAUSIBLE_DOMAIN,
|
|
14
70
|
},
|
|
15
|
-
theme: {
|
|
16
|
-
title: 'Docus',
|
|
17
|
-
twitter: '@docus_',
|
|
18
|
-
github: 'nuxtlabs/docus',
|
|
19
|
-
header: {
|
|
20
|
-
title: false,
|
|
21
|
-
logo: true,
|
|
22
|
-
},
|
|
23
|
-
footer: {
|
|
24
|
-
credits: {
|
|
25
|
-
icon: 'IconNuxtLabs',
|
|
26
|
-
text: 'Made by Nuxt Labs',
|
|
27
|
-
},
|
|
28
|
-
icons: [
|
|
29
|
-
{
|
|
30
|
-
label: 'NuxtJS',
|
|
31
|
-
href: 'https://nuxtjs.org',
|
|
32
|
-
component: 'IconNuxt',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
label: 'Vue Telescope',
|
|
36
|
-
href: 'https://vuetelescope.com',
|
|
37
|
-
component: 'IconVueTelescope',
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
71
|
},
|
|
43
72
|
},
|
|
73
|
+
*/
|
|
74
|
+
plugins,
|
|
44
75
|
head: {
|
|
45
76
|
title: 'Docus',
|
|
46
77
|
link: [
|
|
@@ -61,46 +92,29 @@ export default defineNuxtConfig({
|
|
|
61
92
|
/**
|
|
62
93
|
* Components
|
|
63
94
|
*/
|
|
64
|
-
components
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
prefix: '',
|
|
82
|
-
path: './components/globals',
|
|
83
|
-
global: true,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
prefix: '',
|
|
87
|
-
path: './components/content',
|
|
88
|
-
global: true,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
prefix: '',
|
|
92
|
-
path: './components/icons',
|
|
93
|
-
global: true,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
95
|
+
// To enable for `components` middleware
|
|
96
|
+
//
|
|
97
|
+
// components: [
|
|
98
|
+
// './components/app',
|
|
99
|
+
// './components/docs',
|
|
100
|
+
// './components/prose',
|
|
101
|
+
// './components/globals',
|
|
102
|
+
// './components/content',
|
|
103
|
+
// './components/dev',
|
|
104
|
+
// {
|
|
105
|
+
// prefix: '',
|
|
106
|
+
// path: './components/icons',
|
|
107
|
+
// global: true,
|
|
108
|
+
// },
|
|
109
|
+
// ],
|
|
110
|
+
// To enable for working build
|
|
111
|
+
components,
|
|
96
112
|
css: [
|
|
97
|
-
resolveThemeDir('assets/css/main.css'),
|
|
98
113
|
resolveThemeDir('assets/css/fonts.css'),
|
|
99
|
-
resolveThemeDir('assets/css/tailwind.css'),
|
|
100
114
|
],
|
|
101
115
|
tailwindcss: {
|
|
102
116
|
viewer: false,
|
|
103
|
-
cssPath: resolveThemeDir('assets/css/
|
|
117
|
+
cssPath: resolveThemeDir('assets/css/main.css'),
|
|
104
118
|
config: {
|
|
105
119
|
darkMode: 'class',
|
|
106
120
|
theme: {
|
|
@@ -112,6 +126,10 @@ export default defineNuxtConfig({
|
|
|
112
126
|
fontFamily: {
|
|
113
127
|
sans: 'Inter, sans-serif',
|
|
114
128
|
},
|
|
129
|
+
spacing: {
|
|
130
|
+
base: '320px',
|
|
131
|
+
header: 'var(--header-height)',
|
|
132
|
+
},
|
|
115
133
|
},
|
|
116
134
|
},
|
|
117
135
|
plugins: [
|
|
@@ -121,6 +139,7 @@ export default defineNuxtConfig({
|
|
|
121
139
|
require('@tailwindcss/aspect-ratio'),
|
|
122
140
|
],
|
|
123
141
|
content: [
|
|
142
|
+
'~/content/**/*.{md,yml,json,json5,csv}',
|
|
124
143
|
resolveThemeDir('assets/**/*.{mjs,vue,js,ts}'),
|
|
125
144
|
resolveThemeDir('components/**/*.{mjs,vue,js,ts}'),
|
|
126
145
|
resolveThemeDir('layouts/**/*.{mjs,vue,js,ts}'),
|
|
@@ -146,6 +165,7 @@ export default defineNuxtConfig({
|
|
|
146
165
|
'@nuxtjs/tailwindcss',
|
|
147
166
|
'@nuxtjs/color-mode',
|
|
148
167
|
'@nuxthq/admin',
|
|
149
|
-
'vue-plausible',
|
|
168
|
+
// 'vue-plausible',
|
|
169
|
+
'@vueuse/nuxt',
|
|
150
170
|
],
|
|
151
171
|
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
definePageMeta({
|
|
3
|
+
middleware: [
|
|
4
|
+
'page',
|
|
5
|
+
/* 'components' */
|
|
6
|
+
],
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const { page, theme } = useDocus()
|
|
10
|
+
|
|
11
|
+
useHead({
|
|
12
|
+
title: `${theme.value?.title} | ${page.value?.title}`,
|
|
13
|
+
description: page.value?.description || theme.value?.description || '',
|
|
14
|
+
meta: [
|
|
15
|
+
{ hid: 'og:site_name', property: 'og:site_name', content: 'Nuxt' },
|
|
16
|
+
{ hid: 'og:type', property: 'og:type', content: 'website' },
|
|
17
|
+
{ hid: 'twitter:site', name: 'twitter:site', content: theme.value?.url || theme.value?.twitter || '' },
|
|
18
|
+
{
|
|
19
|
+
hid: 'twitter:card',
|
|
20
|
+
name: 'twitter:card',
|
|
21
|
+
content: 'summary_large_image',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
hid: 'og:image',
|
|
25
|
+
property: 'og:image',
|
|
26
|
+
content: theme.value?.cover || '',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
hid: 'og:image:secure_url',
|
|
30
|
+
property: 'og:image:secure_url',
|
|
31
|
+
content: theme.value?.cover || '',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
hid: 'og:image:alt',
|
|
35
|
+
property: 'og:image:alt',
|
|
36
|
+
content: theme.value?.coverAlt || '',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
hid: 'twitter:image',
|
|
40
|
+
name: 'twitter:image',
|
|
41
|
+
content: theme.value?.cover || '',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<Content v-if="page" class="content" :document="page" />
|
|
49
|
+
<p v-else>
|
|
50
|
+
<Alert type="warning">
|
|
51
|
+
Page not found!
|
|
52
|
+
</Alert>
|
|
53
|
+
</p>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.content {
|
|
58
|
+
& > :first-child {
|
|
59
|
+
margin-top: 0 !important;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export default defineNuxtPlugin((ctx: any) => {
|
|
2
|
+
// Menu visible reference
|
|
3
|
+
const visible = ref(false)
|
|
4
|
+
|
|
5
|
+
// Current tab visible reference
|
|
6
|
+
const currentTab = ref()
|
|
7
|
+
|
|
8
|
+
// Scrollbar gap (used for responsive menu)
|
|
9
|
+
const scrollBarGap = ref()
|
|
10
|
+
|
|
11
|
+
// Open the menu
|
|
12
|
+
const open = () => (visible.value = true)
|
|
13
|
+
|
|
14
|
+
// Close the menu
|
|
15
|
+
const close = () => (visible.value = false)
|
|
16
|
+
|
|
17
|
+
// Toggle the menu (useful for one-off buttons)
|
|
18
|
+
const toggle = () => (visible.value = !visible.value)
|
|
19
|
+
|
|
20
|
+
// Toggle a tab from its id
|
|
21
|
+
const toggleTab = (tab: string) =>
|
|
22
|
+
currentTab.value === tab ? (currentTab.value = undefined) : (currentTab.value = tab)
|
|
23
|
+
|
|
24
|
+
// Watch route change, close on change
|
|
25
|
+
ctx.$router.afterEach(() => setTimeout(close, 50))
|
|
26
|
+
|
|
27
|
+
// Watch visible and remove overflow so the scrollbar disappears when menu is opened
|
|
28
|
+
if (process.client) {
|
|
29
|
+
watch(
|
|
30
|
+
visible,
|
|
31
|
+
(isVisible) => {
|
|
32
|
+
const html = document.querySelector('html')
|
|
33
|
+
|
|
34
|
+
if (isVisible) {
|
|
35
|
+
scrollBarGap.value = window.innerWidth - document.documentElement.clientWidth
|
|
36
|
+
html.style.overflow = 'hidden'
|
|
37
|
+
html.style.paddingRight = `${scrollBarGap.value}px`
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
html.style.overflow = ''
|
|
42
|
+
html.style.paddingRight = ''
|
|
43
|
+
}, 100) /* had to put it, because of layout shift on leave transition */
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
immediate: true,
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
provide: {
|
|
54
|
+
menu: {
|
|
55
|
+
scrollBarGap,
|
|
56
|
+
visible,
|
|
57
|
+
close,
|
|
58
|
+
open,
|
|
59
|
+
toggle,
|
|
60
|
+
currentTab,
|
|
61
|
+
toggleTab,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default defineNuxtPlugin(() => {
|
|
2
|
+
const isDesktopSafari = ref(false)
|
|
3
|
+
const isDesktopFirefox = ref(false)
|
|
4
|
+
|
|
5
|
+
const refresh = () => {
|
|
6
|
+
isDesktopSafari.value
|
|
7
|
+
= !/Mobi|Android/i.test(navigator.userAgent)
|
|
8
|
+
&& /Safari/i.test(navigator.userAgent)
|
|
9
|
+
&& !/Chrome|Chromium/i.test(navigator.userAgent)
|
|
10
|
+
|
|
11
|
+
isDesktopFirefox.value = !/Mobi|Android/i.test(navigator.userAgent) && /Firefox/i.test(navigator.userAgent)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (process.client)
|
|
15
|
+
refresh()
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
provide: {
|
|
19
|
+
userAgent: {
|
|
20
|
+
isDesktopSafari,
|
|
21
|
+
isDesktopFirefox,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isHTMLTag } from '@vue/shared'
|
|
2
|
+
import { pascalCase } from 'scule'
|
|
3
|
+
import { useRuntimeConfig } from '#imports'
|
|
4
|
+
|
|
5
|
+
export const flattenComponents = (body, flattened = []) => {
|
|
6
|
+
// Grab tags list from content config
|
|
7
|
+
const { content: { tags = {} } } = useRuntimeConfig().public
|
|
8
|
+
|
|
9
|
+
for (const node of body) {
|
|
10
|
+
if (node?.tag) {
|
|
11
|
+
let tag = node.tag
|
|
12
|
+
|
|
13
|
+
if (Object.keys(tags).includes(tag))
|
|
14
|
+
tag = pascalCase(`prose-${tag}`)
|
|
15
|
+
|
|
16
|
+
if (!isHTMLTag(tag) && !flattened.includes(tag))
|
|
17
|
+
flattened.push(pascalCase(tag))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (node.children)
|
|
21
|
+
flattenComponents(node.children, flattened)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return flattened
|
|
25
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Find first child link from a navigation node.
|
|
5
|
+
*/
|
|
6
|
+
export const findBottomLink = (link: NavItem) => {
|
|
7
|
+
for (const child of link.children) {
|
|
8
|
+
if (!child.children)
|
|
9
|
+
return child.slug
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const child of link.children) {
|
|
13
|
+
const result = findBottomLink(child)
|
|
14
|
+
if (result)
|
|
15
|
+
return result
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find current navigation directory from a path.
|
|
21
|
+
*/
|
|
22
|
+
export const navFromPath = (path: string, tree: NavItem[]) => {
|
|
23
|
+
for (const file of tree) {
|
|
24
|
+
if (file.slug === path && !file.id)
|
|
25
|
+
return file
|
|
26
|
+
|
|
27
|
+
if (file.children) {
|
|
28
|
+
const result = navFromPath(path, file.children)
|
|
29
|
+
if (result)
|
|
30
|
+
return result
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Find a navigation node from a path.
|
|
37
|
+
*/
|
|
38
|
+
export const fileFromPath = (path: string, tree: NavItem[]) => {
|
|
39
|
+
for (const file of tree) {
|
|
40
|
+
if (file.children) {
|
|
41
|
+
const result = fileFromPath(path, file.children)
|
|
42
|
+
if (result)
|
|
43
|
+
return result
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (file.slug === path)
|
|
47
|
+
return file
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { queryNavigation, queryPage, queryTheme } from './queries'
|
|
2
|
+
import { useRoute } from '#imports'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Plugin enabled only in development
|
|
6
|
+
* Ensure hot reload works with content sources
|
|
7
|
+
*/
|
|
8
|
+
export default defineNuxtPlugin(
|
|
9
|
+
(nuxt) => {
|
|
10
|
+
nuxt.hook(
|
|
11
|
+
'app:data:refresh',
|
|
12
|
+
async() => {
|
|
13
|
+
const route = useRoute()
|
|
14
|
+
|
|
15
|
+
await queryNavigation()
|
|
16
|
+
await queryTheme()
|
|
17
|
+
await queryPage(route)
|
|
18
|
+
},
|
|
19
|
+
)
|
|
20
|
+
},
|
|
21
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { withoutTrailingSlash } from 'ufo'
|
|
2
|
+
import type { ParsedContent } from '@nuxt/content/dist/runtime/types'
|
|
3
|
+
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router'
|
|
4
|
+
import { defaultThemeConfig } from './theme'
|
|
5
|
+
import { useDocusState } from './state'
|
|
6
|
+
import { fetchContentNavigation, queryContent } from '#imports'
|
|
7
|
+
|
|
8
|
+
export const queryPage = async(route: RouteLocationNormalized | RouteLocationNormalizedLoaded) => {
|
|
9
|
+
const path = withoutTrailingSlash(route.path)
|
|
10
|
+
|
|
11
|
+
const { page, surround } = useDocusState()
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
await Promise.all([
|
|
15
|
+
queryContent().where({ slug: path }).findOne() as Promise<ParsedContent>,
|
|
16
|
+
queryContent().where({ partial: { $not: true }, navigation: { $not: false } }).findSurround(path) as Promise<ParsedContent[]>,
|
|
17
|
+
]).then(
|
|
18
|
+
([_page, _surround]) => {
|
|
19
|
+
if (_page)
|
|
20
|
+
page.value = _page
|
|
21
|
+
else page.value = undefined
|
|
22
|
+
|
|
23
|
+
if (_surround && _surround.length)
|
|
24
|
+
surround.value = _surround
|
|
25
|
+
else surround.value = undefined
|
|
26
|
+
|
|
27
|
+
// Handle layout update from page
|
|
28
|
+
if (_page?.layout)
|
|
29
|
+
route.meta.layout = _page?.layout
|
|
30
|
+
else
|
|
31
|
+
route.meta.layout = 'default'
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
console.warn(`Could not find page for path ${path}!`)
|
|
37
|
+
page.value = undefined
|
|
38
|
+
surround.value = undefined
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const queryNavigation = async() => {
|
|
43
|
+
const { navigation } = useDocusState()
|
|
44
|
+
|
|
45
|
+
navigation.value = await fetchContentNavigation(queryContent().where({
|
|
46
|
+
navigation: {
|
|
47
|
+
$not: false,
|
|
48
|
+
},
|
|
49
|
+
}))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const queryTheme = async() => {
|
|
53
|
+
const { theme } = useDocusState()
|
|
54
|
+
|
|
55
|
+
// Fetch _theme.yml at `content/` root.
|
|
56
|
+
const query = await queryContent().where({
|
|
57
|
+
id: 'content:_theme.yml',
|
|
58
|
+
}).findOne()
|
|
59
|
+
|
|
60
|
+
if (!query) {
|
|
61
|
+
// Assign default theme config if none found.
|
|
62
|
+
theme.value = defaultThemeConfig
|
|
63
|
+
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
theme.value = query.body
|
|
68
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { NavItem, ParsedContent } from '@nuxt/content/dist/runtime/types'
|
|
2
|
+
import type { ThemeConfig } from './theme'
|
|
3
|
+
|
|
4
|
+
export const useDocusState = () => {
|
|
5
|
+
/**
|
|
6
|
+
* Navigation tree from root of app.
|
|
7
|
+
*/
|
|
8
|
+
const navigation = useState<NavItem[]>('docus-navigation', () => null)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Current page complete data.
|
|
12
|
+
*/
|
|
13
|
+
const page = useState<ParsedContent>('docus-page', () => null)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Previous and next page data.
|
|
17
|
+
* Format: [prev, next]
|
|
18
|
+
*/
|
|
19
|
+
const surround = useState<ParsedContent[]>('docus-page-surround', () => null)
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Theme configuration.
|
|
23
|
+
*/
|
|
24
|
+
const theme = useState<ThemeConfig>('docus-theme', () => null)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
navigation,
|
|
28
|
+
page,
|
|
29
|
+
surround,
|
|
30
|
+
theme,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface ThemeIcon {
|
|
2
|
+
label: string
|
|
3
|
+
href: string
|
|
4
|
+
component: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ThemeDebugConfig {
|
|
8
|
+
page: boolean
|
|
9
|
+
navigation: boolean
|
|
10
|
+
theme: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ThemeConfig {
|
|
14
|
+
title: string
|
|
15
|
+
description: string
|
|
16
|
+
twitter: string
|
|
17
|
+
github: string
|
|
18
|
+
cover: string
|
|
19
|
+
coverAlt: string
|
|
20
|
+
header: {
|
|
21
|
+
title: false | string
|
|
22
|
+
logo: boolean | string
|
|
23
|
+
}
|
|
24
|
+
footer: {
|
|
25
|
+
credits: false | {
|
|
26
|
+
icon: string
|
|
27
|
+
text: string
|
|
28
|
+
}
|
|
29
|
+
icons: ThemeIcon[]
|
|
30
|
+
}
|
|
31
|
+
debug: boolean | ThemeDebugConfig
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const defaultThemeConfig: ThemeConfig = {
|
|
35
|
+
title: 'Docus',
|
|
36
|
+
twitter: '@docus_',
|
|
37
|
+
github: 'nuxtlabs/docus',
|
|
38
|
+
description: 'Write pages in markdown, use Vue components and enjoy the power of Nuxt with a blazing fast developer experience.',
|
|
39
|
+
header: {
|
|
40
|
+
title: false,
|
|
41
|
+
logo: true,
|
|
42
|
+
},
|
|
43
|
+
cover: 'https://user-images.githubusercontent.com/904724/105075054-872fac80-5a89-11eb-8aab-46dd254ad986.png',
|
|
44
|
+
coverAlt: 'A screenshot of a website built with Docus with the Docus logo on top of it.',
|
|
45
|
+
footer: {
|
|
46
|
+
credits: {
|
|
47
|
+
icon: 'IconNuxtLabs',
|
|
48
|
+
text: 'Made by NuxtLabs',
|
|
49
|
+
},
|
|
50
|
+
icons: [
|
|
51
|
+
{
|
|
52
|
+
label: 'NuxtJS',
|
|
53
|
+
href: 'https://nuxtjs.org',
|
|
54
|
+
component: 'IconNuxtLabs',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Vue Telescope',
|
|
58
|
+
href: 'https://vuetelescope.com',
|
|
59
|
+
component: 'IconVueTelescope',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
debug: true,
|
|
64
|
+
}
|