Skip to content

vincentole/mdx_blog_website

Repository files navigation

Contributors Forks Stargazers Issues MIT License LinkedIn


Logo

MDX Blog Website

A responsive and static blog website with category functionality, portfolio section and more.

Explore the code »

View Demo · Report Bug

Table of Contents
  1. About The Project
  2. Getting Started
  3. License
  4. Contact
  5. Acknowledgments

About The Project


Rustica Coffee Website Screen Shot


MDX Blog Website is a statically generated blog. Blog posts can be grouped into categories accessible from the sidebar. It is also possible to add individual pages based on mdx and group them into categories. Each individual page shows linked tags of the other pages within its category for easier access. In addition to Markdown pages, there are three other sections: Who Am I, Portfolio and Contact, which offer the possibility to display additional author information.

(back to top)

Built With

type script tailwind react next mdx bundler mdx gray matter

(back to top)

Highlights of What I Learned

In this section, I highlight a few code snippets that I find valuable. Please refer to the section below for more concepts and features I implemented.

Get Blog Data (markdown, metadata, category count)

This function is the core logic of the blog. First, the frontmatter metadata interface is defined according to the metadata used in the actual .mdx file. In the function, I set the path to the folder that contains the blog entries, where the last folder name can be adjusted as needed via the function argument. Then I initialize the numberOfPosts as an object containing all categories and the value 0 as a field value. Since the map function is asynchronous, I use Promise.all() to await all promises. Inside the map function, I return the output code and metadata output using mdx-bundler and simulatively increment the number of blog entries within the specified category. Note: The date is reformatted to an ISO string because of a type error.

The final output is an object with numberOfPosts containing the number of posts per category and the object posts containing the code and metadata of each post.

import fs from 'fs';
import path from 'path';
import { bundleMDX } from 'mdx-bundler';
import { CategoriesUnion } from '#/src/types/types';
import { initialState } from '#/src/store/NumberOfPostsContext';

export interface FrontmatterBlog {
    title: string;
    description: string;
    category: CategoriesUnion;
    date: string;
    slug: string;
}

export async function getBlogData(folder: string) {
    const blogDir = path.join(process.cwd(), 'src', 'markdown', folder);
    const files = fs.readdirSync(blogDir);
    const numberOfPosts = { ...initialState };

    const posts = await Promise.all(
        files.map(async (filename) => {
            const markdownWithMeta = fs.readFileSync(path.join(blogDir, filename), 'utf-8');

            const result = await bundleMDX<FrontmatterBlog>({ source: markdownWithMeta });
            result.frontmatter.date = new Date(result.frontmatter.date).toISOString();

            const category = result.frontmatter.category;

            numberOfPosts[category] = numberOfPosts[category] ? (numberOfPosts[category] += 1) : 1;
            numberOfPosts['DevBlog'] = numberOfPosts['DevBlog']
                ? (numberOfPosts['DevBlog'] += 1)
                : 1;

            return result;
        }),
    );

    return { numberOfPosts, posts };
}

This is an example of the NumberOfPosts type used for the numberOfPosts object for reference:

type NumberOfPosts = {
    Algorithms: number;
    'React.js': number;
    'Next.js': number;
};

Generating Blog Post Lists

With getStaticProps data can be passed to statically generated pages. Here I get the blog data from the function getBlogData, which I showed in more detail above. I then use type guards to make sure I have a category slug with a string type, otherwise a 404 page is returned. Next, the category slug is converted to the into the actual category name, and again type-checking is required to ensure that this category exists. Finally, I either return the metadata for all posts if the category devblog was chosen, or I only return the metadata for the appropriate category. All posts are sorted by date, with new posts first. To understand this, notice the -(...) around new Date(a.date).getTime() - new Date(b.date).getTime().

export async function getStaticProps(context: GetStaticPropsContext) {
    const { numberOfPosts, posts } = await getBlogData('blog');

    if (!context.params || !context.params.category || Array.isArray(context.params.category)) {
        return {
            notFound: true,
        };
    }

    const contextCategory = context.params.category;
    const category = categorySlugToCategory(contextCategory);

    if (!category) {
        return {
            notFound: true,
        };
    }

    if (contextCategory === 'devblog') {
        const frontmatterSorted = posts
            .map((post) => post.frontmatter)
            .sort((a, b) => -(new Date(a.date).getTime() - new Date(b.date).getTime()));

        return { props: { numberOfPosts, frontmatterSorted, category: 'DevBlog' } };
    } else {
        const frontmatterSorted = posts
            .map((post) => post.frontmatter)
            .filter((post) => categoryToSlug(post.category) === contextCategory)
            .sort((a, b) => -(new Date(a.date).getTime() - new Date(b.date).getTime()));

        return { props: { numberOfPosts, frontmatterSorted, category } };
    }
}

(back to top)

Roadmap & Continued Development

  • TypeScript
  • Reusable components
  • Dynamic routes
  • Transitions
  • Responsive sidebar
  • Number of blog posts by category
  • Blog post pages via mdx
  • Single pages via mdx
  • Show links to other single pages of the same category

(back to top)

Getting Started

To get a local copy up and running follow these steps.

Installation

  1. Clone the repo

    ```sh
    git clone https://github.com/vincentole/mdx_blog_website.git
    ```
    
  2. Install packages

    npm

    npm install

    yarn

    yarn

(back to top)

Usage

You can run the project in a local environment as follows:

npm

npm run dev

yarn

yarn dev

(back to top)

License

Distributed under the MIT License. See github/LICENSE.md for more information.

(back to top)

Contact

Ole Urfels (vincentole):

Project Link: https://github.com/vincentole/mdx_blog_website

(back to top)

Acknowledgments

(back to top)

About

A mdx based blog website with personal info, blog, categories and more.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published