Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/content/docs/1.getting-started/3.configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,24 @@ export default defineTransformer({

Read more about transformers in the [Transformers](/docs/advanced/transformers) documentation.

### `assets`

Nuxt Content resolves relative paths to co-located images, video and documents in markdown, MDC components and frontmatter. The files are copied next to the built site and the references are rewritten. Enabled by default.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
content: {
build: {
assets: {
imageSize: 'style', // inject image dimensions to avoid layout shift
},
},
},
})
```

Read more in the [Assets](/docs/files/assets) documentation.

## `database`

By default Nuxt Content uses a local SQLite database to store and query content. If you like to use another database or you plan to deploy on Cloudflare Workers, you can modify this option.
Expand Down
23 changes: 16 additions & 7 deletions docs/content/docs/3.files/1.markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,23 +506,32 @@ Each line of a code block gets its line number in the `line` attribute so lines

## Images

You can add images to your `public` directory:
Reference an image **relative to your content file**. Nuxt Content copies it
next to the built site and resolves the path to a served URL automatically:

```bash [Directory structure]
content/
index.md
public/
image.png
nuxt.config.ts
package.json
img/
cover.png
```

And then use them in your markdown files in the `content` directory as such:
```md [content/index.md]
![my image](./img/cover.png)
```

For an image shared across many pages, place it in the `public/` directory and
reference it with an absolute path:

```md [content/index.md]
![my image](/image.png)
![logo](/logo.png)
```

::tip
Relative resolution also works in MDC components, raw HTML and frontmatter, and
covers video and documents too. See [Assets](/docs/files/assets).
::

## Excerpt

Content excerpt or summary can be extracted from the content using `<!--more-->` as a divider.
Expand Down
198 changes: 198 additions & 0 deletions docs/content/docs/3.files/5.assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
title: Assets
description: How Nuxt Content resolves relative paths to images, video and documents.
---

Nuxt Content resolves **relative paths** to images, video and documents
co-located with your content. Matching files are copied next to the built site
and every reference (in markdown, MDC components, raw HTML and frontmatter) is
rewritten to an absolute URL.

```bash [Directory structure]
content/
blog/
launch/
index.md
media/
cover.png
demo.mp4
files/
press-kit.pdf
```

```md [content/blog/launch/index.md]
---
title: Launch
cover: media/cover.png
---

![Cover](media/cover.png)

:video{src="media/demo.mp4"}

[Press kit](files/press-kit.pdf)
```

::note
Absolute references (`/image.png`) and remote URLs are left untouched. Use the
`public/` directory and absolute paths for assets shared across many pages.
::

## Usage

A relative path is resolved wherever a value points to a co-located file.

::code-group
```md [Markdown image]
![mountains](media/mountains.png)
```

```md [Markdown link]
[Download](files/report.pdf)
```

```md [MDC component]
:video{src="media/clip.mp4"}
```

```md [HTML]
<img src="media/photo.png">
```
::

Relative paths also work in **frontmatter**, including inside arrays:

```md
---
title: Portfolio
cover: media/cover.jpg
gallery:
- media/image-1.jpg
- media/image-2.jpg
- media/image-3.jpg
---
```

```md [Pass the resolved paths to a component]
:image-gallery{:images="gallery"}
```

Ordering prefixes are stripped from the served URL, exactly like for content
routes: an asset stored under `1.launch/media/01.cover.png` is served at
`/launch/media/cover.png`.

Links pointing to an asset open in a new tab (`target="_blank"`).

## Image sizing

To prevent layout shift, Nuxt Content reads each image's dimensions at build time
and injects them. By default it adds an `aspect-ratio` style. Use `imageSize` to
choose where the dimensions go, or to turn it off:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
content: {
build: {
assets: {
imageSize: 'style', // the default
},
},
},
})
```

You can combine one or more hints:

| Hint | Effect |
| --------- | ----------------------------------------------------------------- |
| `'style'` | Adds `style="aspect-ratio:W/H"` to the `<img>` (default) |
| `'attrs'` | Adds `width` and `height` attributes to the `<img>` |
| `'src'` | Adds `?width=W&height=H` to the resolved path (frontmatter values)|
| `'url'` | Alias of `'src'` |
| `''` | Inject nothing |

::warning
If you use **only** `'attrs'`, add the following CSS so images stay responsive:

```css
img {
max-width: 100%;
height: auto;
}
```
::

When you pass a frontmatter image to a custom component with the `'src'` hint, the
component receives the dimensions as a query string you can extract and apply:

```html
<img src="/media/photo.png?width=640&height=480">
```

## Live reload

In development, adding, editing, moving or deleting an asset updates the browser
without a full reload:

- editing an image refreshes it in place;
- deleting an asset greys it out until you restore it or change the reference;
- resizing an image re-injects its dimensions so the layout stays correct.

## Nuxt Image

Because assets are served from the site root, `<NuxtImg>` works out of the box
with the default IPX provider:

```vue [components/content/ProseImg.vue]
<template>
<NuxtImg v-bind="$attrs" />
</template>
```

::warning
Do not use `imageSize: 'src'` together with Nuxt Image: the query string prevents
IPX from resolving the image and breaks static generation. The default `'style'`
is safe.
::

## Configuration

