Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/thefubon/next15-mdx-blog

Next 15.0.3 | React 19.0.0 | TailwindCSS 3.4.14 | ESlint 9.14.0 | PNPM
https://github.com/thefubon/next15-mdx-blog

mdx mdx-blog next-blog next15 next15-mdx-blog nextjs15

Last synced: 2 days ago
JSON representation

Next 15.0.3 | React 19.0.0 | TailwindCSS 3.4.14 | ESlint 9.14.0 | PNPM

Awesome Lists containing this project

README

        

# Next Blog

Next 15.0.3 | React 19.0.0 | TailwindCSS 3.4.14 | ESlint 9.14.0 | PNPM

- [x] Next 15
- [x] NDX Blog
- [ ] Tailwind 4

[VIEW CHANGELOG](https://github.com/thefubon/next15-mdx-blog/blob/main/CHANGELOG.md)

### MDX Components

```mdx

```

## Install Package

```bash
pnpm i gray-matter next-mdx-remote path fs
```

## Bug Fix: slug.params

```bash
npx @next/codemod@canary next-async-request-api . --force
```

## Pages

Context MDX: `content/hello-world.mdx`

```mdx
---
title: "Hello World"
date: "2024-11-12"
description: "This is a sample MDX file."
---

## This is a sample MDX file

This is a sample MDX file. It contains JSX and markdown content.

![Image](https://images.unsplash.com/photo-1730840669516-10f18020ca8e?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxmZWF0dXJlZC1waG90b3MtZmVlZHwyNnx8fGVufDB8fHx8fA%3D%3D)

```

Components: `components/mdx/youtube.tsx`

```tsx
const YouTube = ({ videoId }: { videoId: string }) => {
const videoSrc = `https://www.youtube.com/embed/${videoId}`
return (




)
}

export default YouTube
```

Blog List: `app/blog/page.tsx`

```tsx
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import Link from 'next/link'

export default function Blog() {
const blogDirectory = path.join(process.cwd(), 'content')
const fileNames = fs.readdirSync(blogDirectory)

const blogs = fileNames.map((fileName) => {
const slug = fileName.replace('.mdx', '')
const fullPath = path.join(blogDirectory, fileName)
const fileContents = fs.readFileSync(fullPath, 'utf8')

const { data: frontMatter } = matter(fileContents)

const date = new Date(frontMatter.date)

// Отформатируйте дату в удобочитаемый строковый формат
// Например, "12 ноября 2024 г.".
const formattedDate = date.toLocaleDateString('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
})

return {
slug,
formattedDate,
meta: frontMatter,
}
})

return (

{blogs.map((blog) => (



{blog.meta.title}


{blog.formattedDate}


{blog.meta.description}




))}

)
}

```

Blog Post: `app/blog/[slug]/page.tsx`

```tsx
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { MDXRemote } from 'next-mdx-remote/rsc'
import YouTube from '@/components/mdx/youtube'
import Link from 'next/link'

async function getPost(slug: string) {
const markdownFile = fs.readFileSync(
path.join('content', `${slug}.mdx`),
'utf-8'
)
const { data: frontMatter, content } = matter(markdownFile)
return {
frontMatter,
slug,
content,
}
}

export async function generateStaticParams() {
const files = fs.readdirSync(path.join('content'))
const params = files.map((filename) => ({
slug: filename.replace('.mdx', ''),
}))

return params
}

export default async function Page(url: { params: Promise<{ slug: string }> }) {
const params = await url.params
const { slug } = params
const props = await getPost(slug)

// MDX Custom Components
const components = {
YouTube,
}

return (
<>

Назад


{props.frontMatter.title}


{props.frontMatter.description}




>
)
}
```