Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions app/a/[slug]/BlogPostClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@ import { ArrowLeft, Calendar, User } from "lucide-react"
import Image from "next/image"
import { MarkdownRenderer } from "@/lib/markdown-renderer"
import Footer from "@/components/footer"
import ThemeToggle from "@/components/theme-toggle"
import { BlogPost } from "@/lib/blog"

/**
* Render a complete blog post page with header, optional hero image, metadata, content, and footer.
*
* @param post - BlogPost data used to render the page. Expected properties: `title`, `author`, `date`, `content`, and optional `image`.
* @returns The React element representing the full blog post page.
*/
export default function BlogPostPage({ post }: { post: BlogPost }) {
return (
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10">
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 dark:from-slate-950 dark:via-emerald-950 dark:to-slate-900 transition-colors">
{/* Header */}
<header className="border-b border-gradient-to-r from-[#228B22]/20 to-[#FFBF00]/20 bg-white/90 backdrop-blur-sm sticky top-0 z-50 shadow-sm">
<header className="border-b border-[#228B22]/10 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 backdrop-blur-sm sticky top-0 z-50 shadow-sm transition-colors">
<div className="max-w-4xl mx-auto px-4 py-4 flex justify-between items-center">
<Link
href="/"
className="inline-flex items-center text-[#228B22] hover:text-[#3E921E] transition-colors font-semibold"
className="inline-flex items-center text-[#228B22] hover:text-[#3E921E] dark:text-amber-200 dark:hover:text-amber-300 transition-colors font-semibold"
>
<ArrowLeft className="w-4 h-4 mr-2" />
Back to Stable Viewpoints
</Link>
<ThemeToggle />
</div>
</header>

{/* Article */}
<article className="max-w-4xl mx-auto px-4 py-12">
<div className="bg-white shadow-xl overflow-hidden border border-gradient-to-r from-[#228B22]/10 to-[#FFBF00]/10">
<div className="bg-white dark:bg-slate-900/70 shadow-xl overflow-hidden border border-[#228B22]/10 dark:border-white/10 transition-colors">
{/* Hero Image */}
{post.image && (
<div className="relative h-64 md:h-96">
Expand All @@ -50,7 +58,7 @@ export default function BlogPostPage({ post }: { post: BlogPost }) {
{post.title}
</h1>

<div className="flex items-center gap-6 text-gray-600 mb-8 pb-8 border-b border-gradient-to-r from-[#228B22]/20 to-[#FFBF00]/20">
<div className="flex items-center gap-6 text-gray-600 dark:text-gray-300 mb-8 pb-8 border-b border-[#228B22]/15 dark:border-white/10">
<div className="flex items-center gap-2">
<User className="w-4 h-4 text-[#228B22]" />
<span className="font-medium">{post.author}</span>
Expand All @@ -67,12 +75,12 @@ export default function BlogPostPage({ post }: { post: BlogPost }) {
</div>
</div>

<div className="prose prose-lg max-w-none">
<div className="prose prose-lg max-w-none dark:prose-invert">
<MarkdownRenderer content={post.content} />
</div>

<div className="mt-12 pt-8 border-t border-gradient-to-r from-[#228B22]/20 to-[#FFBF00]/20">
<p className="text-sm text-gray-500 italic">
<div className="mt-12 pt-8 border-t border-[#228B22]/15 dark:border-white/10">
<p className="text-sm text-gray-500 dark:text-gray-400 italic">
© {new Date(post.date).getFullYear()} {post.author}. All rights reserved.
</p>
</div>
Expand All @@ -83,4 +91,4 @@ export default function BlogPostPage({ post }: { post: BlogPost }) {
<Footer />
</div>
)
}
}
15 changes: 12 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Metadata } from "next"
import { Inter, Playfair_Display } from "next/font/google"
import "./globals.css"
import { getBaseUrl, getAbsoluteUrl, getOgImageUrl } from "@/lib/metadata"
import { ThemeProvider } from "@/components/theme-provider"

const inter = Inter({ subsets: ["latin"] })
const playfair = Playfair_Display({
Expand Down Expand Up @@ -70,14 +71,22 @@ export const metadata: Metadata = {
},
}

/**
* Root application layout that sets the HTML language, global fonts, and theme provider.
*
* @param children - The content to render inside the layout (application pages or components).
* @returns A JSX element representing the root HTML document with configured fonts and a ThemeProvider wrapping `children`.
*/
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={`${inter.className} ${playfair.variable}`}>{children}</body>
<html lang="en" suppressHydrationWarning>
<body className={`${inter.className} ${playfair.variable}`}>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
)
}
}
44 changes: 29 additions & 15 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import BlogCard from "@/components/blog-card"
import Pagination from "@/components/pagination"
import Link from "next/link"
import Footer from "@/components/footer"
import ThemeToggle from "@/components/theme-toggle"

interface BlogPost {
slug: string
Expand All @@ -25,6 +26,16 @@ interface PaginatedData {
hasPrevPage: boolean
}

/**
* Renders the blog homepage with paginated posts, header controls, and pagination UI.
*
* Reads the "page" query parameter to initialize and synchronize the current page, loads
* the corresponding paginated posts, and displays loading or error states as needed.
* The header includes site branding, a theme toggle, and a "Submit an Article" link;
* the main area renders post cards and a pagination control that updates both state and URL.
*
* @returns The React element for the homepage containing the header, post grid, pagination, and footer
*/
export default function HomePage() {
const router = useRouter()
const searchParams = useSearchParams()
Expand Down Expand Up @@ -76,20 +87,20 @@ export default function HomePage() {

if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 flex items-center justify-center">
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 dark:from-slate-950 dark:via-emerald-950 dark:to-slate-900 transition-colors flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#228B22] mx-auto mb-4"></div>
<p className="text-gray-600">Loading articles...</p>
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#228B22] dark:border-amber-300 mx-auto mb-4"></div>
<p className="text-gray-600 dark:text-gray-300">Loading articles...</p>
</div>
</div>
)
}

if (!paginatedData) {
return (
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 flex items-center justify-center">
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 dark:from-slate-950 dark:via-emerald-950 dark:to-slate-900 transition-colors flex items-center justify-center">
<div className="text-center">
<p className="text-gray-600">Failed to load articles.</p>
<p className="text-gray-600 dark:text-gray-300">Failed to load articles.</p>
</div>
</div>
)
Expand All @@ -98,22 +109,25 @@ export default function HomePage() {
const { posts, totalPages, hasNextPage, hasPrevPage } = paginatedData

return (
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10">
<div className="min-h-screen bg-gradient-to-br from-green-50 via-yellow-50 to-[#FFC517]/10 dark:from-slate-950 dark:via-emerald-950 dark:to-slate-900 transition-colors">
{/* Header */}
<header className="border-b border-gradient-to-r from-[#228B22]/20 to-[#FFBF00]/20 bg-white/90 backdrop-blur-sm sticky top-0 z-50 shadow-sm">
<header className="border-b border-[#228B22]/10 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 backdrop-blur-sm sticky top-0 z-50 shadow-sm transition-colors">
<div className="max-w-6xl mx-auto px-4 py-6 flex justify-between items-center">
<div>
<h1 className="text-5xl font-bold font-playfair bg-gradient-to-r from-[#228B22] via-[#5A981A] via-[#91A511] via-[#ADAC0D] via-[#E4B905] to-[#FFBF00] bg-clip-text text-transparent drop-shadow-sm leading-tight pb-2">
Stable Viewpoints
</h1>
<p className="text-gray-600 mt-2 text-lg">Independent Articles about Stability</p>
<p className="text-gray-600 dark:text-gray-300 mt-2 text-lg">Independent Articles about Stability</p>
</div>
<div className="flex items-center gap-4">
<ThemeToggle />
<Link
href="/submit"
className="inline-flex items-center gap-2 bg-gradient-to-r from-[#228B22] to-[#91A511] hover:from-[#3E921E] hover:to-[#ADAC0D] text-white px-6 py-3 font-semibold transition-all duration-300 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5"
>
Submit an Article
</Link>
</div>
<Link
href="/submit"
className="inline-flex items-center gap-2 bg-gradient-to-r from-[#228B22] to-[#91A511] hover:from-[#3E921E] hover:to-[#ADAC0D] text-white px-6 py-3 font-semibold transition-all duration-300 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5"
>
Submit an Article
</Link>
</div>
</header>

Expand All @@ -138,4 +152,4 @@ export default function HomePage() {
<Footer />
</div>
)
}
}
Loading