Skip to content

Commit

Permalink
feat(navigation): allow _dir.yml to filter navigation (#1261)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tahul committed Jun 15, 2022
1 parent a2dd092 commit fa45652
Show file tree
Hide file tree
Showing 31 changed files with 389 additions and 103 deletions.
29 changes: 29 additions & 0 deletions docs/components/content/ReadMore.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<Alert>
<Icon class="inline-block w-5 h-5" name="heroicons-outline:information-circle" />
Read more in
<NuxtLink :to="link">
{{ computedTitle }}
</NuxtLink>.
</Alert>
</template>

<script setup lang="ts">
import { splitByCase, upperFirst } from 'scule'
const props = defineProps({
link: {
type: String,
required: true
},
title: {
type: String,
required: false,
default: undefined
}
})
const createTitle = (title, link) => (title || link.split('/').filter(Boolean).map(part => splitByCase(part).map(p => upperFirst(p)).join(' ')).join(' > ').replace('Api', 'API'))
const computedTitle = computed(() => createTitle(props.title, props.link))
</script>
189 changes: 141 additions & 48 deletions docs/content/3.guide/2.displaying/3.navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,149 @@ title: Navigation
description: 'The fetchContentNavigation utility returns a tree of items based on the content/ directory structure and files.'
---

Use the `title`{lang="ts"} and `path`{lang="ts"} properties of each item to create your application's navigation.
Navigation generation is based on your content sources directory structure.

## Nested navigation
Based on the generated `_id` and `_path` keys, we generate a whole navigation structure for your content.

You can pass a `queryContent()`{lang="ts"} instance to the `fetchContentNavigation()`{lang="ts"} utility to filter the items returned.
It allows you to create advanced navigation components without having to maintain any querying logic related to it.

That allows to create navigation objects for which the starting point is based on a specific content directory.
## Structure

```ts
const query = queryContent({
where: {
_path: { $contains: '/your/navigation/starting/point' }
The navigation object can be seen as a tree representing in a JSON format the structure of your content sources.

It is divided in two type of nodes, **pages** and **directories**.

::code-group

``` [Directory structure]
content/
my-directory/
page.md
```

```json [Directory node]
{
"title": "My Directory",
"_path": "/my-directory",
"children": [
...pagesNodes
]
}
```

```json [Page node]
{
"title": "Page title",
"_path": "/my-directory/my-page",
"_id": "content:my-directory:page.md"
}
```

```json [Complete navigation]
[
{
"title": "My Directory",
"_path": "/my-directory",
"children": [
{
"title": "Page title",
"_path": "/my-directory/my-page",
"_id": "content:my-directory:page.md"
}
]
}
})
]
```

::

## Configuration

Set `navigation: false` in the [front-matter](/guide/writing/markdown) of a page to exclude it in `fetchContentNavigation()` return value.
### Module

The only key available in [module configuration](/api/configuration#navigation) about navigation is `fields`.

`fields` allows you to define the properties that will be included in the navigation items.

::code-group

```ts [nuxt.config.ts]
defineNuxtConfig({
content: {
navigation: {
fields: ['author', 'publishedAt']
}
}
})
```

```md
```md [page.md]
---
navigation: false
title: My Page
author: 'Sébastien Chopin'
publishedAt: '15-06-2022'
---
```

## Example
```json [Navigation node]
{
"title": "My Page",
"author": "Sébastien Chopin",
"publishedAt": "15-06-2022",
"_path": "/page",
"_id": "content:page.md",
}
```

::code-group
::

```Text [Directory structure]
content/
index.md
sub-folder
about.md
### Per-directory

Alternatively, the navigation also allows you to configure directory nodes via `_dir.yml` files.

It allows you to overwrite directory names, and add custom properties to directory nodes in navigation.

## Excluding

Set `navigation: false` in the [front-matter](/guide/writing/markdown) of a page to filter it out of navigation.

```md [page.md]
---
navigation: false
---
```

```vue [app.vue]
<script setup>
const { data: navigation } = await useAsyncData('navigation', () => {
return fetchContentNavigation()
})
</script>
This pattern also works inside `_dir.yml` file, allowing you to filter out content directories and files.

```yaml [_dir.yml]
navigation: false
```

You can also use the `_` content prefix to exclude content directories and files.

::code-group

<template>
<pre>
{{ navigation }}
</pre>
</template>
``` [Directory structure]
content/
_hidden-directory/
page.md
index.md
not-hidden-directory/
_dir.yml
index.md
page.md
```

