DEV Community

Cover image for How to create a blog for your Next.js and ChakraUI website
Muhammad Ahmad
Muhammad Ahmad

Posted on • Edited on • Originally published at my-portfolio-ma-ahmad.vercel.app

How to create a blog for your Next.js and ChakraUI website

I have been writing on dev.to for more than 1 year. I really like to write articles on dev.to but now I wanted to write posts on my portfolio website.
So I created a blog where I'll be writing new articles and showing my dev.to posts.
I'll guide you how you can create similar blog for your Next.js website.

Live demo: posts-list
Github repo: https://github.com/MA-Ahmad/myPortfolio

1. Packages required

2. Create a mdx file

See mdx file sample here mdx-file

3. Create a Blog page

Show all local and dev.to posts

const getPosts = async () => { const res = await fetch("https://dev.to/api/articles?username=m_ahmad"); const posts = await res.json(); return posts; }; const root = process.cwd(); export const getStaticProps: GetStaticProps = async () => { const paths = fs .readdirSync(path.join(root, "data", "posts")) .map(p => p.replace(/\.mdx/, "")); const localPosts = []; paths.map(p => { const markdownWithMeta = fs.readFileSync( path.join(root, "data", "posts", `${p}.mdx`), "utf-8" ); const { data: frontmatter } = matter(markdownWithMeta); localPosts.push({ slug: p, title: frontmatter.title, description: frontmatter.description, published_at: frontmatter.published_at, comments_count: frontmatter.comments_count, public_reactions_count: frontmatter.public_reactions_count, tag_list: frontmatter.tags, url: null }); }); const devtoPosts = await getPosts(); const posts = [...localPosts, ...devtoPosts]; if (!posts) { return { notFound: true }; } return { props: { posts }, revalidate: 1 }; }; 
Enter fullscreen mode Exit fullscreen mode

4. Create a blog detail page

  • Get paths of all blog posts
const root = process.cwd(); export const getStaticPaths: GetStaticPaths = async () => { const devData: BlogPost[] = await getAllBlogs(); const devtoPaths = devData.map(data => ({ params: { slug: data?.slug } })); const localPaths = fs .readdirSync(path.join(root, "data", "posts")) .map(p => ({ params: { slug: p.replace(/\.mdx/, "") } })); return { paths: [...devtoPaths, ...localPaths], fallback: true }; }; const getAllBlogs = async () => { const res = await fetch("https://dev.to/api/articles?username=m_ahmad"); if (res.status < 200 || res.status >= 300) { throw new Error( `Error fetching... Status code: ${res.status}, ${res.statusText}` ); } const data = await res.json(); return data; }; 
Enter fullscreen mode Exit fullscreen mode
  • markdown to html code
const markdownToHtml = async (markdown: string) => { const result = await remark() .use(html) .use(prism) .process(markdown); return result.toString(); }; 
Enter fullscreen mode Exit fullscreen mode
  • Select the right blog and convert it to html
export const getStaticProps: GetStaticProps = async ({ params }) => { const devData: BlogPost[] = await getAllBlogs(); const selectedBlog = devData.filter(data => data?.slug === params?.slug); let blogObj = null, remarkContent = null; if (selectedBlog.length) { const res = await fetch( `https://dev.to/api/articles/${selectedBlog[0]?.id}` ); blogObj = await res.json(); remarkContent = await markdownToHtml(blogObj.body_markdown); } else { const markdownWithMeta = fs.readFileSync( path.join(root, "data", "posts", `${params?.slug}.mdx`), "utf-8" ); const { data: frontmatter, content } = matter(markdownWithMeta); blogObj = frontmatter; remarkContent = await markdownToHtml(content); } if (!devData) { return { notFound: true }; } return { props: { articleContent: remarkContent, blogDetails: blogObj }, revalidate: 1 }; }; 
Enter fullscreen mode Exit fullscreen mode

5. Create a custom stylesheet to handle dark and light theme

Blog page

blog

Top comments (3)

Collapse
 
aligerm profile image
Ali

I love animations.

Collapse
 
alexweininger profile image
Alex Weininger

Your portfolio is amazing! I really love the open source page.

Collapse
 
m_ahmad profile image
Muhammad Ahmad

Glad you liked it.