فرانتاند: ویرایش زنده درجا — دوقلوی دیجیتال سایت برای ادمین
لایه ویرایش بصری روی سایت واقعی (بدون داشبورد جدا): - ورود ادمین از مسیر پنهان /admin/login با توکن JWT (localStorage) و AdminContext شامل isEditMode و وضعیت ذخیره (همگام/در حال ذخیره/خطا) - AdminBar شناور پایین صفحه (فقط برای کاربر واردشده): کلید حالت ویرایش، وضعیت ذخیره، خروج — حالت ویرایش در sessionStorage میماند - InlineEdit: در حالت عادی دقیقاً همان HTML قبلی (بدون تغییر چیدمان)؛ در حالت ویرایش کادرخطچین + contentEditable با ذخیره خودکار در blur (Enter ذخیره، Esc لغو) — وایرایششده روی همه متنهای سایت: هیرو، تیتر بخشها، هیرو صفحات، داستان، فرم تماس، خبرنامه، فوتر، منو، برچسبهای وضعیت پروژه و... - کشوی عمومی EntityDrawer با پیکربندی متمرکز برای ۱۴ مجموعه (خدمات، پروژهها، مقالات، نظرات، سوالات، تیم، تایملاین، آمار، چرا آرامش، مدلهای سرمایهگذاری، مراحل کار، دفاتر، گالری، منو): ویرایش چندفیلدی، افزودن، حذف و جابهجایی ترتیب (▲▼) با ذخیره خودکار هر فیلد - دکمههای شناور ویرایش/حذف/ترتیب فقط در حالت ویرایش روی آیتمها - کشوهای یگانه: برند و لوگو، تنظیمات هیرو، فرم تماس، خبرنامه، فوتر، قبل/بعد و نقلقول داستان — آپلود تصویر به MinIO از همانجا - بهروزرسانی خوشبینانه SiteContext (updateSite) پس از هر PATCH؛ مسیرها در حالت ویرایش کلیک نمیشوند؛ breadcrumb محافظ beforeunload
This commit is contained in:
@@ -5,20 +5,21 @@ import { PageHero } from '../components/PageHero'
|
||||
import { Reveal } from '../components/Reveal'
|
||||
import { ArticleCard } from '../components/ArticleCard'
|
||||
import { Newsletter } from '../components/home/Newsletter'
|
||||
import { usePageHero, useSite } from '../api'
|
||||
import { useSite } from '../api'
|
||||
import { AddItemButton, EditableItem } from '../admin/Editable'
|
||||
|
||||
export function Blog() {
|
||||
const { articles } = useSite()
|
||||
const hero = usePageHero('blog')
|
||||
const [featured, ...rest] = articles
|
||||
const [featured, ...rest] = articles
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHero title={hero.title} lead={hero.lead} image={hero.image} />
|
||||
<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">
|
||||
<Reveal>
|
||||
<EditableItem resource="articles" item={featured}>
|
||||
<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"
|
||||
@@ -52,14 +53,18 @@ export function Blog() {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</EditableItem>
|
||||
</Reveal>
|
||||
|
||||
<div className="mt-12 grid gap-6 lg:grid-cols-3">
|
||||
{rest.map((article, i) => (
|
||||
<Reveal key={article.slug} delay={0.05 * i} className="h-full">
|
||||
<ArticleCard article={article} />
|
||||
<Reveal key={article.id} delay={0.05 * i} className="h-full">
|
||||
<EditableItem resource="articles" item={article} className="h-full">
|
||||
<ArticleCard article={article} />
|
||||
</EditableItem>
|
||||
</Reveal>
|
||||
))}
|
||||
<AddItemButton resource="articles" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user