cassidoo / next-netlify-blog-starter

A lightweight markdown blog starter built with Next.js 12+ and Netlify
https://next-netlify-blog-starter.netlify.app/
Other
200 stars 55 forks source link

Nested Markdown files? (Information request) #6

Open brycewray opened 4 years ago

brycewray commented 4 years ago

This repo and the accompanying article on the Netlify blog are very helpful!

What additional config, and in which file(s), would be required to let this properly handle routing for Markdown files in nested directories — so that, for example, the final path would be something like example.com/post/dirlevel1/dirlevel2/dirlevel3/my-post for a Markdown file in /posts/dirlevel1/dirlevel2/dirlevel3/? It currently can detect such a file's presence but it's unclear what the correct pathname reference should be in /components/PostList.js to provide the right URL. Most Next.js-to-blog tutorials similarly seem to assume only one level of Markdown posts, but this becomes impractical after a while.

Thanks for any consideration you can give to this request.

brycewray commented 4 years ago

Would greatly appreciate an answer to my question, and I will understand if it's considered a "dumb noob" question. 😄

ReangeloJ commented 3 years ago

Would greatly appreciate an answer to my question, and I will understand if it's considered a "dumb noob" question. 😄

A friend of mine got through with this. I created a nested folder structure using the beta version.

The structure was like this Public -> Content -> Projects -> FolderA, FolderB, FolderA -> Project_1, Project_2, Project_1 -> landing image, cover_image, Project_1.md

The mock-config I used:

I used the hidden widget to hardcode that all projects in this particular setup are listed in Folder_A becuase for my particular project I needed to filter. And this Setup I repeated for Folder_B, etc. I could have made it more dynamic by adding a dropdown with the options Folder_A, Folder_B and setting that value in the path prop above, but if a user would miss-label, the post would end up somewhere else and they might have thought they deleted it.

I then needed a way to: -1 show all projects -2 access their data for path to the image etc. That's where my friend helped and came up with this code:

//folder lib/api.js


  import fs from 'fs'
  import { join } from 'path'
  import matter from 'gray-matter'

  const postsDirectory = join(process.cwd(), 'public', 'content', 'projects')

  export function getPostSlugs() {
      return walkSync(postsDirectory)
  }

  // List all files in a directory in Node.js recursively in a synchronous fashion
  const walkSync = function(dir, filelist) {
      var fs = fs || require('fs'),
          files = fs.readdirSync(dir);
      filelist = filelist || [];
      files.forEach(function(file) {
          if (fs.statSync(dir + '/' + file).isDirectory()) {
              filelist = walkSync(dir + '/' + file, filelist);
          }
          else {
              if(file.endsWith(".md")){
                  console.log(dir, file)
                  let post = {
                      directory: dir,
                      file: file
                  };

                  filelist.push(post);
              }
          }
      });
      return filelist;
  };

  export function getPostBySlug(slug, fields = []) {

      const fullPath = slug.directory + '/' + slug.file;
      const fileContents = fs.readFileSync(fullPath, 'utf8')
      const { data, content } = matter(fileContents)

      const items = {}

      // Ensure only the minimal needed data is exposed
      fields.forEach((field) => {
          if (field === 'slug') {
              items[field] = slug.file
          }
          if (field === 'content') {
              items[field] = content
          }

          if (data[field]) {
              items[field] = data[field]
          }
      })

      return items
  }

  export function getAllPosts(fields = []) {
      const slugs = getPostSlugs()
      const posts = slugs
          .map((slug) => getPostBySlug(slug, fields))
          // sort posts by date in descending order
          .sort((post1, post2) => (post1.date > post2.date ? '-1' : '1'))
      return posts
  }

IN PROJECTS PAGE


  import React, { useEffect } from 'react'
  import { getAllPosts } from '../lib/api'

  const Projects = ({ allProjects }) => {
      return (
          <div>
              <ProjectPage projects={allProjects}/>
          </div>
      )

  }

  export async function getStaticProps () {
      // These are all the props from your markdown file
      const allProjects = getAllPosts([
          'title',
          'date',
          'slug',
          'anotherProp',
      ])

      return {
          props: { allProjects },
      }
  }

  export default  Projects

Hope this helps happy new year! :)

brycewray commented 3 years ago

Thanks very much, @ReangeloJ! Happy 2021 to you, too.