```Text [Output]
```json [Navigation object]
[
{
"title": "Hello Content V2",
"_path": "/",
"children": [
{
"_id": "content:index.md",
"title": "Hello Content V2",
"_path": "/"
}
]
},
{
"title": "Sub Directory",
"_path": "/sub-directory",
"title": "Not Hidden Directory",
"_path": "/not-hidden-directory",
"children": [
{
"_id": "content:sub-directory:about.md",
"title": "About Content V2",
"_path": "/sub-directory/about"
"title": "Page",
"_id": "content:not-hidden-directory:page.md",
"_path": "/not-hidden-directory/page"
}
]
}
Expand All @@ -83,4 +154,26 @@ const { data: navigation } = await useAsyncData('navigation', () => {

::

:ReadMore{link="/examples/navigation/fetch-content-navigation"}

## Nested navigation

You can pass a `queryContent()`{lang="ts"} instance to the `fetchContentNavigation()`{lang="ts"} utility to filter the items returned.

That allows to create navigation objects for which the starting point is based on a specific content directory.

```ts
const query = queryContent({
where: {
_path: { $contains: '/your/navigation/starting/point' }
}
})
```

---

::alert
Go deeper in the **API** section:

- [fetchContentNavigation()](/api/composables/fetch-content-navigation) composable to fetch navigation in `<script>`
- [ContentNavigation](/api/components/content-navigation) component made to shorten access to navigation in `<template>`
::
55 changes: 54 additions & 1 deletion docs/content/4.api/2.composables/2.fetch-content-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,64 @@ title: 'fetchContentNavigation()'
description: 'The fetchContentNavigation utility returns a tree of items based on the content/ directory structure and files.'
---

## Usage

::code-group

```Text [Directory structure]
content/
index.md
sub-folder
about.md
```

```vue [app.vue]
<script setup>
const { data: navigation } = await useAsyncData('navigation', fetchContentNavigation())
</script>
<template>
<pre>
{{ navigation }}
</pre>
</template>
```

```json [Output]
[
{
"title": "Hello Content V2",
"_path": "/",
"children": [
{
"title": "Hello Content V2",
"_id": "content:index.md",
"_path": "/"
}
]
},
{
"title": "Sub Directory",
"_path": "/sub-directory",
"children": [
{
"title": "About Content V2",
"_id": "content:sub-directory:about.md",
"_path": "/sub-directory/about"
}
]
}
]
```

::

## Arguments

- `queryBuilder`{lang=ts}
- Type: `QueryBuilder`{lang=ts}
- Definition: Any query built via `queryContent()`{lang=ts}
- Default: `/`{lang=ts}

:ReadMore{link="/examples/navigation/fetch-content-navigation"}
::ReadMore{link="/examples/navigation/fetch-content-navigation"}
::
12 changes: 10 additions & 2 deletions docs/content/4.api/3.configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,18 @@ Options for yaml parser.

## `navigation`

- Type: `Boolean`{lang=ts}
- Type: `false or Object`{lang=ts}
- Default: `true`{lang=ts}

Enable/Disable content navigation.
Configure the navigation feature.

Can be set to `false` to disable the feature completely.

### `navigation` options

| Option | Type | Description |
| ----------------- | :--------: | :-------- |
| `fields` | `string[]` | A list of fields to inherit from front-matter to navigation nodes. |

## `locales`

Expand Down
6 changes: 4 additions & 2 deletions docs/content/5.examples/1.essentials/1.hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ toc: false
title: 'Hello world'
---

:ReadMore{link="/get-started"}
::ReadMore{link="/get-started"}
::

:sandbox{repo="nuxt/content" branch="main" dir="examples/essentials/hello-world" file="app.vue"}
::sandbox{repo="nuxt/content" branch="main" dir="examples/essentials/hello-world" file="app.vue"}
::
6 changes: 4 additions & 2 deletions docs/content/5.examples/2.mdc/1.inline-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Inline components are components that don't contain any slot.

After creating them in the `components/` directory, declare them in your markdown files with the `:` MDC syntax.

:ReadMore{link="/guide/writing/mdc#inline-components"}
::ReadMore{link="/guide/writing/mdc#inline-components"}
::

:sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/inline-component" file="content/index.md"}
::sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/inline-component" file="content/index.md"}
::
5 changes: 3 additions & 2 deletions docs/content/5.examples/2.mdc/2.nested-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The MDC syntax allow you to nest components within a parent slot using indentati

The `components/AppNested.vue` component uses the `<Markdown>` component as markdown-rendering slot.

:ReadMore{link="/guide/writing/mdc#nesting"}
::ReadMore{link="/guide/writing/mdc#nesting"}

:sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/nested-components" file="content/index.md"}
::sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/nested-components" file="content/index.md"}
::
6 changes: 4 additions & 2 deletions docs/content/5.examples/2.mdc/3.props.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: ''

Pass props to your components in Markdown files using the `{}` MDC syntax.

:ReadMore{link="/guide/writing/mdc#props"}
::ReadMore{link="/guide/writing/mdc#props"}
::

:sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/props" file="content/index.md"}
::sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/props" file="content/index.md"}
::
6 changes: 4 additions & 2 deletions docs/content/5.examples/2.mdc/4.slots.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ You can fill a component's default slot by inserting content between `::`.

Use the `#` MDC syntax to fill a named slot inside a component.

:ReadMore{link="/guide/writing/mdc#slots"}
::ReadMore{link="/guide/writing/mdc#slots"}
::

:sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/slots" file="content/index.md"}
::sandbox{repo="nuxt/content" branch="main" dir="examples/mdc/slots" file="content/index.md"}
::

0 comments on commit fa45652

Please sign in to comment.