switched to approuter

This commit is contained in:
2025-08-18 13:10:47 -05:00
parent c2b0d905e1
commit 6cd941295c
82 changed files with 5154 additions and 9772 deletions
+135
View File
@@ -0,0 +1,135 @@
import ShareButtons from '@/components/ShareButtons';
import { getPostData, getSortedPostsData } from '@/lib/markdown';
import { PostData, PostMetadata } from '@/types';
import { format } from 'date-fns';
import Image from 'next/image';
import Link from 'next/link';
import React from 'react';
import CommentSection from "@/components/CommentSection";
import { generateMetadata as createMetadata } from '@/components/Metadata';
import type { Metadata } from 'next';
interface PageProps {
params: Promise<{ id: string }>;
}
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { id } = await params;
const post = await getPostData(id);
const postUrl = `https://confessionsofgrace.com/posts/${post.id}`;
return createMetadata({
title: post.title,
description: post.excerpt,
keywords: post.tags.join(', '),
image: post.coverImage,
url: postUrl,
type: 'article'
});
}
async function getPostAndMorePosts(id: string): Promise<{ post: PostData; morePosts: PostMetadata[] }> {
const post = await getPostData(id);
const allPosts = getSortedPostsData();
// Filter out the current post and get a few related posts (by tags)
const otherPosts = allPosts.filter(p => p.id !== post.id);
// Find posts with matching tags
const relatedPosts = otherPosts
.filter(p => p.tags.some(tag => post.tags.includes(tag)))
.slice(0, 2);
// If we don't have enough related posts, add recent posts
const morePosts = relatedPosts.length < 2
? [...relatedPosts, ...otherPosts.filter(p => !relatedPosts.includes(p))].slice(0, 2)
: relatedPosts;
return { post, morePosts };
}
export default async function PostPage({ params }: PageProps) {
const { id } = await params;
const { post, morePosts } = await getPostAndMorePosts(id);
const postUrl = `https://confessionsofgrace.com/posts/${post.id}`;
return (
<article className="max-w-3xl mx-auto">
<header className="mb-8">
<h1 className="text-3xl md:text-4xl font-bold mb-2">{post.title}</h1>
<div className="flex items-center text-primary-500 mb-6">
<span>{post.author}</span>
<span className="mx-2"></span>
<time dateTime={post.date}>
{format(new Date(post.date), 'MMMM d, yyyy')}
</time>
</div>
{post.coverImage && (
<div className="relative h-64 md:h-96 w-full mb-8 rounded-lg overflow-hidden">
<Image
src={post.coverImage}
alt={post.title}
fill
className="object-cover"
priority
/>
</div>
)}
<div className="flex flex-wrap gap-2 mb-6">
{post.tags.map(tag => (
<Link
key={tag}
href={`/tags/${tag}`}
className="text-sm bg-primary-100 text-primary-600 px-3 py-1 rounded-md hover:bg-primary-200"
>
{tag}
</Link>
))}
</div>
</header>
<div
className="blog-post prose prose-lg max-w-none"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
<div className="mt-8 pt-6 border-t border-primary-200">
<ShareButtons
url={postUrl}
title={post.title}
description={post.excerpt}
/>
</div>
<div className="mt-12 pt-6 border-t border-primary-200">
<h2 className="text-2xl font-bold mb-6">More Posts</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{morePosts.slice(0, 2).map(post => (
<div key={post.id} className="bg-white p-6 rounded-md border border-primary-200 shadow-sm">
<h3 className="font-bold mb-2">
<Link href={`/posts/${post.id}`} className="hover:text-accent-dark">
{post.title}
</Link>
</h3>
<p className="text-primary-600 text-sm mb-2">
{format(new Date(post.date), 'MMMM d, yyyy')}
</p>
<p className="text-primary-700">{post.excerpt}</p>
</div>
))}
</div>
</div>
<CommentSection postId={post.id} />
<div className="mt-12 pt-6 border-t border-primary-200">
<Link href="/public" className="text-accent-dark hover:text-accent inline-flex items-center">
<svg className="mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Back to all posts
</Link>
</div>
</article>
);
}
+84
View File
@@ -0,0 +1,84 @@
import React from 'react';
import Link from 'next/link';
import { format } from 'date-fns';
import { getSortedPostsData } from '@/lib/markdown';
import { PostMetadata } from '@/types';
import { generateMetadata as createMetadata } from '@/components/Metadata';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
return createMetadata({
title: 'Posts Archive',
description: 'Browse all posts from Confessions of Grace, organized by year.',
url: 'https://confessionsofgrace.com/posts',
type: 'website'
});
}
async function getPostsAndYears(): Promise<{ posts: PostMetadata[]; years: number[] }> {
const posts = getSortedPostsData();
// Extract unique years from post dates
const years = Array.from(new Set(
posts.map(post => new Date(post.date).getFullYear())
)).sort((a, b) => b - a); // Sort years in descending order
return { posts, years };
}
export default async function PostsPage() {
const { posts, years } = await getPostsAndYears();
return (
<div className="max-w-3xl mx-auto">
<h1 className="text-3xl md:text-4xl font-bold mb-8">Archive</h1>
{years.map(year => (
<div key={year} className="mb-12">
<h2 className="text-2xl font-bold border-b border-primary-200 pb-2 mb-6">{year}</h2>
<ul className="space-y-6">
{posts
.filter(post => new Date(post.date).getFullYear() === year)
.map(post => (
<li key={post.id} className="bg-white p-6 rounded-md shadow-sm border border-primary-200">
<div className="md:flex md:justify-between md:items-center">
<div>
<h3 className="text-xl font-bold mb-2">
<Link href={`/posts/${post.id}`} className="hover:text-accent-dark">
{post.title}
</Link>
</h3>
<div className="flex items-center mb-2 text-sm text-primary-500">
<span>{post.author}</span>
<span className="mx-2"></span>
<time dateTime={post.date}>
{format(new Date(post.date), 'MMMM d, yyyy')}
</time>
</div>
<p className="text-primary-600">{post.excerpt}</p>
</div>
</div>
<div className="flex flex-wrap gap-2 mt-4 items-center">
{post.tags.map(tag => (
<Link
key={tag}
href={`/tags/${tag}`}
className="text-sm bg-primary-100 text-primary-600 px-3 py-1 rounded-md hover:bg-primary-200"
>
{tag}
</Link>
))}
<div className="mt-4 md:mt-0 md:self-end md:ml-auto flex justify-end">
<Link href={`/posts/${post.id}`} className="text-sm bg-accent text-white px-3 py-1 rounded-md hover:bg-accent-dark">
Read post
</Link>
</div>
</div>
</li>
))}
</ul>
</div>
))}
</div>
);
}