131 lines
5.4 KiB
TypeScript
131 lines
5.4 KiB
TypeScript
import React from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
import { ArrowLeftIcon, ClockIcon } from 'lucide-react'
|
|
import { PageHero } from '../components/PageHero'
|
|
import { Reveal } from '../components/Reveal'
|
|
import { ArticleCard } from '../components/ArticleCard'
|
|
import { Newsletter } from '../components/home/Newsletter'
|
|
import { useSite } from '../api'
|
|
import { EditableItem } from '../admin/Editable'
|
|
import { useAdmin } from '../admin/AdminContext'
|
|
import { PlusIcon } from 'lucide-react'
|
|
|
|
function DraftBadge({ className = '' }: { className?: string }) {
|
|
return (
|
|
<span
|
|
className={`border border-amber-400/60 bg-ink/90 px-2 py-1 text-xs font-bold text-amber-300 ${className}`}
|
|
>
|
|
پیشنویس
|
|
</span>
|
|
)
|
|
}
|
|
|
|
export function Blog() {
|
|
const { articles } = useSite()
|
|
const { isEditMode } = useAdmin()
|
|
|
|
// دکمه «نوشتن مقاله جدید» فقط در حالت ویرایش ادمین دیده میشود
|
|
const writeButton = isEditMode ? (
|
|
<Link
|
|
to="/admin/write"
|
|
data-admin-link
|
|
className="inline-flex items-center gap-2 bg-copper px-6 py-3 text-sm font-bold text-char transition-transform duration-200 hover:scale-105"
|
|
>
|
|
<PlusIcon className="h-4 w-4" />
|
|
نوشتن مقاله جدید
|
|
</Link>
|
|
) : null
|
|
|
|
// حالت خالی — وبلاگ بدون مقاله نباید کرش کند
|
|
if (articles.length === 0) {
|
|
return (
|
|
<>
|
|
<PageHero pageKey="blog" />
|
|
<section className="bg-ink py-24 lg:py-32" aria-label="مقالات">
|
|
<div className="mx-auto max-w-site px-6 text-center lg:px-10">
|
|
<h2 className="text-3xl font-bold text-ivory">هنوز مقالهای منتشر نشده است</h2>
|
|
<p className="mt-4 text-sm font-light text-ivory/60">
|
|
بهزودی نخستین نوشتههای ما اینجا منتشر میشود.
|
|
</p>
|
|
<div className="mt-8 flex justify-center">{writeButton}</div>
|
|
</div>
|
|
</section>
|
|
<Newsletter />
|
|
</>
|
|
)
|
|
}
|
|
|
|
const [featured, ...rest] = articles
|
|
|
|
return (
|
|
<>
|
|
<PageHero pageKey="blog" />
|
|
|
|
<section className="bg-ink py-24 lg:py-32" aria-label="مقالات">
|
|
<div className="mx-auto max-w-site px-6 lg:px-10">
|
|
<div className="mb-10 flex justify-start">{writeButton}</div>
|
|
<Reveal>
|
|
<EditableItem resource="articles" item={featured} editHref={`/admin/write/${featured.id}`}>
|
|
<Link
|
|
to={`/blog/${featured.slug}`}
|
|
className="group grid items-stretch border border-ivory/10 bg-char transition-[transform,box-shadow,border-color] duration-300 ease-lux hover:-translate-y-2 hover:border-copper/50 hover:shadow-lift lg:grid-cols-2"
|
|
aria-label={`خواندن مقاله ${featured.title}`}
|
|
>
|
|
<div className="overflow-hidden">
|
|
<img
|
|
src={featured.image}
|
|
alt={`تصویر مقاله ${featured.title}`}
|
|
className="h-full min-h-[20rem] w-full object-cover transition-transform duration-500 ease-lux group-hover:scale-105"
|
|
/>
|
|
</div>
|
|
<div className="flex flex-col justify-center p-8 lg:p-12">
|
|
<p className="text-xs font-light text-copper">
|
|
مقاله ویژه — {featured.category}
|
|
{featured.status === 'draft' && (
|
|
<DraftBadge className="mr-3 inline-block align-middle" />
|
|
)}
|
|
</p>
|
|
<h2 className="mt-6 text-2xl font-bold leading-[2.2] md:leading-[2.2] text-ivory transition-colors duration-200 ease-lux group-hover:text-copper md:text-3xl">
|
|
{featured.title}
|
|
</h2>
|
|
<p className="mt-6 text-sm font-light leading-10 text-ivory/65">{featured.excerpt}</p>
|
|
<div className="mt-10 flex items-center justify-between border-t border-ivory/10 pt-8 text-xs font-light text-ivory/50">
|
|
<span className="flex items-center gap-4">
|
|
<span>{featured.date}</span>
|
|
<span className="flex items-center gap-1.5">
|
|
<ClockIcon className="h-3.5 w-3.5" />
|
|
{featured.read}
|
|
</span>
|
|
</span>
|
|
<span className="flex items-center gap-2 text-copper">
|
|
ادامه مطلب
|
|
<ArrowLeftIcon className="h-3.5 w-3.5 transition-transform duration-200 ease-lux group-hover:-translate-x-1" />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</EditableItem>
|
|
</Reveal>
|
|
|
|
<div className="mt-12 grid gap-6 lg:grid-cols-3">
|
|
{rest.map((article, i) => (
|
|
<Reveal key={article.id} delay={0.05 * i} className="h-full">
|
|
<EditableItem resource="articles" item={article} className="h-full" editHref={`/admin/write/${article.id}`}>
|
|
<div className="relative h-full">
|
|
{article.status === 'draft' && (
|
|
<DraftBadge className="absolute left-3 top-3 z-10" />
|
|
)}
|
|
<ArticleCard article={article} />
|
|
</div>
|
|
</EditableItem>
|
|
</Reveal>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<Newsletter />
|
|
</>
|
|
)
|
|
}
|