feat(www): SEO technical + on-page improvements #12

Merged
adrianbonpin merged 6 commits from feat/www-seo-technical into prod 2026-09-02 09:10:51 +00:00
2 changed files with 38 additions and 0 deletions
Showing only changes of commit 0e4b47704c - Show all commits
+15
View File
@@ -6,6 +6,7 @@ import {
buildWebSiteJsonLd, buildWebSiteJsonLd,
buildBreadcrumbJsonLd, buildBreadcrumbJsonLd,
buildTitle, buildTitle,
buildProductJsonLd,
} from "./seo"; } from "./seo";
describe("seo builders", () => { describe("seo builders", () => {
@@ -70,4 +71,18 @@ describe("seo builders", () => {
it("buildTitle appends the brand", () => { it("buildTitle appends the brand", () => {
expect(buildTitle("PostgreSQL GUI")).toBe("PostgreSQL GUI | Gridline"); expect(buildTitle("PostgreSQL GUI")).toBe("PostgreSQL GUI | Gridline");
}); });
it("buildProductJsonLd returns valid Product schema", () => {
const ld = buildProductJsonLd({
name: "Gridline",
url: "https://getgridline.app/",
description: "Open-source database GUI",
image: "https://getgridline.app/og.png",
offersPrice: 0,
offersCurrency: "USD",
});
expect(ld["@type"]).toBe("Product");
expect(ld.name).toBe("Gridline");
expect((ld.offers as { price: number }).price).toBe(0);
});
}); });
+23
View File
@@ -108,3 +108,26 @@ export function buildBreadcrumbJsonLd(
export function buildTitle(primary: string, brand = "Gridline"): string { export function buildTitle(primary: string, brand = "Gridline"): string {
return `${primary} | ${brand}`; return `${primary} | ${brand}`;
} }
export function buildProductJsonLd(opts: {
name: string;
url: string;
description: string;
image: string;
offersPrice: number;
offersCurrency: string;
}): JsonLd {
return {
"@context": "https://schema.org",
"@type": "Product",
name: opts.name,
url: opts.url,
description: opts.description,
image: opts.image,
offers: {
"@type": "Offer",
price: opts.offersPrice,
priceCurrency: opts.offersCurrency,
},
};
}