Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Section splitting in Markdown files #678

Open
rbndelrio opened this issue Dec 9, 2020 · 3 comments
Open

Section splitting in Markdown files #678

rbndelrio opened this issue Dec 9, 2020 · 3 comments
Labels
enhancement New feature or request

Comments

@rbndelrio
Copy link

rbndelrio commented Dec 9, 2020

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!

@rbndelrio rbndelrio added the enhancement New feature or request label Dec 9, 2020
@rbndelrio
Copy link
Author

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.

@nimonian
Copy link

@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.

@danielfazlijevic
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants