وبلاگ: دکمه «نوشتن مقاله جدید» بالای صفحه + ویرایشگر متن در ابتدای کشو

- دکمه پررنگ «نوشتن مقاله جدید» بالای صفحه وبلاگ (فقط در حالت ویرایش) —
  ساخت مقاله جدید و باز شدن مستقیم کشوی نوشتن
- ترتیب فیلدهای کشوی مقاله: عنوان، سپس ویرایشگر WYSIWYG — نوشتن اول،
  متادیتا (دسته/تاریخ/اسلاگ و...) بعد
- رفع باگ: ساخت رکورد قبلاً کل درخت را reload می‌کرد و کشوی
  تازه‌ساخته‌شده بی‌درنگ بسته می‌شد؛ حالا آیتم ساخته‌شده به‌صورت
  خوش‌بینانه به لیست اضافه می‌شود و کشو باز می‌ماند
This commit is contained in:
MMD
2026-09-07 02:09:17 +03:30
parent 70cf9616c1
commit 2c96562b66
3 changed files with 47 additions and 9 deletions
+37 -6
View File
@@ -3,6 +3,7 @@ import type { ReactNode } from 'react'
import { ArrowDownIcon, ArrowUpIcon, PencilIcon, PlusIcon, Trash2Icon } from 'lucide-react' import { ArrowDownIcon, ArrowUpIcon, PencilIcon, PlusIcon, Trash2Icon } from 'lucide-react'
import Swal from 'sweetalert2' import Swal from 'sweetalert2'
import { useSiteData } from '../api' import { useSiteData } from '../api'
import type { SiteData } from '../api'
import { useAdmin } from './AdminContext' import { useAdmin } from './AdminContext'
import { adminApi } from './adminClient' import { adminApi } from './adminClient'
import { ENTITIES } from './entities' import { ENTITIES } from './entities'
@@ -142,9 +143,17 @@ export function EditableItem({
} }
/** دکمه افزودن آیتم جدید به یک مجموعه — فقط در حالت ویرایش */ /** دکمه افزودن آیتم جدید به یک مجموعه — فقط در حالت ویرایش */
export function AddItemButton({ resource }: { resource: string }) { export function AddItemButton({
resource,
label,
variant = 'cell',
}: {
resource: string
label?: string
variant?: 'cell' | 'button'
}) {
const { isAuthenticated, isEditMode, runSave } = useAdmin() const { isAuthenticated, isEditMode, runSave } = useAdmin()
const { reload } = useSiteData() const { updateSite } = useSiteData()
const config = ENTITIES[resource] const config = ENTITIES[resource]
const [newItem, setNewItem] = useState<ItemWithId | null>(null) const [newItem, setNewItem] = useState<ItemWithId | null>(null)
@@ -153,11 +162,35 @@ export function AddItemButton({ resource }: { resource: string }) {
const create = () => { const create = () => {
void runSave(async () => { void runSave(async () => {
const created = await adminApi.create<ItemWithId>(config.resource, config.defaults) const created = await adminApi.create<ItemWithId>(config.resource, config.defaults)
reload() // درج خوش‌بینانه — reload کل درخت را بازسازی می‌کند و کشوی تازه‌ساخته‌شده می‌میرد
updateSite((d) => {
const list = d[config.dataKey as keyof SiteData] as unknown as ItemWithId[]
if (Array.isArray(list)) list.push(created)
})
setNewItem(created) setNewItem(created)
}) })
} }
const drawer = newItem ? (
<EntityDrawer config={config} item={newItem} deletable onClose={() => setNewItem(null)} />
) : null
if (variant === 'button') {
return (
<>
<button
type="button"
onClick={create}
className="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" />
{label ?? `افزودن ${config.title}`}
</button>
{drawer}
</>
)
}
return ( return (
<> <>
<button <button
@@ -169,9 +202,7 @@ export function AddItemButton({ resource }: { resource: string }) {
<span className="text-sm font-light">افزودن {config.title}</span> <span className="text-sm font-light">افزودن {config.title}</span>
</button> </button>
{newItem && ( {drawer}
<EntityDrawer config={config} item={newItem} deletable onClose={() => setNewItem(null)} />
)}
</> </>
) )
} }
+7 -2
View File
@@ -55,9 +55,14 @@ export const ENTITIES: Record<string, EntityConfig> = {
resource: 'articles', dataKey: 'articles', title: 'مقالات', kind: 'collection', resource: 'articles', dataKey: 'articles', title: 'مقالات', kind: 'collection',
titleKey: 'title', titleKey: 'title',
fields: [ fields: [
F('title', 'عنوان'), F('slug', 'نشانی (slug)'), F('date', 'تاریخ'), F('category', 'دسته'), F('title', 'عنوان'),
F('image', 'تصویر شاخص', 'image'), F('read', 'زمان مطالعه'), F('excerpt', 'چکیده', 'textarea'),
F('body', 'متن مقاله', 'wysiwyg'), F('body', 'متن مقاله', 'wysiwyg'),
F('excerpt', 'چکیده', 'textarea'),
F('image', 'تصویر شاخص', 'image'),
F('category', 'دسته'),
F('date', 'تاریخ'),
F('read', 'زمان مطالعه'),
F('slug', 'نشانی (slug)'),
], ],
defaults: { title: 'مقاله جدید', slug: `article-${Date.now()}`, date: '', category: '', image: '', read: '', excerpt: '', body: { type: 'doc', content: [{ type: 'paragraph' }] } }, defaults: { title: 'مقاله جدید', slug: `article-${Date.now()}`, date: '', category: '', image: '', read: '', excerpt: '', body: { type: 'doc', content: [{ type: 'paragraph' }] } },
}, },
+3 -1
View File
@@ -18,6 +18,9 @@ export function Blog() {
<section className="bg-ink py-24 lg:py-32" aria-label="مقالات"> <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="mx-auto max-w-site px-6 lg:px-10">
<div className="mb-10 flex justify-start">
<AddItemButton resource="articles" label="نوشتن مقاله جدید" variant="button" />
</div>
<Reveal> <Reveal>
<EditableItem resource="articles" item={featured}> <EditableItem resource="articles" item={featured}>
<Link <Link
@@ -64,7 +67,6 @@ export function Blog() {
</EditableItem> </EditableItem>
</Reveal> </Reveal>
))} ))}
<AddItemButton resource="articles" />
</div> </div>
</div> </div>
</section> </section>