feat(blog): redesign post list cards
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import BlogThumbnail from "@/components/BlogThumbnail";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Link, useLocation, useNavigate } from "@/lib/router";
|
||||
import { api } from "@/lib/api";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import type * as Types from "@/lib/types";
|
||||
import { blogPostPath } from "@/lib/blog-routes";
|
||||
import { apiBaseUrl, toAbsoluteUrl } from "@/lib/site";
|
||||
import type * as Types from "@/lib/types";
|
||||
import { formatJalaliDate, getBlogCardImageUrl } from "@/lib/utils";
|
||||
|
||||
type BlogProps = {
|
||||
initialPosts?: Types.PostListSchema[];
|
||||
@@ -60,59 +62,55 @@ export default function Blog({
|
||||
}, [location.pathname, navigate, search]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<h1 className="text-4xl font-bold mb-8">وبلاگ</h1>
|
||||
|
||||
<div className="mb-8">
|
||||
<div className="min-h-screen bg-[linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.32))]" dir="rtl">
|
||||
<div className="container mx-auto px-4 py-10">
|
||||
<div className="mb-8 flex flex-col gap-5 md:flex-row md:items-end md:justify-between">
|
||||
<div className="text-right">
|
||||
<p className="mb-2 text-sm font-medium text-primary">خواندنیهای انجمن</p>
|
||||
<h1 className="text-4xl font-black tracking-tight">بلاگ</h1>
|
||||
<p className="mt-3 max-w-2xl text-sm leading-7 text-muted-foreground">
|
||||
نوشتههای آموزشی، تجربههای دانشجویی و یادداشتهای تخصصی اعضای انجمن علمی.
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="جستجو در مقالات..."
|
||||
placeholder="جستجو در نوشتهها..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
className="max-w-md"
|
||||
onChange={(event) => setSearch(event.target.value)}
|
||||
className="max-w-md rounded-full bg-background/80 text-right shadow-sm backdrop-blur"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<p className="text-center text-muted-foreground">در حال بارگذاری...</p>
|
||||
) : posts.length === 0 ? (
|
||||
<p className="text-center text-muted-foreground">مقالهای یافت نشد</p>
|
||||
<p className="rounded-3xl border border-dashed bg-background/70 p-10 text-center text-muted-foreground">
|
||||
نوشتهای پیدا نشد.
|
||||
</p>
|
||||
) : (
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="grid gap-6 md:grid-cols-2 xl:grid-cols-3">
|
||||
{posts.map((post) => (
|
||||
<Link key={post.id} to={blogPostPath(post.slug)}>
|
||||
<Card className="h-full hover:shadow-lg transition-shadow">
|
||||
{(post.absolute_featured_image_thumbnail_url || post.absolute_featured_image_preview_url || post.absolute_featured_image_url || post.featured_image) ? (
|
||||
<div className="aspect-video overflow-hidden rounded-t-lg bg-muted">
|
||||
<img
|
||||
src={post.absolute_featured_image_thumbnail_url || post.absolute_featured_image_preview_url || post.absolute_featured_image_url || post.featured_image}
|
||||
alt={post.title}
|
||||
className="h-full w-full object-cover transition duration-300 group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<CardHeader>
|
||||
<CardTitle className="line-clamp-2">{post.title}</CardTitle>
|
||||
<CardDescription>
|
||||
{post.category?.name && (
|
||||
<span className="text-primary ml-2">{post.category.name}</span>
|
||||
)}
|
||||
{new Date(post.created_at).toLocaleDateString("fa-IR")}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{post.excerpt && (
|
||||
<p className="text-muted-foreground line-clamp-3 mb-4">
|
||||
{post.excerpt}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-sm">
|
||||
نویسنده: {post.author.first_name} {post.author.last_name}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Link
|
||||
key={post.id}
|
||||
to={blogPostPath(post.slug)}
|
||||
className="group overflow-hidden rounded-[2rem] border border-border/70 bg-card/85 shadow-sm transition duration-300 hover:-translate-y-1 hover:shadow-xl hover:shadow-primary/10"
|
||||
>
|
||||
<BlogThumbnail
|
||||
post={post}
|
||||
imageUrl={toAbsoluteUrl(getBlogCardImageUrl(post), apiBaseUrl)}
|
||||
className="aspect-[16/10] rounded-t-[2rem]"
|
||||
/>
|
||||
<article className="space-y-4 p-5 text-right">
|
||||
<h2 className="line-clamp-2 text-xl font-bold leading-9 transition group-hover:text-primary">
|
||||
{post.title}
|
||||
</h2>
|
||||
<p className="line-clamp-3 min-h-[5.25rem] text-sm leading-7 text-muted-foreground">
|
||||
{post.excerpt || post.seo_description || "خلاصهای برای این نوشته ثبت نشده است."}
|
||||
</p>
|
||||
<time className="block text-xs font-medium text-primary/80" dateTime={post.published_at || post.created_at}>
|
||||
{formatJalaliDate(post.published_at || post.created_at)}
|
||||
</time>
|
||||
</article>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user