From c081e894cb7b8e4bbde6d427ae8a3b78e1e9146e Mon Sep 17 00:00:00 2001 From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com> Date: Thu, 11 Jun 2026 10:05:55 +0200 Subject: [PATCH 1/4] SEO improvements --- website-next/app/(content)/help/page.tsx | 8 +++ .../app/(content)/platform/analytics/page.tsx | 8 +++ .../platform/continuous-integration/page.tsx | 8 +++ .../app/(content)/platform/ecosystem/page.tsx | 8 +++ website-next/app/(content)/platform/page.tsx | 7 ++ website-next/app/(content)/pricing/page.tsx | 8 +++ .../(content)/products/hotchocolate/page.tsx | 8 +++ .../app/(content)/products/nitro/page.tsx | 8 +++ .../products/strawberryshake/page.tsx | 8 +++ .../app/(content)/services/advisory/page.tsx | 8 +++ website-next/app/(content)/services/page.tsx | 7 ++ .../services/support/contact/page.tsx | 8 +++ .../app/(content)/services/support/page.tsx | 8 +++ .../app/(content)/services/training/page.tsx | 8 +++ website-next/app/blog/[...slug]/page.tsx | 43 ++++++++++++ website-next/app/docs/[...slug]/page.tsx | 64 ++++++++++++++++- website-next/app/favicon.ico | Bin 0 -> 6159 bytes website-next/app/globals.css | 65 ++++++++++++++++++ website-next/app/icon.png | Bin 14087 -> 21514 bytes website-next/app/icon.svg | 6 ++ website-next/app/{(content) => }/page.tsx | 0 website-next/app/sitemap.ts | 37 +++++----- .../blog/2022-01-13-hot-chocolate-12-5.md | 2 +- .../2022-09-01-new-in-banana-cake-pop-1.md | 2 +- .../2022-10-05-new-in-banana-cake-pop-2.md | 2 +- .../2023-01-08-new-in-banana-cake-pop-3.md | 2 +- .../2023-02-07-new-in-banana-cake-pop-4.md | 2 +- .../2023-02-08-new-in-hot-chocolate-13.md | 2 +- ...2023-03-15-banana-cake-pop-graphql-apis.md | 1 - .../content/blog/2023-08-15-fusion.md | 1 - .../blog/2024-04-01-fullstack-workshop.md | 1 - .../content/blog/2024-05-21-newsletter-may.md | 2 +- .../content/blog/2024-08-11-logging.md | 1 - .../blog/2024-08-30-hot-chocolate-14.md | 2 +- .../blog/2024-10-07-introducing-nitro.md | 1 - .../blog/2024-10-30-newsletter-october.md | 2 +- .../blog/2025-02-01-hot-chocolate-15.md | 2 +- .../2025-03-17-open-telemetry-for-everyone.md | 1 - .../blog/2026-04-22-semantic-introspection.md | 2 +- .../blog/2026-05-11-hot-chocolate-16.md | 2 +- .../content/blog/2026-05-15-fusion-16.md | 2 +- .../2026-05-28-mcp-hotchocolate-fusion.md | 2 +- .../blog/2026-06-05-introducing-skillz.md | 2 +- .../blog/2026-06-06-newsletter-may-2026.md | 2 +- .../content/legal/acceptable-use-policy.md | 1 + website-next/content/legal/cookie-policy.md | 1 + website-next/content/legal/privacy-policy.md | 1 + .../content/legal/terms-of-service.md | 1 + website-next/src/components/BlogTeaser.tsx | 2 +- website-next/src/components/DocsToolbar.tsx | 2 +- website-next/src/components/EditOnGitHub.tsx | 2 +- website-next/src/components/SimilarPosts.tsx | 2 +- .../src/design-system/BrokenMedia.tsx | 30 ++++---- .../src/design-system/Image.stories.tsx | 41 ++++++++++- website-next/src/design-system/Image.tsx | 16 ++++- website-next/src/helpers/buildContentTree.ts | 41 +++++++++++ .../src/image-optimization/manifest.ts | 5 ++ 57 files changed, 445 insertions(+), 63 deletions(-) create mode 100644 website-next/app/favicon.ico create mode 100644 website-next/app/icon.svg rename website-next/app/{(content) => }/page.tsx (100%) diff --git a/website-next/app/(content)/help/page.tsx b/website-next/app/(content)/help/page.tsx index 94f8259fce9..019da51e56c 100644 --- a/website-next/app/(content)/help/page.tsx +++ b/website-next/app/(content)/help/page.tsx @@ -1,6 +1,14 @@ +import type { Metadata } from "next"; + import { type Plan, PlanGrid } from "@/src/components/PlanGrid"; import { Section } from "@/src/components/Section"; +export const metadata: Metadata = { + title: "Help", + description: + "Need urgent GraphQL help? Join the ChilliCream community Slack, book a session with an expert, or choose a support plan that fits your team.", +}; + const PLANS: Plan[] = [ { title: "Community", diff --git a/website-next/app/(content)/platform/analytics/page.tsx b/website-next/app/(content)/platform/analytics/page.tsx index b97455e2520..cf53433598c 100644 --- a/website-next/app/(content)/platform/analytics/page.tsx +++ b/website-next/app/(content)/platform/analytics/page.tsx @@ -1,3 +1,5 @@ +import type { Metadata } from "next"; + import { Picture } from "@/src/design-system/Picture"; import { ContentSection } from "@/src/components/ContentSection"; @@ -5,6 +7,12 @@ import { NextStepsSection } from "@/src/components/NextStepsSection"; import { PageHero } from "@/src/components/PageHero"; import { SolidButton } from "@/src/design-system/Button"; +export const metadata: Metadata = { + title: "Analytics", + description: + "Monitor your GraphQL APIs with ChilliCream analytics: real-time insights, throughput and latency metrics, and full OpenTelemetry trace exploration.", +}; + export default function AnalyticsPage() { return ( <> diff --git a/website-next/app/(content)/platform/continuous-integration/page.tsx b/website-next/app/(content)/platform/continuous-integration/page.tsx index b65ad7051ea..896f7761410 100644 --- a/website-next/app/(content)/platform/continuous-integration/page.tsx +++ b/website-next/app/(content)/platform/continuous-integration/page.tsx @@ -1,8 +1,16 @@ +import type { Metadata } from "next"; + import { ContentSection } from "@/src/components/ContentSection"; import { NextStepsSection } from "@/src/components/NextStepsSection"; import { PageHero } from "@/src/components/PageHero"; import { SolidButton } from "@/src/design-system/Button"; +export const metadata: Metadata = { + title: "Continuous Integration", + description: + "Ship GraphQL changes safely with ChilliCream: schema validation, a centralized registry, environment workflows, and CI/CD integration via the Nitro CLI.", +}; + export default function ContinuousIntegrationPage() { return ( <> diff --git a/website-next/app/(content)/platform/ecosystem/page.tsx b/website-next/app/(content)/platform/ecosystem/page.tsx index b3b1db131aa..a2ef620396b 100644 --- a/website-next/app/(content)/platform/ecosystem/page.tsx +++ b/website-next/app/(content)/platform/ecosystem/page.tsx @@ -1,8 +1,16 @@ +import type { Metadata } from "next"; + import { ContentSection } from "@/src/components/ContentSection"; import { NextStepsSection } from "@/src/components/NextStepsSection"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; +export const metadata: Metadata = { + title: "Ecosystem", + description: + "Explore the ChilliCream ecosystem: GraphQL tooling with authentication flows, document sync, subscriptions, and a fast IDE built for your API journey.", +}; + interface FeatureCard { title: string; description: string; diff --git a/website-next/app/(content)/platform/page.tsx b/website-next/app/(content)/platform/page.tsx index 7faeaf34c40..d7fd278a36d 100644 --- a/website-next/app/(content)/platform/page.tsx +++ b/website-next/app/(content)/platform/page.tsx @@ -1,8 +1,15 @@ +import type { Metadata } from "next"; import Link from "next/link"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; +export const metadata: Metadata = { + title: "Platform", + description: + "Discover the ChilliCream GraphQL Platform: one place for analytics, continuous integration, and a trusted ecosystem for every API in your organization.", +}; + const PLATFORM_SECTIONS = [ { href: "/platform/analytics", diff --git a/website-next/app/(content)/pricing/page.tsx b/website-next/app/(content)/pricing/page.tsx index 05d7200be67..3c46fa8fcff 100644 --- a/website-next/app/(content)/pricing/page.tsx +++ b/website-next/app/(content)/pricing/page.tsx @@ -1,5 +1,13 @@ +import type { Metadata } from "next"; + import { Typography } from "@/src/design-system/Typography"; +export const metadata: Metadata = { + title: "Pricing", + description: + "Explore pricing for the ChilliCream GraphQL Platform. Compare plans and find the right option for your team, from open source to enterprise.", +}; + export default function Page() { return TODO: Pricing page; } diff --git a/website-next/app/(content)/products/hotchocolate/page.tsx b/website-next/app/(content)/products/hotchocolate/page.tsx index e117811b563..ff75a7f2c8b 100644 --- a/website-next/app/(content)/products/hotchocolate/page.tsx +++ b/website-next/app/(content)/products/hotchocolate/page.tsx @@ -1,8 +1,16 @@ +import type { Metadata } from "next"; + import { ContentSection } from "@/src/components/ContentSection"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; import { OutlineButton, SolidButton } from "@/src/design-system/Button"; +export const metadata: Metadata = { + title: "Hot Chocolate", + description: + "Hot Chocolate is the GraphQL server for .NET: build type-safe APIs with DataLoader batching, subscriptions, OpenTelemetry, and federation via Fusion.", +}; + const FEATURES = [ { title: "Compile-time Composition", diff --git a/website-next/app/(content)/products/nitro/page.tsx b/website-next/app/(content)/products/nitro/page.tsx index eab5ef37f2e..b43af199e92 100644 --- a/website-next/app/(content)/products/nitro/page.tsx +++ b/website-next/app/(content)/products/nitro/page.tsx @@ -1,8 +1,16 @@ +import type { Metadata } from "next"; + import { ContentSection } from "@/src/components/ContentSection"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; import { OutlineButton, SolidButton } from "@/src/design-system/Button"; +export const metadata: Metadata = { + title: "Nitro", + description: + "Nitro is ChilliCream's GraphQL IDE: explore any GraphQL API with authentication flows, document sync, and subscriptions over SSE and WebSockets.", +}; + const FEATURES: { title: string; description: string }[] = [ { title: "Authentication Flows", diff --git a/website-next/app/(content)/products/strawberryshake/page.tsx b/website-next/app/(content)/products/strawberryshake/page.tsx index 359a45ec5bd..d63d5f358d2 100644 --- a/website-next/app/(content)/products/strawberryshake/page.tsx +++ b/website-next/app/(content)/products/strawberryshake/page.tsx @@ -1,8 +1,16 @@ +import type { Metadata } from "next"; + import { ContentSection } from "@/src/components/ContentSection"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; import { OutlineButton, SolidButton } from "@/src/design-system/Button"; +export const metadata: Metadata = { + title: "Strawberry Shake", + description: + "Strawberry Shake is a strongly-typed GraphQL client for .NET with a reactive store, caching, subscriptions, and compile-time source generators.", +}; + const FEATURES = [ { title: "Strongly-typed Client", diff --git a/website-next/app/(content)/services/advisory/page.tsx b/website-next/app/(content)/services/advisory/page.tsx index af4c46aa209..c5df4828f19 100644 --- a/website-next/app/(content)/services/advisory/page.tsx +++ b/website-next/app/(content)/services/advisory/page.tsx @@ -1,6 +1,14 @@ +import type { Metadata } from "next"; + import { Offering } from "@/src/components/Offering"; import { PageHero } from "@/src/components/PageHero"; +export const metadata: Metadata = { + title: "Advisory", + description: + "Get quick access to ChilliCream's GraphQL experts: hourly consulting, architecture guidance, code reviews, and full contracting engagements.", +}; + interface InquiryPlan { title: string; description: string; diff --git a/website-next/app/(content)/services/page.tsx b/website-next/app/(content)/services/page.tsx index eb21c8d9237..02ee40fed19 100644 --- a/website-next/app/(content)/services/page.tsx +++ b/website-next/app/(content)/services/page.tsx @@ -1,8 +1,15 @@ +import type { Metadata } from "next"; import Link from "next/link"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; +export const metadata: Metadata = { + title: "Services", + description: + "Work with ChilliCream's GraphQL experts: advisory and consulting, support plans with SLAs you can rely on, and focused training for your team.", +}; + const SERVICE_SECTIONS = [ { href: "/services/advisory", diff --git a/website-next/app/(content)/services/support/contact/page.tsx b/website-next/app/(content)/services/support/contact/page.tsx index 025884c5358..e5feae13013 100644 --- a/website-next/app/(content)/services/support/contact/page.tsx +++ b/website-next/app/(content)/services/support/contact/page.tsx @@ -1,6 +1,14 @@ +import type { Metadata } from "next"; + import { PageHero } from "@/src/components/PageHero"; import { ContactForm } from "./ContactForm"; +export const metadata: Metadata = { + title: "Contact Us", + description: + "Contact the ChilliCream team: tell us what you need, from support plans and demos to GraphQL consulting and training, and we will be in touch shortly.", +}; + export default function ContactPage() { return ( <> diff --git a/website-next/app/(content)/services/support/page.tsx b/website-next/app/(content)/services/support/page.tsx index d3c34934e03..7d84e627383 100644 --- a/website-next/app/(content)/services/support/page.tsx +++ b/website-next/app/(content)/services/support/page.tsx @@ -1,3 +1,5 @@ +import type { Metadata } from "next"; + import { type Plan, PlanGrid } from "@/src/components/PlanGrid"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; @@ -11,6 +13,12 @@ import { } from "@/src/design-system/Table"; import { CheckIcon } from "@/src/components/CheckIcon"; +export const metadata: Metadata = { + title: "Support", + description: + "Get GraphQL support from ChilliCream experts: plans from a free community Slack to enterprise SLAs with dedicated account managers and phone support.", +}; + const SUPPORT_PLANS: Plan[] = [ { title: "Community", diff --git a/website-next/app/(content)/services/training/page.tsx b/website-next/app/(content)/services/training/page.tsx index ef24576ac70..990320b9880 100644 --- a/website-next/app/(content)/services/training/page.tsx +++ b/website-next/app/(content)/services/training/page.tsx @@ -1,7 +1,15 @@ +import type { Metadata } from "next"; + import { Offering } from "@/src/components/Offering"; import { PageHero } from "@/src/components/PageHero"; import { Section } from "@/src/components/Section"; +export const metadata: Metadata = { + title: "Training", + description: + "Train your team with ChilliCream: corporate GraphQL training and workshops covering Hot Chocolate, ASP.NET Core, React, and Relay, taught by experts.", +}; + interface CorporateService { kind: string; description: string; diff --git a/website-next/app/blog/[...slug]/page.tsx b/website-next/app/blog/[...slug]/page.tsx index 709ef769ef8..8402b239ad5 100644 --- a/website-next/app/blog/[...slug]/page.tsx +++ b/website-next/app/blog/[...slug]/page.tsx @@ -95,11 +95,25 @@ export async function generateMetadata({ return { title, description, + ...(summary?.author + ? { authors: [{ name: summary.author, url: summary.authorUrl ?? undefined }] } + : {}), + alternates: { + canonical: summary?.href, + }, openGraph: { type: "article", title, description, images, + url: summary?.href, + publishedTime: summary?.date, + authors: summary?.authorUrl + ? [summary.authorUrl] + : summary?.author + ? [summary.author] + : undefined, + tags: summary && summary.tags.length > 0 ? summary.tags : undefined, }, twitter: { card: "summary_large_image", @@ -143,8 +157,37 @@ export default async function BlogSlugPage({ params }: PageProps) { const similar = current ? findSimilarPosts(current, summaries) : []; const featuredImage = current?.featuredImage ?? null; + const jsonLd = current + ? { + "@context": "https://schema.org", + "@type": "BlogPosting", + headline: current.title, + ...(current.description ? { description: current.description } : {}), + datePublished: current.date, + ...(current.featuredImage + ? { image: toAbsoluteUrl(current.featuredImage) } + : {}), + ...(current.author + ? { + author: { + "@type": "Person", + name: current.author, + ...(current.authorUrl ? { url: current.authorUrl } : {}), + }, + } + : {}), + mainEntityOfPage: toAbsoluteUrl(current.href), + } + : null; + return (
+ {jsonLd ? ( +