This commit is contained in:
Andras Schmelczer 2026-05-11 21:30:57 +01:00
parent f3fc893675
commit bb5b4c4cf3
43 changed files with 585 additions and 524 deletions

View file

@ -19,18 +19,20 @@ export const site = {
// entry where `footerOnly` is falsy AND `href !== '/'` (Home is implicit via
// the site title). The Footer renders every entry regardless. Items marked
// `footerOnly: true` appear only in the Footer.
export const navItems = [
export interface NavItem {
href: string;
label: string;
footerOnly?: boolean;
}
export const navItems: readonly NavItem[] = [
{ href: '/', label: 'Home' },
{ href: '/articles/', label: 'Articles' },
{ href: '/projects/', label: 'Projects' },
{ href: '/about/', label: 'About' },
{ href: '/tags/', label: 'Tags', footerOnly: false },
{ href: '/tags/', label: 'Tags' },
{ href: '/rss.xml', label: 'RSS', footerOnly: true },
] as const satisfies ReadonlyArray<{
href: string;
label: string;
footerOnly?: boolean;
}>;
];
export function formatDate(date: Date) {
return new Intl.DateTimeFormat('en', {
@ -176,28 +178,53 @@ interface BreadcrumbCrumb {
interface BreadcrumbInput {
articles?: boolean;
projects?: boolean;
tagsIndex?: boolean;
tag?: string;
post?: CollectionEntry<'posts'>;
}
// Builds the breadcrumb trail shared by JSON-LD (BreadcrumbList) and the
// visible Breadcrumbs component. Home is always first. Pass `articles: true`
// to include the /articles/ crumb; pass a `tag` to append a tag crumb; pass
// a `post` to append the post title (linking to its article path).
// visible Breadcrumbs component. Home is always first. Flags append crumbs
// in a fixed order: Articles → Tags → tag → Post (or Projects). A `tag`
// implies both Articles and Tags so callers don't have to set every flag.
export function buildBreadcrumbTrail({
articles,
projects,
tagsIndex,
tag,
post,
}: BreadcrumbInput): BreadcrumbCrumb[] {
const trail: BreadcrumbCrumb[] = [{ name: 'Home', href: '/' }];
if (articles || post) {
if (articles || post || tagsIndex || tag) {
trail.push({ name: 'Articles', href: '/articles/' });
}
if (tagsIndex || tag) {
trail.push({ name: 'Tags', href: '/tags/' });
}
if (tag) {
trail.push({ name: tag, href: tagPath(tag) });
trail.push({ name: `#${tag}`, href: tagPath(tag) });
}
if (post) {
trail.push({ name: post.data.title, href: articlePath(post) });
}
if (projects) {
trail.push({ name: 'Projects', href: '/projects/' });
}
return trail;
}
// Builds the schema.org BreadcrumbList JSON-LD object for a given trail.
// Shared by every page that emits breadcrumb structured data.
export function buildBreadcrumbJsonLd(trail: BreadcrumbCrumb[]) {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: trail.map((crumb, index) => ({
'@type': 'ListItem',
position: index + 1,
name: crumb.name,
item: absoluteUrl(crumb.href),
})),
};
}