mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 02:53:51 +00:00
migrate to vercel; bump version
This commit is contained in:
104
src/pages/blog/[...slug].astro
Normal file
104
src/pages/blog/[...slug].astro
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
import { getCollection, render } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import ContentLayout from "@/layouts/content.astro";
|
||||
import { getArticleSchema } from "@/lib/structuredData";
|
||||
import { blogWebsite } from "@/lib/structuredData";
|
||||
import { Comments } from "@/components/blog/comments";
|
||||
|
||||
// This is a dynamic route in SSR mode
|
||||
const { slug } = Astro.params;
|
||||
|
||||
// Fetch blog posts
|
||||
const posts = await getCollection("blog");
|
||||
const post = posts.find(post => post.id === slug);
|
||||
|
||||
if (!post || (!import.meta.env.DEV && post.data.isDraft === true)) {
|
||||
return new Response(null, {
|
||||
status: 404,
|
||||
statusText: "Not found"
|
||||
});
|
||||
}
|
||||
|
||||
// Dynamically render the content
|
||||
const { Content } = await render(post);
|
||||
|
||||
// Format the date
|
||||
const formattedDate = new Date(post.data.date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric"
|
||||
});
|
||||
|
||||
const articleStructuredData = getArticleSchema(post);
|
||||
|
||||
const breadcrumbsStructuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Blog",
|
||||
item: `${import.meta.env.SITE}/blog/`,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: post.data.title,
|
||||
item: `${import.meta.env.SITE}/blog/${post.id}/`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [articleStructuredData, breadcrumbsStructuredData, blogWebsite],
|
||||
};
|
||||
---
|
||||
|
||||
<ContentLayout
|
||||
title={`${post.data.title} | Timothy Pidashev`}
|
||||
description={post.data.description}
|
||||
>
|
||||
<script type="application/ld+json" set:html={JSON.stringify(jsonLd)} />
|
||||
<div class="relative max-w-8xl mx-auto">
|
||||
<article class="prose prose-invert prose-lg mx-auto max-w-4xl">
|
||||
{post.data.image && (
|
||||
<div class="-mx-4 sm:mx-0 mb-4">
|
||||
<Image
|
||||
src={post.data.image}
|
||||
alt={post.data.title}
|
||||
class="w-full h-auto rounded-lg object-cover"
|
||||
width={1200}
|
||||
height={630}
|
||||
quality={100}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<h1 class="text-3xl !mt-2 !mb-2">{post.data.title}</h1>
|
||||
<p class="lg:text-2xl sm:text-lg !mt-0 !mb-3">{post.data.description}</p>
|
||||
<div class="flex flex-wrap items-center gap-2 md:gap-3 text-sm md:text-base text-foreground/80">
|
||||
<span class="text-orange">{post.data.author}</span>
|
||||
<span class="text-foreground/50">•</span>
|
||||
<time dateTime={post.data.date instanceof Date ? post.data.date.toISOString() : post.data.date} class="text-blue">
|
||||
{formattedDate}
|
||||
</time>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-2">
|
||||
{post.data.tags.map((tag) => (
|
||||
<span
|
||||
class="text-xs md:text-base text-aqua hover:text-aqua-bright transition-colors duration-200"
|
||||
onclick={`window.location.href='/blog/tag/${tag}'`}
|
||||
>
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div class="prose prose-invert prose-lg max-w-none">
|
||||
<Content />
|
||||
</div>
|
||||
</article>
|
||||
<Comments client:idle />
|
||||
</div>
|
||||
</ContentLayout>
|
||||
Reference in New Issue
Block a user