mirror of
https://github.com/Dokploy/website
synced 2025-06-26 18:16:01 +00:00
refactor: extract BlogPostCard component and improve image handling
This commit is contained in:
parent
99a1cdb651
commit
b797f6b9b3
@ -16,22 +16,25 @@ export function BlogPostCard({ post, locale }: BlogPostCardProps) {
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
const handleTwitterClick = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
className="group block hover:bg-muted p-4 rounded-lg"
|
||||
>
|
||||
<article className="flex gap-6 items-start">
|
||||
{post.feature_image && (
|
||||
<div className="relative h-32 w-48 shrink-0">
|
||||
<Image
|
||||
src={post.feature_image}
|
||||
alt={post.title}
|
||||
fill
|
||||
className="object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="relative h-32 w-48 shrink-0">
|
||||
<Image
|
||||
src={post.feature_image || "/default.jpg"}
|
||||
alt={post.feature_image ? post.title : "Default Image"}
|
||||
fill
|
||||
className="object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h2 className="text-xl font-semibold mb-2 group-hover:text-primary">
|
||||
{post.title}
|
||||
@ -49,6 +52,7 @@ export function BlogPostCard({ post, locale }: BlogPostCardProps) {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block cursor-pointer transition-opacity hover:opacity-90"
|
||||
onClick={handleTwitterClick}
|
||||
>
|
||||
<Image
|
||||
src={post.primary_author.profile_image}
|
||||
@ -73,6 +77,7 @@ export function BlogPostCard({ post, locale }: BlogPostCardProps) {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-primary transition-colors"
|
||||
onClick={handleTwitterClick}
|
||||
>
|
||||
{post.primary_author.name || "Unknown Author"}
|
||||
</a>
|
||||
|
@ -3,8 +3,8 @@ import type { Post } from "@/lib/ghost";
|
||||
import { RssIcon } from "lucide-react";
|
||||
import type { Metadata } from "next";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { BlogPostCard } from "./components/BlogPostCard";
|
||||
import { SearchAndFilter } from "./components/SearchAndFilter";
|
||||
|
||||
interface Tag {
|
||||
@ -18,8 +18,6 @@ export const metadata: Metadata = {
|
||||
description: "Latest news, updates, and articles from Dokploy",
|
||||
};
|
||||
|
||||
export const revalidate = 3600; // Revalidate the data at most every hour
|
||||
|
||||
export default async function BlogPage({
|
||||
params: { locale },
|
||||
searchParams,
|
||||
@ -88,96 +86,3 @@ export default async function BlogPage({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BlogPostCard({ post, locale }: { post: Post; locale: string }) {
|
||||
const formattedDate = new Date(post.published_at).toLocaleDateString(locale, {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
className="group block hover:bg-muted p-4 rounded-lg"
|
||||
>
|
||||
<article className="flex gap-6 items-start">
|
||||
{post.feature_image ? (
|
||||
<div className="relative h-32 w-48 shrink-0">
|
||||
<Image
|
||||
src={post.feature_image}
|
||||
alt={post.title}
|
||||
fill
|
||||
className="object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative h-32 w-48 shrink-0">
|
||||
<Image
|
||||
src={"/default.jpg"}
|
||||
alt="Default Image"
|
||||
fill
|
||||
className="object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h2 className="text-xl font-semibold mb-2 group-hover:text-primary">
|
||||
{post.title}
|
||||
</h2>
|
||||
<p className="text-muted-foreground line-clamp-2 mb-4">
|
||||
{post.custom_excerpt || post.excerpt}
|
||||
</p>
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<div className="flex items-center">
|
||||
{post.primary_author?.profile_image && (
|
||||
<div className="relative h-6 w-6 rounded-full overflow-hidden mr-2">
|
||||
{post.primary_author.twitter ? (
|
||||
<a
|
||||
href={`https://twitter.com/${post.primary_author.twitter}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block cursor-pointer transition-opacity hover:opacity-90"
|
||||
>
|
||||
<Image
|
||||
src={post.primary_author.profile_image}
|
||||
alt={post.primary_author.name}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<Image
|
||||
src={post.primary_author.profile_image}
|
||||
alt={post.primary_author.name}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{post.primary_author?.twitter ? (
|
||||
<a
|
||||
href={`https://twitter.com/${post.primary_author.twitter}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-primary transition-colors"
|
||||
>
|
||||
{post.primary_author.name || "Unknown Author"}
|
||||
</a>
|
||||
) : (
|
||||
<span>{post.primary_author?.name || "Unknown Author"}</span>
|
||||
)}
|
||||
</div>
|
||||
<span className="mx-2">in</span>
|
||||
<span>{post.primary_tag?.name || "General"}</span>
|
||||
<span className="mx-2">•</span>
|
||||
<span>{post.reading_time} min read</span>
|
||||
<span className="mx-2">•</span>
|
||||
<span>{formattedDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user