سئو: بررسی سئو در صفحه نوشتن + عنوان و توضیح متای هر صفحه
- پنل «بررسی سئو» در صفحه نوشتن مقاله — سبز/نارنجی/قرمز سازگار با فارسی: طول عنوان، کلمه کلیدی هدف (در عنوان/پاراگراف اول/تیتر H2)، طول چکیده، تعداد واژه، تیتربندی، متن جایگزین تصاویر، پیوندها و slug. کلمه کلیدی در localStorage نگه داشته میشود (راهنمای ویرایشگر است، نه محتوا) - جدول seo_meta: عنوان و توضیح متای هر صفحه (page_key برای هر ۸ صفحه، seed خودکار، CRUD در /api/admin/seo-meta، خواندن در GET /api/site) - تزریق عنوان/توضیح متا در فرانتاند: صفحههای فهرست از دیتابیس؛ صفحه مقاله و پروژه از محتوای خودشان (بدون تداخل با اثر سطح والد) - دکمه سئو روی هیرو هر صفحه و کنار هیرو صفحه اصلی (فقط حالت ویرایش)
This commit is contained in:
@@ -6,6 +6,7 @@ import { useSiteData } from '../api'
|
||||
import { useAdmin } from './AdminContext'
|
||||
import { adminApi } from './adminClient'
|
||||
import { ArticleEditor } from '../components/admin/ArticleEditor'
|
||||
import { SeoChecklist } from '../components/admin/SeoChecklist'
|
||||
import { ImageField } from '../components/admin/ImageField'
|
||||
import type { ArticleBodyDoc } from '../data/site'
|
||||
|
||||
@@ -61,6 +62,12 @@ export function ArticleWritePage() {
|
||||
)
|
||||
const [createdId, setCreatedId] = useState<number | null>(existing?.id ?? null)
|
||||
const [deleting, setDeleting] = useState(false)
|
||||
// کلمه کلیدی هدف فقط راهنمای سئو است — در localStorage میماند، نه در دیتابیس
|
||||
const [keyphrase, setKeyphrase] = useState(() => localStorage.getItem(`seo-keyphrase-${id ?? 'new'}`) ?? '')
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem(`seo-keyphrase-${id ?? 'new'}`, keyphrase)
|
||||
}, [keyphrase, id])
|
||||
|
||||
const draftRef = useRef(draft)
|
||||
draftRef.current = draft
|
||||
@@ -247,9 +254,29 @@ export function ArticleWritePage() {
|
||||
</div>
|
||||
|
||||
{/* چکیده و متادیتا */}
|
||||
<SeoChecklist
|
||||
input={{
|
||||
title: draft.title,
|
||||
slug: draft.slug,
|
||||
excerpt: draft.excerpt,
|
||||
body: draft.body,
|
||||
keyphrase,
|
||||
}}
|
||||
/>
|
||||
|
||||
<section className="mt-12 border-t border-ivory/10 pt-8" aria-label="جزئیات مقاله">
|
||||
<h2 className="text-sm font-bold text-copper">جزئیات انتشار</h2>
|
||||
<div className="mt-5 grid gap-5">
|
||||
<div>
|
||||
<label htmlFor="seo-keyphrase" className="text-xs font-light text-ivory/50">کلمه کلیدی هدف (فقط برای راهنمای سئو — در سایت نمایش داده نمیشود)</label>
|
||||
<input
|
||||
id="seo-keyphrase"
|
||||
type="text"
|
||||
value={keyphrase}
|
||||
onChange={(e) => setKeyphrase(e.target.value)}
|
||||
className="mt-2 w-full border border-ivory/15 bg-char px-3 py-2 text-sm font-light text-ivory focus:border-copper focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-light text-ivory/50">چکیده (روی کارت مقاله نمایش داده میشود)</label>
|
||||
<textarea
|
||||
|
||||
Reference in New Issue
Block a user