feat(breadcrumb): implement BreadcrumbList structure and validation for SEO compliance
This commit is contained in:
+12
-22
@@ -1,41 +1,31 @@
|
||||
import Link from "next/link";
|
||||
import { safeJsonLd } from "@/lib/sanitize";
|
||||
import { buildBreadcrumbJsonLd, normalizeBreadcrumb } from "@/lib/breadcrumb";
|
||||
|
||||
// Breadcrumb واحد سایت: ظاهر دقیقاً همان نسخهٔ قبلی (همان کلاسها، همان جداکنندهٔ «>»)
|
||||
// ولی ساختار سمانتیک درست (nav/ol/a) و BreadcrumbList از همان یک منبع داده تولید میشود
|
||||
// تا نسخهٔ بصری و schema هرگز واگرا نشوند.
|
||||
//
|
||||
// list: Array<string | { name, href }> — آیتم آخر همیشه صفحهٔ جاری است (بدون لینک).
|
||||
// list: Array<string | { name, href }> — به آیتم آخر (صفحهٔ جاری) هم href بده؛
|
||||
// ظاهرش عوض نمیشود (هرگز لینک نمیشود) ولی schema بدون `item` نامعتبر است.
|
||||
// `origin` هم لازم است، چون گوگل URL مطلق میخواهد؛ بدون آن JSON-LD منتشر نمیشود.
|
||||
|
||||
const ITEM_CLASS = "text-[16px] font-normal";
|
||||
|
||||
function normalize(list) {
|
||||
return list
|
||||
.map((item) => (typeof item === "string" ? { name: item } : item))
|
||||
.filter((item) => item?.name);
|
||||
}
|
||||
|
||||
function Pageguide({ list = [], origin }) {
|
||||
const items = normalize(list);
|
||||
const items = normalizeBreadcrumb(list);
|
||||
if (items.length === 0) return null;
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: items.map((item, idx) => ({
|
||||
"@type": "ListItem",
|
||||
position: idx + 1,
|
||||
name: item.name,
|
||||
...(item.href && origin && { item: `${origin}${item.href}` }),
|
||||
})),
|
||||
};
|
||||
const jsonLd = buildBreadcrumbJsonLd(items, origin);
|
||||
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: safeJsonLd(jsonLd) }}
|
||||
/>
|
||||
{jsonLd && (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: safeJsonLd(jsonLd) }}
|
||||
/>
|
||||
)}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol className="flex items-center justify-start gap-1">
|
||||
{items.map((item, idx) => {
|
||||
|
||||
Reference in New Issue
Block a user