In response to the changes made to the directory structure of the project, the code has been refactored to adjust image import paths across various sections. It also involves reorganizing components into appropriate folders based on their roles in the application. Along with this, a new utility file for navigation links has been introduced, and configurations for authorizing remote images have been added to Astro configuration file, suggesting an enhancement in SEO performance.
126 lines
4.9 KiB
Text
126 lines
4.9 KiB
Text
---
|
|
// Import necessary components and utilities
|
|
import MainLayout from "../../layouts/MainLayout.astro";
|
|
import AvatarBlogLarge from "../../components/ui/avatars/AvatarBlogLarge.astro";
|
|
import CardRelated from "../../components/ui/cards/CardRelated.astro";
|
|
import { Image } from "astro:assets";
|
|
import { capitalize, formatDate } from "../../utils/utils";
|
|
import { getCollection } from "astro:content";
|
|
import type { CollectionEntry } from "astro:content";
|
|
|
|
// getStaticPaths is used to pre-render all routes based on the blog posts
|
|
export async function getStaticPaths() {
|
|
const blogPosts = await getCollection("blog");
|
|
return blogPosts.map((post) => ({
|
|
params: { slug: post.slug },
|
|
props: { post },
|
|
}));
|
|
}
|
|
// Get the current post's data
|
|
const { post } = Astro.props;
|
|
|
|
// Get all blog posts
|
|
const blogPosts: CollectionEntry<"blog">[] = await getCollection("blog");
|
|
|
|
// Filter out the current post to get related posts
|
|
// Note: This is a very basic way of choosing related posts, just for the purpose of the example.
|
|
// In a production site, you might want to implement a more robust algorithm, choosing related posts based on tags, categories, dates, authors, or keywords.
|
|
const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter(
|
|
(blogEntry) => blogEntry.slug !== post.slug,
|
|
);
|
|
---
|
|
|
|
<MainLayout title={post.data.title + " | ScrewFast"}>
|
|
<section class="mx-auto max-w-3xl px-4 pb-12 pt-6 sm:px-6 lg:px-8 lg:pt-10">
|
|
<div class="max-w-2xl">
|
|
<div class="mb-6 flex items-center justify-between">
|
|
<div class="flex w-full gap-x-5 sm:items-center sm:gap-x-3">
|
|
<AvatarBlogLarge blogEntry={post} />
|
|
<div class="grow">
|
|
<div class="flex items-center justify-between gap-x-2">
|
|
<div>
|
|
<div
|
|
class="hs-tooltip inline-block [--placement:bottom] [--trigger:hover]"
|
|
>
|
|
<!--Post metadata and author info-->
|
|
<span
|
|
class="font-bold text-neutral-700 dark:text-neutral-300"
|
|
>
|
|
{post.data.author}
|
|
</span>
|
|
</div>
|
|
<ul class="text-xs text-neutral-500">
|
|
<li
|
|
class="relative inline-block pe-6 before:absolute before:end-2 before:top-1/2 before:size-1 before:-translate-y-1/2 before:rounded-full before:bg-neutral-300 last:pe-0 last-of-type:before:hidden dark:text-neutral-400 dark:before:bg-neutral-600"
|
|
>
|
|
{formatDate(post.data.pubDate)}
|
|
</li>
|
|
<li
|
|
class="relative inline-block pe-6 before:absolute before:end-2 before:top-1/2 before:size-1 before:-translate-y-1/2 before:rounded-full before:bg-neutral-300 last:pe-0 last-of-type:before:hidden dark:text-neutral-400 dark:before:bg-neutral-600"
|
|
>
|
|
{post.data.readTime} min read
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!--Blog post title-->
|
|
<h2
|
|
class="mb-3 text-2xl font-bold text-neutral-800 dark:text-neutral-200 md:text-3xl"
|
|
>
|
|
{post.data.title}
|
|
</h2>
|
|
<!--Blog post contents-->
|
|
<div class="mb-5 space-y-5 md:mb-8 md:space-y-8">
|
|
{
|
|
post.data.contents.map((content: string, index: any) =>
|
|
index === 1 ? (
|
|
<>
|
|
<p class="text-pretty text-lg text-neutral-700 dark:text-neutral-300">
|
|
{content}
|
|
</p>
|
|
<Image
|
|
class="w-full rounded-xl object-cover"
|
|
src={post.data.cardImage}
|
|
alt={post.data.cardImageAlt}
|
|
draggable={"false"}
|
|
format={"avif"}
|
|
/>
|
|
</>
|
|
) : (
|
|
<p class="text-pretty text-lg text-neutral-700 dark:text-neutral-300">
|
|
{content}
|
|
</p>
|
|
),
|
|
)
|
|
}
|
|
</div>
|
|
<!--Blog post tags-->
|
|
<div class="space-x-2">
|
|
{
|
|
post.data.tags?.map((tag: string) => (
|
|
<span class="inline-flex items-center gap-x-1.5 rounded-lg bg-neutral-400/30 px-3 py-1.5 text-xs font-medium text-neutral-700 outline-none focus:outline-none focus-visible:outline-none focus-visible:ring dark:bg-neutral-700/60 dark:text-neutral-300">
|
|
{capitalize(tag)}
|
|
</span>
|
|
))
|
|
}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<!--Related articles section-->
|
|
<section class="mx-auto max-w-3xl px-4 py-10 sm:px-6 lg:px-8 lg:py-14">
|
|
<div class="mb-10 max-w-2xl">
|
|
<h2
|
|
class="text-balance text-2xl font-bold text-neutral-800 dark:text-neutral-200 md:text-4xl md:leading-tight"
|
|
>
|
|
Related articles
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-6">
|
|
{relatedPosts.map((entry) => <CardRelated blogEntry={entry} />)}
|
|
</div>
|
|
</section>
|
|
</MainLayout>
|