DEV Community

loading...

Linking Blog Content and Markdown conversion in Next.js

Ashutosh
・4 min read

So far:

  • We have set up a page to list blogs.
  • Link blogs to their respective links

However, if we click on the individual blog, it is not showing relevant content. In this article, we fix this issue. And our blog URL presents relevant data to the users.

When this series started, I downloaded the content (in Markdown) from dev.to in JSON file saved in a data folder. Now, we need to read the JSON file and load it in our blog.

Create the "Utilities" folder under the root of the application folder, and add the FileRead.js file under Utilities.

import fs from 'fs';
import path from "path";


// Get All Blogs Details
export default function getAllBlogsData(fileName) {
    let blog = new Array()
    const data = getFileData(fileName)

    for (let index in data) {
        const catList = data[index].cached_tag_list

        blog.push({
            title: data[index].title,
            date: data[index].published_at,
            body: data[index].body_markdown,
            description: data[index].description,
            categories: catList,
            slug: data[index].slug
        });
    }

    // Reverse an Array
    const reverseData = blog.slice(0).reverse()

    return reverseData
}

// Get Individual Blog Data from slug
export function getBlogData(fileName, slug) {
    const data = getFileData(fileName)

    for (let index in data) {
        if (data[index].slug === slug) {
            return data[index]
        }
    }
    return 0
}

function getFileData(fileName) {
    const fileToRead = path.join(process.cwd(), fileName)
    return ( JSON.parse(fs.readFileSync(fileToRead)) )
}
Enter fullscreen mode Exit fullscreen mode

We created a JavaScript file and, add the following functions:

  • getAllBlogsData() - [To read all the data from the JSON file]
  • getBlogData() - [To read the data for the individual blog]
  • getFileData() - [Get all the data from the file in the JSON format]

In the index.js, first, import the getAllBlogsData function from the FileRead.js.

import getAllBlogsData from "../Utilities/FileRead";
Enter fullscreen mode Exit fullscreen mode

And then modify the getStaticProps(context) subroutine.

export async function getStaticProps(context) {
    const data = getAllBlogsData('/data/articles.json')

    return  {
        props: {
            sample_blogs: data
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Hmm, now our index.js file is cleaner :).

Open the file [slug].js and update the file with the following code:

import BlogDetailsComponent from "../../components/Blog/BlogDetailsComponent";
import {getBlogData} from "../../Utilities/FileRead";
import CategoriesComponent from "../../components/Categories/CategoriesComponent";
import BlogComponent from "../../components/Blog/BlogComponent";

function IndividualBlogPage(props) {

    return (
        <div className="flex flex-auto">
            <CategoriesComponent />
            <BlogDetailsComponent blog={props}/>
            <div></div>
        </div>
    )
}

export async function getServerSideProps(context) {
    const fileName = '/data/articles.json';
    const { params } = context

    const blogData = getBlogData(fileName, params.slug)

    return {
        props:{
            title: blogData.title,
            date: blogData.published_at,
            body: blogData.body_markdown,
            description: blogData.description,
            categories: blogData.cached_tag_list,
            slug: params.slug
        }
    }
}

export default IndividualBlogPage
Enter fullscreen mode Exit fullscreen mode

Up to this point, we pass the slug to the component and, we'll get the result for the individual blog post.

Before proceeding, we also need to some styles to our blog.

Create a new file BlogStyles.js under the blog folder with the following code:

import CSS from 'styled-jsx/css'

export default css.global `
    .blogs ul > li > ul > li {
      font-weight: 400;
      font-size: 0.8em;
    }

    p, ul, li {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif, Arial;
      letter-spacing: calc(0px * 16);
      line-height: calc(2.5px * 16);
      color: rgb(14, 16, 26);
      -webkit-font-smoothing: antialiased;
      animation-iteration-count: 1!important;
    }

    .blogs h1, p, ul {
      margin-left: 1.5em;
    }

    .blogs p { 
      display: block;
      font-size: calc(1.375px * 16);
      margin-block-start: 1em;
      margin-block-end: 1em;
      margin-inline-start: 1.5em;
      margin-inline-end: 1.5em;
      font-weight: 400;
    }

    .blogs ul {
      margin-left: 1.5em;
      font-size: 1.2em;
      list-style-type: disc;
    }

    .blogs ul > li {
      margin-left: 1.5em;
      font-weight: 400;
    }


    @media (min-width: 768px) {
      .blogs h1 {
        font-size: 1.5em;
        text-align: left;
        margin: 1.5em;
        font-weight: bold;
      }

      .blogs h2 {
        font-size: 1.2em;
        text-align: left;
        margin: 1.5em;
        font-weight: bold;
      }
    }
`
Enter fullscreen mode Exit fullscreen mode

Now, we need to pass the javascript object to the BlogDetailsComponent.js file.

import ReactMarkdown from 'react-markdown';
import styles from './BlogStyles'

function BlogDetailsComponent(props) {

    return (
        <div className={`ml-10 mt-4 w-3/5 container mr-4 shadow rounded border blogs `}>
            <ReactMarkdown >{props.blog.body}</ReactMarkdown>
            <style jsx global>
                {styles}
            </style>
        </div>
    )
} 

export default BlogDetailsComponent
Enter fullscreen mode Exit fullscreen mode

If the 'react-markdown' package doesn't exist, please install it using the npm.

We also have some code written for the tutorials but it is not showing correctly as of now.

Please install

npm install react-syntax-highlighter
Enter fullscreen mode Exit fullscreen mode

And open the BlogDetailsComponent.js and add the following lines at the top of the file:

import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
Enter fullscreen mode Exit fullscreen mode

And modify the function:

function BlogDetailsComponent(props) {
    // let body = props.blog.body
    // let res = body.match(/<img.* \/>/g);
    // console.log(res)
    const customComponents = {

        code(code) {
            const { className, children } =  code

            let language = new Array();

            if (className) {
                language = className.split("-");
            }

            return (
                <SyntaxHighlighter language={language[language.length -1]} children={children} style={atomDark}   />
            )
        }
    }

    return (
        <div className={`ml-10 mt-4 w-3/5 container mr-4 shadow rounded border blogs `}>
            <ReactMarkdown components={customComponents}>{props.blog.body}</ReactMarkdown>
            <style jsx global>
                {styles}
            </style>
        </div>
    )
} 

export default BlogDetailsComponent
Enter fullscreen mode Exit fullscreen mode

Refresh the page and, you'll see the highlighted syntax in our code blocks.

That's all for now. In the upcoming article, we fix the broken images.

Discussion (0)