trptk/components/blog/BlogCard.tsx
2026-02-24 17:14:07 +01:00

69 lines
2.2 KiB
TypeScript

import Link from "next/link";
import Image from "next/image";
import { urlFor } from "@/lib/sanityImage";
import type { SanityImageSource } from "@sanity/image-url";
export type BlogCardData = {
_id?: string;
title?: string;
subtitle?: string;
slug?: string;
author?: string;
publishDate?: string;
category?: string;
featuredImage?: SanityImageSource;
};
type Props = {
blog: BlogCardData;
className?: string;
};
function formatPublishDate(dateString?: string) {
if (!dateString) return null;
return new Intl.DateTimeFormat("en-US", {
month: "short",
day: "numeric",
year: "numeric",
}).format(new Date(dateString));
}
export function BlogCard({ blog, className = "" }: Props) {
const url = blog.slug ? `/blog/${blog.slug}` : "#";
const imageSrc = blog.featuredImage ? urlFor(blog.featuredImage).url() : null;
return (
<Link
href={url}
className={`group transition-color relative z-10 rounded-xl bg-lightbg shadow-lg ring-1 ring-lightline duration-300 ease-in-out hover:text-trptkblue hover:ring-lightline-hover dark:bg-darkbg dark:ring-darkline dark:hover:text-white dark:hover:ring-darkline-hover ${className}`}
>
<div className="relative aspect-square w-full overflow-hidden rounded-xl">
{imageSrc ? (
<Image
src={imageSrc}
alt={blog.title ? `Featured image for ${blog.title}` : "Blog post image"}
fill
className="object-cover"
sizes="(max-width: 560px) calc(100vw - 32px), 450px"
/>
) : (
<div className="absolute inset-0 bg-lightline-mid dark:bg-darkline-mid" />
)}
</div>
<div className="p-4 sm:p-5 sm:pb-15">
<div className="">
<h3 className="mb-2 break-words">{blog.title}</h3>
<h4 className="text-sm break-words text-lightsec dark:text-darksec">
{blog.subtitle || blog.category}
</h4>
</div>
</div>
<div className="absolute right-4 bottom-4 left-4 hidden text-lightsec opacity-50 sm:right-5 sm:bottom-5 sm:left-5 sm:flex dark:text-darksec">
<span className="text-sm">{formatPublishDate(blog.publishDate)}</span>
</div>
</Link>
);
}