spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { Metadata } from "next";2import { SITE_URL } from "@/lib/routes";34/** Metadata for an entity / index page: title, description, canonical + OG/Twitter mirror (OG image comes from the segment's opengraph-image.tsx). */5export function pageMetadata({ title, description, path, absoluteTitle }: { title: string; description: string; path: string; absoluteTitle?: boolean }): Metadata {6 const desc = description.length > 300 ? `${description.slice(0, 297)}…` : description;7 return {8 title: absoluteTitle ? { absolute: title } : title,9 description: desc,10 alternates: { canonical: path },11 openGraph: { title, description: desc, url: `${SITE_URL}${path}`, type: "website" },12 twitter: { card: "summary_large_image", title, description: desc },13 };14}1516/** Metadata for an entity that does not exist (still renders 404 body via notFound()). */17export const NOT_FOUND_METADATA: Metadata = { title: "Not found", robots: { index: false, follow: false } };1819export function absoluteUrl(path: string): string {20 return `${SITE_URL}${path.startsWith("/") ? path : `/${path}`}`;21}2223/** Drop null / undefined / empty values from a JSON-LD object (Google ignores empty props but it keeps the payload tidy). */24export function compactJsonLd<T extends Record<string, unknown>>(obj: T): Partial<T> {25 const out: Record<string, unknown> = {};26 for (const [k, v] of Object.entries(obj)) {27 if (v === null || v === undefined || v === "") continue;28 if (Array.isArray(v) && v.length === 0) continue;29 out[k] = v;30 }31 return out as Partial<T>;32}3334export function breadcrumbJsonLd(items: Array<{ name: string; href: string }>) {35 return {36 "@context": "https://schema.org",37 "@type": "BreadcrumbList",38 itemListElement: items.map((it, i) => ({ "@type": "ListItem", position: i + 1, name: it.name, item: absoluteUrl(it.href) })),39 };40}41