Update quote style and add markdown rendering
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from "next/navigation";
|
||||||
import Link from 'next/link';
|
import Link from "next/link";
|
||||||
import { loadStories } from '@/utils/mdxLoader';
|
import { loadStories } from "@/utils/mdxLoader";
|
||||||
import { formatReadingTime } from '@/utils/readingTime';
|
import { formatReadingTime } from "@/utils/readingTime";
|
||||||
|
|
||||||
interface StoryPageProps {
|
interface StoryPageProps {
|
||||||
params: {
|
params: {
|
||||||
@@ -9,27 +9,30 @@ interface StoryPageProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const storiesDirectory = process.cwd() + '/src/content/stories';
|
const storiesDirectory = process.cwd() + "/src/content/stories";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filenames = fs.readdirSync(storiesDirectory);
|
const filenames = fs.readdirSync(storiesDirectory);
|
||||||
return filenames.map((filename: string) => ({
|
return filenames.map((filename: string) => ({
|
||||||
slug: filename.replace(/\.mdx$/, ''),
|
slug: filename.replace(/\.mdx$/, ""),
|
||||||
}));
|
}));
|
||||||
} catch {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({ params }: StoryPageProps) {
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: StoryPageProps): Promise<Metadata> {
|
||||||
const story = await getStoryBySlug(params.slug);
|
const story = await getStoryBySlug(params.slug);
|
||||||
|
|
||||||
if (!story) {
|
if (!story) {
|
||||||
return {
|
return {
|
||||||
title: 'Story Not Found',
|
title: "Story Not Found",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +53,14 @@ export async function generateMetadata({ params }: StoryPageProps) {
|
|||||||
|
|
||||||
async function getStoryBySlug(slug: string) {
|
async function getStoryBySlug(slug: string) {
|
||||||
const stories = await loadStories();
|
const stories = await loadStories();
|
||||||
return stories.find(story => story.id === slug.replace(/[^a-zA-Z0-9]/g, '-'));
|
return stories.find(
|
||||||
|
(story) => story.id === slug.replace(/[^a-zA-Z0-9]/g, "-"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function StoryPage({ params }: StoryPageProps) {
|
export default async function StoryPage({ params }: StoryPageProps) {
|
||||||
const story = await getStoryBySlug(params.slug);
|
const story = await getStoryBySlug(params.slug);
|
||||||
|
|
||||||
if (!story) {
|
if (!story) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
@@ -122,16 +127,16 @@ export default async function StoryPage({ params }: StoryPageProps) {
|
|||||||
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 uppercase mb-4">
|
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 uppercase mb-4">
|
||||||
{story.title}
|
{story.title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="flex gap-4 text-sm mb-6">
|
<div className="flex gap-4 text-sm mb-6">
|
||||||
<span className="bg-yellow-200 text-black px-3 py-1 border-2 border-black font-bold">
|
<span className="bg-yellow-200 text-black px-3 py-1 border-2 border-black font-bold">
|
||||||
{formatReadingTime(story.readTime)} read
|
{formatReadingTime(story.readTime)} read
|
||||||
</span>
|
</span>
|
||||||
<span className="bg-gray-200 text-black px-3 py-1 border-2 border-black font-bold">
|
<span className="bg-gray-200 text-black px-3 py-1 border-2 border-black font-bold">
|
||||||
{new Date(story.createdAt).toLocaleDateString('en-US', {
|
{new Date(story.createdAt).toLocaleDateString("en-US", {
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
month: 'long',
|
month: "long",
|
||||||
day: 'numeric'
|
day: "numeric",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -153,4 +158,4 @@ export default async function StoryPage({ params }: StoryPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from "next/navigation";
|
||||||
import Link from 'next/link';
|
import Link from "next/link";
|
||||||
import { loadThoughts } from '@/utils/mdxLoader';
|
import { loadThoughts } from "@/utils/mdxLoader";
|
||||||
import { formatReadingTime } from '@/utils/readingTime';
|
import { formatReadingTime } from "@/utils/readingTime";
|
||||||
|
|
||||||
interface ThoughtPageProps {
|
interface ThoughtPageProps {
|
||||||
params: {
|
params: {
|
||||||
@@ -9,27 +9,31 @@ interface ThoughtPageProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import Markdown from "react-markdown";
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const thoughtsDirectory = process.cwd() + '/src/content/thoughts';
|
const thoughtsDirectory = process.cwd() + "/src/content/thoughts";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filenames = fs.readdirSync(thoughtsDirectory);
|
const filenames = fs.readdirSync(thoughtsDirectory);
|
||||||
return filenames.map((filename: string) => ({
|
return filenames.map((filename: string) => ({
|
||||||
slug: filename.replace(/\.mdx$/, ''),
|
slug: filename.replace(/\.mdx$/, ""),
|
||||||
}));
|
}));
|
||||||
} catch {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({ params }: ThoughtPageProps) {
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: ThoughtPageProps): Promise<Metadata> {
|
||||||
const thought = await getThoughtBySlug(params.slug);
|
const thought = await getThoughtBySlug(params.slug);
|
||||||
|
|
||||||
if (!thought) {
|
if (!thought) {
|
||||||
return {
|
return {
|
||||||
title: 'Thought Not Found',
|
title: "Thought Not Found",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +54,14 @@ export async function generateMetadata({ params }: ThoughtPageProps) {
|
|||||||
|
|
||||||
async function getThoughtBySlug(slug: string) {
|
async function getThoughtBySlug(slug: string) {
|
||||||
const thoughts = await loadThoughts();
|
const thoughts = await loadThoughts();
|
||||||
return thoughts.find(thought => thought.id === slug.replace(/[^a-zA-Z0-9]/g, '-'));
|
return thoughts.find(
|
||||||
|
(thought) => thought.id === slug.replace(/[^a-zA-Z0-9]/g, "-"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
||||||
const thought = await getThoughtBySlug(params.slug);
|
const thought = await getThoughtBySlug(params.slug);
|
||||||
|
|
||||||
if (!thought) {
|
if (!thought) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
@@ -122,7 +128,7 @@ export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
|||||||
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 uppercase mb-4">
|
<h1 className="text-3xl md:text-4xl font-bold text-gray-900 uppercase mb-4">
|
||||||
{thought.title}
|
{thought.title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="flex gap-4 text-sm mb-6">
|
<div className="flex gap-4 text-sm mb-6">
|
||||||
<span className="bg-teal-200 text-black px-3 py-1 border-2 border-black font-bold">
|
<span className="bg-teal-200 text-black px-3 py-1 border-2 border-black font-bold">
|
||||||
{thought.category}
|
{thought.category}
|
||||||
@@ -131,10 +137,10 @@ export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
|||||||
{formatReadingTime(thought.readTime)} read
|
{formatReadingTime(thought.readTime)} read
|
||||||
</span>
|
</span>
|
||||||
<span className="bg-gray-200 text-black px-3 py-1 border-2 border-black font-bold">
|
<span className="bg-gray-200 text-black px-3 py-1 border-2 border-black font-bold">
|
||||||
{new Date(thought.createdAt).toLocaleDateString('en-US', {
|
{new Date(thought.createdAt).toLocaleDateString("en-US", {
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
month: 'long',
|
month: "long",
|
||||||
day: 'numeric'
|
day: "numeric",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,7 +148,7 @@ export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
|||||||
|
|
||||||
<div className="prose prose-lg max-w-none">
|
<div className="prose prose-lg max-w-none">
|
||||||
<div className="text-gray-800 leading-relaxed whitespace-pre-line">
|
<div className="text-gray-800 leading-relaxed whitespace-pre-line">
|
||||||
{thought.content}
|
<Markdown>{thought.content}</Markdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -156,4 +162,4 @@ export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user