Skip to content

Commit

Permalink
Refactor into MDX
Browse files Browse the repository at this point in the history
  • Loading branch information
cesalberca committed Jul 3, 2024
1 parent 452b57d commit 5621053
Show file tree
Hide file tree
Showing 46 changed files with 250 additions and 269 deletions.
33 changes: 30 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@tailwindcss/typography": "0.5.13",
"@vercel/analytics": "1.2.2",
"@vercel/speed-insights": "1.0.10",
"front-matter": "4.0.2",
"next": "14.2.3",
"next-intl": "3.12.2",
"next-mdx-remote": "4.4.1",
Expand Down
4 changes: 2 additions & 2 deletions src/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { notFound } from 'next/navigation'
import { formatDate, getBlogPosts } from '../../utils'
import { getBlogPosts } from '../../utils'
import { baseUrl } from '../../sitemap'
import { CustomMDX } from '../../components/mdx'
import type { Metadata } from 'next'
Expand Down Expand Up @@ -84,7 +84,7 @@ export default function Blog({ params }: Params) {
/>
<h1 className="title font-semibold text-2xl tracking-tighter">{post.metadata.title}</h1>
<div className="flex justify-between items-center mt-2 mb-8 text-sm">
<p className="text-sm text-neutral-600 dark:text-neutral-400">{formatDate(post.metadata.date)}</p>
<p className="text-sm text-neutral-600 dark:text-neutral-400">{post.metadata.date}</p>
</div>
<article className="prose">
<CustomMDX source={post.content} />
Expand Down
7 changes: 3 additions & 4 deletions src/app/components/mdx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import Link from 'next/link'
import type { MDXRemoteProps } from 'next-mdx-remote/rsc'
import { MDXRemote } from 'next-mdx-remote/rsc'
import { highlight } from 'sugar-high'
import React, { createElement } from 'react'
import type { MDXComponents } from 'mdx/types'
import React, { type ComponentProps, createElement } from 'react'

function CustomLink(props: React.LinkHTMLAttributes<HTMLAnchorElement> & React.PropsWithChildren<{ href: string }>) {
let href = props.href
Expand Down Expand Up @@ -57,7 +56,7 @@ function createHeading(level: number) {
return Heading
}

const components: MDXComponents = {
const components: ComponentProps<any>['components'] = {
h1: createHeading(1),
h2: createHeading(2),
h3: createHeading(3),
Expand All @@ -69,5 +68,5 @@ const components: MDXComponents = {
}

export function CustomMDX(props: MDXRemoteProps) {
return <MDXRemote {...props} components={components} />
return <MDXRemote {...props} components={{ ...components, ...(props.components ?? {}) }} />
}
6 changes: 2 additions & 4 deletions src/app/components/posts.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Link from 'next/link'
import { formatDate, getBlogPosts } from '../utils'
import { getBlogPosts } from '../utils'

export function BlogPosts() {
let allBlogs = getBlogPosts()
Expand All @@ -16,9 +16,7 @@ export function BlogPosts() {
.map(post => (
<Link key={post.slug} className="flex flex-col space-y-1 mb-4" href={`/blog/${post.slug}`}>
<div className="w-full flex flex-col md:flex-row space-x-0 md:space-x-2">
<p className="text-neutral-600 dark:text-neutral-400 w-[100px] tabular-nums">
{formatDate(post.metadata.date, false)}
</p>
<p className="text-neutral-600 dark:text-neutral-400 w-[100px] tabular-nums">{post.metadata.date}</p>
<p className="text-neutral-900 dark:text-neutral-100 tracking-tight">{post.metadata.title}</p>
</div>
</Link>
Expand Down
19 changes: 19 additions & 0 deletions src/app/components/talks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Link from 'next/link'
import { getTalks } from '../utils-talks'

export function Talks() {
const allTalks = getTalks()

return (
<div>
{allTalks.map(post => (
<Link key={post.slug} className="flex flex-col space-y-1 mb-4" href={`/blog/${post.slug}`}>
<div className="w-full flex flex-col md:flex-row space-x-0 md:space-x-2">
<p className="text-neutral-600 dark:text-neutral-400 w-[100px] tabular-nums"></p>
<p className="text-neutral-900 dark:text-neutral-100 tracking-tight">{post.metadata.title}</p>
</div>
</Link>
))}
</div>
)
}
8 changes: 4 additions & 4 deletions src/app/rss/route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { baseUrl } from 'app/sitemap'
import { getBlogPosts } from 'app/blog/utils'
import { getBlogPosts } from '../utils'
import { baseUrl } from '../sitemap'

export async function GET() {
let allBlogs = await getBlogPosts()

const itemsXml = allBlogs
.sort((a, b) => {
if (new Date(a.metadata.publishedAt) > new Date(b.metadata.publishedAt)) {
if (new Date(a.metadata.date) > new Date(b.metadata.date)) {
return -1
}
return 1
Expand All @@ -17,7 +17,7 @@ export async function GET() {
<title>${post.metadata.title}</title>
<link>${baseUrl}/blog/${post.slug}</link>
<description>${post.metadata.summary || ''}</description>
<pubDate>${new Date(post.metadata.publishedAt).toUTCString()}</pubDate>
<pubDate>${new Date(post.metadata.date).toUTCString()}</pubDate>
</item>`,
)
.join('\n')
Expand Down
94 changes: 94 additions & 0 deletions src/app/talks/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { notFound } from 'next/navigation'
import { getBlogPosts } from '../../utils'
import { baseUrl } from '../../sitemap'
import { CustomMDX } from '../../components/mdx'
import type { Metadata } from 'next'

interface Params {
params: {
slug: string
}
}

export async function generateStaticParams() {
let posts = getBlogPosts()

return posts.map(post => ({
slug: post.slug,
}))
}

export function generateMetadata({ params }: Params): Metadata | void {
let post = getBlogPosts().find(post => post.slug === params.slug)
if (!post) {
return
}

let { title, date: publishedTime, image, summary } = post.metadata
let ogImage = image ? image : `${baseUrl}/og?title=${encodeURIComponent(title)}`

return {
title,
description: summary,
openGraph: {
title,
description: summary,
type: 'article',
publishedTime,
url: `${baseUrl}/blog/${post.slug}`,
images: [
{
url: ogImage,
},
],
},
twitter: {
card: 'summary_large_image',
title,
description: summary,
images: [ogImage],
},
}
}

export default function Blog({ params }: Params) {
let post = getBlogPosts().find(post => post.slug === params.slug)

if (!post) {
notFound()
}

return (
<section>
<script
type="application/ld+json"
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.metadata.title,
datePublished: post.metadata.date,
dateModified: post.metadata.date,
description: post.metadata.summary,
image: post.metadata.image
? `${baseUrl}${post.metadata.image}`
: `/og?title=${encodeURIComponent(post.metadata.title)}`,
url: `${baseUrl}/blog/${post.slug}`,
author: {
'@type': 'Person',
name: 'My Portfolio',
},
}),
}}
/>
<h1 className="title font-semibold text-2xl tracking-tighter">{post.metadata.title}</h1>
<div className="flex justify-between items-center mt-2 mb-8 text-sm">
<p className="text-sm text-neutral-600 dark:text-neutral-400">{post.metadata.date}</p>
</div>
<article className="prose">
<CustomMDX source={post.content} />
</article>
</section>
)
}
15 changes: 15 additions & 0 deletions src/app/talks/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Talks } from '../components/talks'

export const metadata = {
title: 'Talks',
description: `Here are all the talks I've given.`,
}

export default function Page() {
return (
<section>
<h1 className="font-semibold text-2xl mb-8 tracking-tighter">My Blog</h1>
<Talks />
</section>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ By joining, you''ll not only learn how to stick to good habits but also how to d
'
---

Are you finding it challenging to stick to a routine? Do you often put off tasks indefinitely or procrastinate excessively? If so, you're not alone. Join us on a journey inspired by James Clear's "Atomic Habits" to cultivate positive habits and break free from negative ones.
Do you find it difficult to stick to a routine? Do you often postpone tasks indefinitely or procrastinate excessively? If so, you are not alone. Join us on this journey inspired by "Atomic Habits" by James Clear to create positive habits and break free from negative ones. In this talk, we will explore what habits are, how they form, and how we can hack them in our personal lives.

Together, we'll embark on creating a Web App using Next.js, Shadcn, and Tailwind CSS to seamlessly track our habits. By leveraging NFC tags, we'll effortlessly record our progress and hold ourselves accountable.
Together, we will use a PWA with NextJS to seamlessly track our habits, integrating it with Notion. With NFC tags, we will effortlessly record our progress.

It's time to bid farewell to procrastination and welcome productivity with open arms!
It's time to say goodbye to procrastination and embrace sustainable productivity!
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
64 changes: 64 additions & 0 deletions src/app/utils-talks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import fs from 'fs'
import path from 'path'

interface Metadata {
title: string
length: string
difficulty: string
language: string
// topics: string[]

image: string
// events: {
// name: string
// date: string
// slides: string
// video: string
// }[]
}

// TODO: Parse frontmatter array
function parseFrontmatter(fileContent: string) {
let frontmatterRegex = /---\s*([\s\S]*?)\s*---/
let match = frontmatterRegex.exec(fileContent)
let frontMatterBlock = match![1]
let content = fileContent.replace(frontmatterRegex, '').trim()
let frontMatterLines = frontMatterBlock.trim().split('\n')
let metadata: Partial<Metadata> = {}

frontMatterLines.forEach(line => {
let [key, ...valueArr] = line.split(': ')
let value = valueArr.join(': ').trim()
value = value.replace(/^['"](.*)['"]$/, '$1') // Remove quotes
metadata[key.trim() as keyof Metadata] = value
})

return { metadata: metadata as Metadata, content }
}

function getMDXFiles(dir: string) {
return fs.readdirSync(dir).filter(file => path.extname(file) === '.mdx')
}

function readMDXFile(filePath: string) {
let rawContent = fs.readFileSync(filePath, 'utf-8')
return parseFrontmatter(rawContent)
}

function getMDXData(dir: string) {
let mdxFiles = getMDXFiles(dir)
return mdxFiles.map(file => {
let { metadata, content } = readMDXFile(path.join(dir, file))
let slug = path.basename(file, path.extname(file))

return {
metadata,
slug,
content,
}
})
}

export function getTalks() {
return getMDXData(path.join(process.cwd(), 'src', 'app', 'talks', 'talks'))
}
Loading

0 comments on commit 5621053

Please sign in to comment.