```ts [nuxt.config.ts]
export default defineNuxtConfig({
content: {
build: {
assets: {
// resolve relative asset paths (set to `false` to opt out)
enabled: true,

// where to inject image dimensions: 'style' | 'attrs' | 'src' | '' (none)
imageSize: 'style',

// open links pointing to an asset in a new tab
blankLinks: true,

// file extensions treated as assets (and excluded from content collections)
extensions: ['png', 'jpg', 'svg', 'mp4', 'pdf' /* … */],

// URL prefix prepended to served assets (namespacing / collision avoidance)
prefix: '',

// log discovered and copied assets
debug: false,
},
},
},
})
```

::note
You rarely need to touch `extensions`. It only matters when a custom transformer
treats a normally-binary extension as content, or vice versa.
::

## Notes

- Relative references are resolved at build time, so the file must exist when the
site is built.
- On a path collision, files in your `public/` directory take precedence. Use
`prefix` to namespace assets if needed.
15 changes: 15 additions & 0 deletions examples/basic/content/cover.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions examples/basic/content/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Welcome to Nuxt Content starter

![Nuxt Content](cover.svg)

## Manage your contents

Create new pages or modify the existing ones in `content/` directory.

The image above sits next to this file (`content/cover.svg`) and is referenced
with a relative path.

## Query & Render pages

You can find an example of querying contents and rendering them in `app/pages/[...slug].vue`
Expand Down
16 changes: 10 additions & 6 deletions examples/blog/app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup>
const { data: posts } = await useAsyncData(() => {
return queryCollection('blog')
.select('title', 'description', 'path', 'id', 'date')
.select('title', 'description', 'path', 'id', 'date', 'image')
.order('date', 'DESC')
.all()
})
Expand All @@ -10,16 +10,20 @@ const { data: posts } = await useAsyncData(() => {
<template>
<div>
<h1>Blog</h1>
<p
<article
v-for="post in posts"
:key="post.id"
style="margin-bottom: 2rem;"
>
>
<nuxt-link :to="post.path">
<img
:src="post.image"
:alt="post.title"
style="max-width: 320px; height: auto; border-radius: 8px; display: block;"
>
<strong>{{ post.title }}</strong>
</nuxt-link>

&nbsp;{{ post.description }}
</p>
<p>{{ post.description }}</p>
</article>
</div>
</template>
1 change: 1 addition & 0 deletions examples/blog/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default defineContentConfig({
source: 'blog/**',
schema: z.object({
date: z.string(),
image: z.string(),
}),
}),
},
Expand Down
Binary file added examples/blog/content/blog/damavand.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/blog/content/blog/everest.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions examples/blog/content/blog/mount-damavand.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
title: Mount Damavand
description: Mount Damavand is the highest peak in the Middle East and a prominent feature of the Alborz mountain range.
date: 2024-10-10
image: damavand.jpg
---

![Mount Damavand](damavand.jpg)

Mount Damavand, located in northern Iran, is the highest peak in the Middle East and a prominent feature of the Alborz mountain range. Standing at an elevation of 5,671 meters (18,606 feet), it is a dormant stratovolcano with a distinctive conical shape, often snow-capped for most of the year. Damavand holds a special place in Persian mythology and culture, symbolizing strength and resistance. Its volcanic origin is evidenced by fumaroles near the summit, which occasionally emit sulfur gases, contributing to the mountain's rugged and otherworldly landscape.

Beyond its geological and cultural significance, Mount Damavand is a popular destination for hikers and climbers, offering a range of challenges depending on the chosen route. The ascent is technically less demanding than other famous peaks, but high altitude and cold weather present significant obstacles. Damavand also attracts nature enthusiasts due to its rich biodiversity, hosting various species of plants and wildlife. As a national symbol of Iran, the mountain holds an enduring presence in Persian poetry and art, making it not just a physical landmark but also a cultural icon.
3 changes: 3 additions & 0 deletions examples/blog/content/blog/mount-everest.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
title: Mount Everest
description: Mount Everest, the tallest mountain in the world
date: 2024-10-11
image: everest.jpg
---

![Mount Everest](everest.jpg)

Mount Everest, the tallest mountain in the world, stands at an impressive 8,848.86 meters (29,031.7 feet) above sea level. Located in the Himalayas on the border between Nepal and the Tibet Autonomous Region of China, it is part of the greater Mahalangur Himal range. Everest attracts climbers from all over the world, including highly skilled mountaineers as well as capable climbers attempting to reach the summit with the help of professional guides. Despite its allure, Everest's extreme altitude, unpredictable weather, and challenging terrain make it a dangerous climb. Many people have lost their lives in pursuit of reaching the summit.

The mountain is known as "Sagarmatha" in Nepali and "Chomolungma" in Tibetan, both of which signify its cultural and spiritual importance to the local populations. Climbing Everest has evolved over the decades, with advances in technology and infrastructure making it somewhat more accessible. However, issues like overcrowding, environmental degradation, and the impact on the health of Sherpa communities who guide climbers have raised concerns. Despite these challenges, Mount Everest remains an iconic symbol of adventure and human endurance, continuing to captivate the imaginations of people worldwide.
17 changes: 17 additions & 0 deletions examples/i18n/content/en/banner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions examples/i18n/content/en/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Welcome to Nuxt Content starter

![Internationalized content](banner.svg)

## Manage your contents

Create new pages or modify the existing ones in `content/` directory.
Expand Down
Loading
Loading