southernmonsarysupply/lib/seo.ts

167 lines
3.6 KiB
TypeScript

import type { Metadata } from "next";
import { siteConfig } from "@/data/site-content";
type PageMetadataInput = {
title: string;
description: string;
path: string;
image?: string;
};
type FaqEntry = {
question: string;
answer: string;
};
type ItemListEntry = {
name: string;
path?: string;
};
export function buildMetadataBase() {
const rawUrl = process.env.NEXT_PUBLIC_SITE_URL || siteConfig.siteUrl;
return new URL(rawUrl.endsWith("/") ? rawUrl : `${rawUrl}/`);
}
export function buildAbsoluteUrl(path: string) {
return new URL(path, buildMetadataBase()).toString();
}
export function buildPageMetadata({
title,
description,
path,
image = siteConfig.defaultOgImage,
}: PageMetadataInput): Metadata {
return {
title,
description,
alternates: {
canonical: path,
},
openGraph: {
title,
description,
url: path,
images: [
{
url: image,
alt: title,
},
],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [image],
},
};
}
export function websiteSchema() {
return {
"@type": "WebSite",
name: siteConfig.name,
url: buildAbsoluteUrl("/"),
};
}
export function businessSchema() {
return {
"@type": "LocalBusiness",
name: siteConfig.name,
url: buildAbsoluteUrl("/"),
description: siteConfig.description,
logo: buildAbsoluteUrl(siteConfig.brand.primaryLogo),
image: buildAbsoluteUrl(siteConfig.defaultOgImage),
telephone: siteConfig.phoneDisplay,
address: {
"@type": "PostalAddress",
streetAddress: siteConfig.address.street,
addressLocality: "Corpus Christi",
addressRegion: "TX",
postalCode: "78405",
addressCountry: "US",
},
sameAs: siteConfig.socials.map((social) => social.href),
contactPoint: [
{
"@type": "ContactPoint",
telephone: siteConfig.phoneDisplay,
contactType: "customer service",
areaServed: "Corpus Christi, TX",
},
],
openingHoursSpecification: [
{
"@type": "OpeningHoursSpecification",
dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
opens: "08:00",
closes: "17:00",
},
],
};
}
export function localBusinessSchema() {
return {
"@context": "https://schema.org",
...businessSchema(),
};
}
export function breadcrumbSchema(items: { name: string; path: string }[]) {
return {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: items.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.name,
item: buildAbsoluteUrl(item.path),
})),
};
}
export function faqPageSchema(items: FaqEntry[]) {
return {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: items.map((item) => ({
"@type": "Question",
name: item.question,
acceptedAnswer: {
"@type": "Answer",
text: item.answer,
},
})),
};
}
export function itemListSchema({
name,
path,
items,
}: {
name: string;
path: string;
items: ItemListEntry[];
}) {
return {
"@context": "https://schema.org",
"@type": "ItemList",
name,
url: buildAbsoluteUrl(path),
numberOfItems: items.length,
itemListOrder: "https://schema.org/ItemListOrderAscending",
itemListElement: items.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.name,
url: item.path ? buildAbsoluteUrl(item.path) : undefined,
})),
};
}