mirror of
https://github.com/Techtonic-Fault/homepage.git
synced 2026-01-23 05:26:30 +00:00
159 lines
5.7 KiB
TypeScript
159 lines
5.7 KiB
TypeScript
import { notFound } from "next/navigation"
|
|
import { Navbar } from "@/components/navbar"
|
|
import { Footer } from "@/components/footer"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
import { ArrowLeft, Calendar, Clock } from "lucide-react"
|
|
import Image from "next/image"
|
|
import Link from "next/link"
|
|
import { Button } from "@/components/ui/button"
|
|
import type { Metadata } from "next"
|
|
import { MDXRemote } from "next-mdx-remote/rsc"
|
|
import rehypePrism from "rehype-prism-plus"
|
|
import blogPosts from "@/data/blog"
|
|
|
|
interface BlogPostPageProps {
|
|
params: {
|
|
slug: string
|
|
}
|
|
}
|
|
|
|
export async function generateMetadata({ params }: BlogPostPageProps): Promise<Metadata> {
|
|
const p = await params;
|
|
const post = blogPosts.find((post) => post.slug === p.slug)
|
|
|
|
if (!post) {
|
|
return {
|
|
title: "Post non trovato",
|
|
}
|
|
}
|
|
|
|
return {
|
|
title: `${post.title} | TECHTONIC FAULT Blog`,
|
|
description: post.excerpt,
|
|
}
|
|
}
|
|
|
|
export default async function BlogPostPage({ params }: BlogPostPageProps) {
|
|
const p = await params;
|
|
const post = blogPosts.find((post) => post.slug === p.slug)
|
|
|
|
if (!post) {
|
|
notFound()
|
|
}
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar />
|
|
|
|
<main className="flex-1">
|
|
{/* Hero Section */}
|
|
<section className="w-full py-12 md:py-24 lg:py-32 bg-primary-50 dark:bg-gray-900">
|
|
<div className="container px-4 md:px-6 mx-auto">
|
|
<div className="flex flex-col items-center text-center space-y-4 max-w-3xl mx-auto">
|
|
<Badge className="bg-primary-100 text-primary-900 border-primary-200 hover:bg-primary-100">
|
|
{post.category}
|
|
</Badge>
|
|
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl text-primary-900 dark:text-primary-300">
|
|
{post.title}
|
|
</h1>
|
|
<div className="flex items-center justify-center gap-4 text-gray-500 dark:text-gray-400">
|
|
<div className="flex items-center">
|
|
<Calendar className="h-4 w-4 mr-2" />
|
|
{post.date}
|
|
</div>
|
|
<div className="flex items-center">
|
|
<Clock className="h-4 w-4 mr-2" />
|
|
{post.readTime}
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center justify-center gap-2 mt-4">
|
|
<Avatar className="h-10 w-10">
|
|
<AvatarImage src={post.author.avatar || "/placeholder.svg"} alt={post.author.name} />
|
|
<AvatarFallback>
|
|
{post.author.name
|
|
.split(" ")
|
|
.map((n) => n[0])
|
|
.join("")}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
<div className="text-left">
|
|
<p className="text-sm font-medium text-primary-900 dark:text-primary-300">{post.author.name}</p>
|
|
<p className="text-xs text-gray-500 dark:text-gray-400">{post.author.title}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Featured Image */}
|
|
<div className="relative w-full h-[300px] md:h-[500px] lg:h-[600px]">
|
|
<Image src={post.coverImage || "/placeholder.svg"} alt={post.title} fill className="object-cover" priority />
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<article className="container px-4 md:px-6 mx-auto py-12 md:py-24">
|
|
<div className="prose prose-purple dark:prose-invert max-w-3xl mx-auto">
|
|
<MDXRemote
|
|
source={post.content}
|
|
options={{
|
|
mdxOptions: {
|
|
rehypePlugins: [rehypePrism],
|
|
},
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2 max-w-3xl mx-auto mt-12">
|
|
{post.tags.map((tag, index) => (
|
|
<Badge
|
|
key={index}
|
|
variant="secondary"
|
|
className="bg-primary-100 text-primary-900 dark:bg-primary-900 dark:text-primary-100"
|
|
>
|
|
{tag}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
|
|
<div className="max-w-3xl mx-auto mt-12 pt-12 border-t border-gray-200 dark:border-gray-800">
|
|
<div className="flex flex-col gap-6">
|
|
<div className="flex flex-col md:flex-row items-center justify-between gap-6">
|
|
<div className="flex items-center gap-4">
|
|
<Avatar className="h-16 w-16">
|
|
<AvatarImage src={post.author.avatar || "/placeholder.svg"} alt={post.author.name} />
|
|
<AvatarFallback>
|
|
{post.author.name
|
|
.split(" ")
|
|
.map((n) => n[0])
|
|
.join("")}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
<div>
|
|
<p className="text-lg font-medium text-primary-900 dark:text-primary-300">{post.author.name}</p>
|
|
<p className="text-gray-500 dark:text-gray-400">{post.author.title}</p>
|
|
</div>
|
|
</div>
|
|
<Link href="/blog">
|
|
<Button
|
|
variant="outline"
|
|
className="border-primary-200 text-primary-900 dark:border-primary-800 dark:text-primary-300"
|
|
>
|
|
<ArrowLeft />
|
|
Blog
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
<p>
|
|
{post.author.description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</main>
|
|
|
|
<Footer />
|
|
</div>
|
|
)
|
|
}
|