Add initial project files
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import type { Breadcrumb, PageDocument } from '#web-runtime/types';
|
||||
import { toPublicHref } from '#i18n/content-href';
|
||||
|
||||
export type JsonLd = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* schema.org `BreadcrumbList` for a resolved breadcrumb trail. Positions are
|
||||
* 1-based. The current page (the last crumb) intentionally omits `item` — per
|
||||
* Google's guidance it is where the user already is, so it carries no URL.
|
||||
*/
|
||||
export function breadcrumbListJsonLd(items: Breadcrumb[]): JsonLd {
|
||||
return {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': items.map((item, index) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': index + 1,
|
||||
'name': item.label,
|
||||
...(index < items.length - 1 ? { item: toPublicHref(item.href) } : {})
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* schema.org `Article` for an editorial page. Only the fields the backend actually knows are
|
||||
* emitted — a date or image invented here would be markup that contradicts the page.
|
||||
*
|
||||
* `dateModified` is omitted when it equals `datePublished`, since repeating it tells a crawler
|
||||
* nothing, and the whole object is skipped by the caller when there is no publication date:
|
||||
* an `Article` without one is markup Google will ignore anyway.
|
||||
*/
|
||||
export function articleJsonLd(page: PageDocument): JsonLd | null {
|
||||
if (!page.publishedAt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const image = page.hero?.media?.url;
|
||||
|
||||
return {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Article',
|
||||
'headline': page.seo.title || page.title,
|
||||
...(page.seo.description ? { description: page.seo.description } : {}),
|
||||
'datePublished': page.publishedAt,
|
||||
...(page.updatedAt && page.updatedAt !== page.publishedAt
|
||||
? { dateModified: page.updatedAt }
|
||||
: {}),
|
||||
...(image ? { image: [image] } : {}),
|
||||
'inLanguage': page.locale
|
||||
};
|
||||
}
|
||||
|
||||
export function JsonLdScript({ data }: { data: JsonLd }) {
|
||||
return (
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }} />
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user