Skip to content

Commit 321bb5e

Browse files
committed
Merge branch 'main' into feat/client-side-fts-search
2 parents c04e129 + f97dc86 commit 321bb5e

12 files changed

Lines changed: 182 additions & 6 deletions

File tree

app/app.vue

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
<script setup lang="ts">
22
import type { NavigationItem } from 'comark-content'
3+
import { useRoute } from 'vue-router'
34
45
const { seo, docs } = useAppConfig()
56
67
const content = useDocsContent()
8+
const route = useRoute()
79
810
const { data: navigation } = await useAsyncData('navigation', () => content.value.client.navigation(), {
911
watch: [() => content.value.base],
1012
})
1113
14+
const nuxtApp = useNuxtApp()
1215
const navTree = computed<NavigationItem[]>(() => prefixNavigation(navigation.value ?? [], content.value.base))
16+
const navigationLayout = ref(findNavigationLayout(navTree.value, route.path))
17+
onNuxtReady(() => {
18+
nuxtApp.hook('page:finish', () => {
19+
navigationLayout.value = findNavigationLayout(navTree.value, route.path)
20+
})
21+
})
1322
1423
useHead({
1524
meta: [{ name: 'viewport', content: 'width=device-width, initial-scale=1' }],
@@ -34,6 +43,7 @@ useSeoMeta({
3443
})
3544
3645
provide('navigation', navTree)
46+
provide('layout', navigationLayout)
3747
3848
// const colorMode = useColorMode()
3949
const historyOpen = useVersionHistory()
@@ -64,9 +74,17 @@ defineShortcuts({
6474
<AppHeader />
6575

6676
<UMain>
67-
<NuxtLayout>
68-
<NuxtPage />
69-
</NuxtLayout>
77+
<Suspense>
78+
<LayoutsPage v-if="navigationLayout === 'page'">
79+
<NuxtPage />
80+
</LayoutsPage>
81+
<LayoutsDocs v-else-if="navigationLayout === 'docs'">
82+
<NuxtPage />
83+
</LayoutsDocs>
84+
<UContainer v-else>
85+
<NuxtPage />
86+
</UContainer>
87+
</Suspense>
7088
</UMain>
7189

7290
<AppFooter />

app/components/docs/DocsAsideMobileBar.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const menuDrawerOpen = ref(false)
1414
const tocDrawerOpen = ref(false)
1515
const navigationRef = ref<HTMLElement | null>(null)
1616
let observer: IntersectionObserver | undefined
17+
const layout = inject('layout')
1718
1819
watch(menuDrawerOpen, (open) => {
1920
nextTick(() => {
@@ -28,9 +29,11 @@ watch(menuDrawerOpen, (open) => {
2829

2930
<template>
3031
<div
31-
class="lg:hidden sticky top-(--ui-header-height) z-10 bg-default -mx-6 p-2 px-6 border-b border-muted flex justify-between"
32+
class="lg:hidden sticky top-(--ui-header-height) z-10 bg-default -mx-6 p-2 px-6 border-b border-muted flex h-13"
33+
:class="layout === 'page' ? 'justify-end' : 'justify-between'"
3234
>
3335
<UDrawer
36+
v-if="layout === 'docs'"
3437
v-model:open="menuDrawerOpen"
3538
direction="left"
3639
:title="title"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<template>
2+
<UContainer class="max-w-7xl">
3+
<UTheme :ui="{ pageHeader: { container: 'lg:pt-8' }, contentToc: { container: 'lg:pt-16' } }">
4+
<slot />
5+
</UTheme>
6+
</UContainer>
7+
</template>

app/pages/[...slug].vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import CodeExplorer from '../components/CodeExplorer.vue'
66
import Browser from '../components/Browser.vue'
77
88
definePageMeta({
9-
layout: 'docs',
109
path: '/:slug(.+)',
1110
})
1211
1312
const { toc, seo } = useAppConfig()
1413
const navigation = inject<Ref<NavigationItem[]>>('navigation')
1514
const content = useDocsContent()
15+
const layout = inject<Ref<NavigationLayout>>('layout')
1616
1717
const { data: page } = await useAsyncData(`${content.value.base}:${content.value.path}`, () =>
1818
content.value.client.get(content.value.path)
@@ -126,6 +126,7 @@ if (content.value.mode === 'prod') {
126126
/>
127127

128128
<UContentSurround
129+
v-if="layout === 'docs'"
129130
:surround="surroundLinks as any"
130131
:ui="{ root: !surroundLinks[0] ? 'sm:grid-cols-1' : 'sm:grid-cols-2' }"
131132
/>

app/utils/navigation.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,35 @@ export interface BreadcrumbItem {
6464
path?: string
6565
}
6666

67+
export type NavigationLayout = 'docs' | 'page'
68+
69+
/** Layout declared by the nearest matching page or directory navigation node. */
70+
export function findNavigationLayout(
71+
navigation: NavigationItem[] | undefined | null,
72+
path: string | undefined
73+
): NavigationLayout | undefined {
74+
if (!navigation?.length || !path || path === '/') return undefined
75+
76+
let layout: NavigationLayout | undefined
77+
const visit = (items: NavigationItem[]) => {
78+
for (const item of items) {
79+
const isPage = item.path === path
80+
const isDirectory = Boolean(
81+
item.children?.length
82+
&& item.path !== '/'
83+
&& path.startsWith(`${item.path}/`)
84+
)
85+
if (!isPage && !isDirectory) continue
86+
87+
if (item.layout === 'docs' || item.layout === 'page') layout = item.layout
88+
if (item.children?.length) visit(item.children)
89+
}
90+
}
91+
92+
visit(navigation)
93+
return layout || 'docs'
94+
}
95+
6796
/** Trail of navigation items leading to `path`, including the page itself. */
6897
export function findBreadcrumb(
6998
navigation: NavigationItem[] | undefined | null,

playground/app/app.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default defineAppConfig({
1212
ecosystem: [{ mark: 'comark-content', to: 'https://content.comark.dev', label: 'Comark Content' }],
1313
nav: [
1414
{ label: 'Documentation', sections: ['getting-started', 'writing', 'concepts', 'deployment'] },
15+
{ label: 'Page', to: '/page' }
1516
],
1617
},
1718
footer: {

playground/content/2.writing/5.navigation.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ title: Getting Started
2626
2727
Page titles come from frontmatter — `navigation.title` when set, `title` otherwise. Pages with `navigation: false` are excluded from the tree entirely (and therefore from prev/next links, search, and `llms.txt`).
2828

29+
## Section layouts
30+
31+
Pages use the `docs` layout by default, which includes the navigation sidebar. Set `layout: page` in a directory's `.navigation.yml` to render every page in that directory without the sidebar:
32+
33+
```yaml [content/3.examples/.navigation.yml]
34+
title: Examples
35+
layout: page
36+
```
37+
38+
The layout applies to nested directories too. A nested `.navigation.yml` can set `layout: docs` to restore the sidebar. The `page` layout keeps the header, footer and page table of contents.
39+
2940
## Header tabs
3041

3142
The header renders one tab per group in `header.nav` from `app.config.ts`. Each group maps top-level content sections to a tab:

playground/content/page.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: Page
3+
description: This is an example using the page layout.
4+
navigation:
5+
layout: page
6+
---
7+
8+
In order to use the `page` layout without the left aside.
9+
10+
## Usage
11+
12+
You only need to set:
13+
14+
```yaml
15+
---
16+
navigation:
17+
layout: page
18+
---
19+
```
20+
21+
## TOC
22+
23+
The Table of Contents stays if you have headings.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
layout: page

0 commit comments

Comments
 (0)