DEV Community

Ashutosh
Ashutosh

Posted on

1 1

Linking Blog Content and Markdown conversion in Next.js

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.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay