content
content copied to clipboard
Section splitting in Markdown files
Is your feature request related to a problem? Please describe.
The nuxt/content module works really well with article- and editorial-style content via markdown and managing page metadata via yaml/json, but I believe there's a gap in use cases between the two: copy-centric pages with multiple sections.
My personal use case is a website where every page has multiple <section>
s with a one-off component and body copy per section. The layout can be distilled to a traditional two-column layout:
~/pages/about.vue
<template>
<div>
<h1>About Us</h1>
<p>Lorem ipsum</p>
</div>
<section class="bg-black text-white">
<img class="left" src="~/asset.png">
<div class="prose">
<h2>First section content</h2>
</div>
</section>
<section class="bg-white text-black">
<img class="right" src="~/asset.png">
<div class="prose">
<h2>Second section content</h2>
</div>
</section>
</template>
Describe the solution you'd like
I'd like to be able to manage this content from within the same markdown file. On the layout component end, an ideal payload would be an array of objects containing each section's parsed content and its optional frontmatter:
const { title, body, sections } = await $content('about').fetch()
console.log(sections[0]) // { key: 'string', image: {...}, content: {...} }
gray-matter
has this feature already, albeit undocumented outside of this example. See additional context.
Describe alternatives you've considered
To my knowledge, these are the existing methods to reach a similar result:
Use Vue Components within Markdown
- Useful for some page structures, but doesn't allow for Markdown within the component which defeats the file's purpose
Configure it with JSON/YAML/etc. through frontmatter or a separate file (~/content/about/sections.yaml
)
- Multi-paragraph and formatted content content is cumbersome without Markdown syntax
- Migrating existing markdown files to this format means refactoring the content itself
- Unintuitive compared to a CMS with loop/repeater field
Split content into multiple files (~/content/about/section_1.md
)
- Requires more higher-level calls to fetch and push each section within a component
- Interrupts writer workflow to switch between several files for a continuous page
- Lack of file structure convention, which is basically nuxt's best feature
Create a remark
/rehype
plugin
Going this route is more modular, but I'd argue:
- The feature has enough use cases to warrant 1st-party integration
- An ideal implementation already exists in a dependency
Roll your own configuration with extendParser
This is actually what I'm doing now but I'm not a fan of how much extra heft and excess processing it's adding to my config. It also results in a substandard file naming convention.
Additional context
Syntax-wise, my example above template's markdown could be written like:
---
title: About Us
---
# About Us
Lorem ipsum
---sectionKey
image:
src: '~/asset.png'
align: left
---
## First section content
---callToAction
image:
src: '~/asset.png'
align: right
---
## Second section content
Implementation of gray-matter
's feature within the parser looks relatively frictionless and could give the user a choice between convention (enabled by default) and configuration (disable or provide a custom parsing function).
If we utilize the existing api's return format, the resulting JSON payload could retain the body
property while adding a sections
array. Each section in that array would have the data from its frontmatter and the generated JSON AST:
{
body: {/*...*/}, /* JSON AST */
sections: [
{
key: 'sectionKey',
image: { src: '~/asset.png', align: 'left' },
content: {/*...*/}, /* JSON AST */
},
],
...etc
}
I don't get the impression this would affect the content-fetching methods. However, I haven't thought through how (or whether) these sections can be rendered by the <nuxt-content>
component.
If this sounds like a good feature, I can put together a PR before year's end!
After some consideration, I got a few more ideas on how this could be fleshed out:
Frontmatter parsing
gray-matter
's section parser simply passes the frontmatter as a string by default. For our purposes, a smart default would be utilizing the package's included YAML parser (matter.engines.yaml
). After that, perhaps give users a hook to shape the output (JSON.parse or otherwise)?
Config option to include section data in table of contents generation
In general, most of my personal use cases for sections would also benefit from having sections included in the AST payload for generateToc
. I can imagine use cases where the section syntax would be used for nonhierarchical content, though.
Shape the section object's output to conform to <nuxt-component />
's document
prop
My original idea for a payload was pretty minimal, but a better implementation would have a type signature resembling:
interface IMarkdownSection { key: string, body: JsonAst, text: string, [string]: any }
That should be enough to implement a path to render the section with the existing component. Still unclear how editing content fits in with the idea, though.
@rbndelrio I wonder if you ever implemented this? I'd be pretty interested in using it. I'm doing something a little similar right now but it is a quite hacky. If not, I could clean up my implementation and maybe contribute it.
Are there any updates regarding this? I'm trying to make some tabbed content (with each tab showing different content from md) but haven't been able to find a solution I'm happy with.