mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 22:18:00 +08:00
## Summary
- Adds `breadcrumbListSchema(items)` helper to `apps/www/lib/json-ld.ts`
and a hand-curated `apps/www/lib/breadcrumbs.ts` route map.
- Wires inline `<script type="application/ld+json">` BreadcrumbList
blocks into 18 marketing surfaces: blog (index + slug), customers (index
+ slug), events (index + slug), 5 product pages (database, auth,
storage, edge-functions, realtime), 3 modules (vector, cron, queues),
pricing, careers, company, features.
- Pages router callers wrap the script in `<Head>`; app router callers
place it directly in JSX. Dynamic surfaces append a leaf at render time
using the page's title (`frontmatter.title` for blog, `meta_title ??
title` for customers, `event.meta_title ?? event.title` for events).
- Modules sit at `Home > {Name}` since no `/modules` index page exists;
products sit at `Home > {Product}` (no shared products parent). Absolute
`https://supabase.com` URLs match the existing `CANONICAL_ORIGIN`
convention so anchors stay stable across Vercel previews.
Linear:
[GROWTH-822](https://linear.app/supabase/issue/GROWTH-822/add-breadcrumblist-json-ld-to-www-marketing-surfaces)
(sub-issue under
[GROWTH-724](https://linear.app/supabase/issue/GROWTH-724)).
> **Note on branch name:** the branch is
`pamela/growth-820-www-breadcrumb-jsonld`; the actual Linear issue is
GROWTH-822. The branch was named before the sub-issue was created.
Ignore the `820` in the branch.
Explicitly deferred (separate PRs / low SEO ROI): `/launch-week/*`,
`/solutions/*`, `/partners/*`, `/alternatives/*`, `/changelog`,
`/legal/dpa`, `/aws-reinvent-2025`, `/wrapped`, `/contribute/*`,
`/brand-assets`, `/ga`, `/ga-week`, `/state-of-startups*`, and the
homepage (Organization + WebSite already cover homepage entity signals;
single-item BreadcrumbList is ignored by Google).
## Test plan
- [x] On the Vercel preview, `curl -s https://<preview>/database | grep
'"BreadcrumbList"'` returns the script block with `Home > Database`.
- [x] `curl -s https://<preview>/blog/<recent-slug> | grep
'"BreadcrumbList"'` returns `Home > Blog > {post title}`.
- [x] `curl -s https://<preview>/customers/<slug> | grep
'"BreadcrumbList"'` returns `Home > Customer Stories > {customer
title}`.
- [x] `curl -s https://<preview>/events/<slug> | grep
'"BreadcrumbList"'` returns `Home > Events > {event title}`.
- [x] `curl -s https://<preview>/modules/vector | grep
'"BreadcrumbList"'` returns `Home > Vector`.
63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
import DefaultLayout from '~/components/Layouts/Default'
|
|
import SectionContainer from '~/components/Layouts/SectionContainer'
|
|
import ModulesNav from '~/components/Modules/ModulesNav'
|
|
import ProductModulesHeader from '~/components/Sections/ProductModulesHeader'
|
|
import CronPageData from '~/data/products/modules/cron'
|
|
import { breadcrumbs } from '~/lib/breadcrumbs'
|
|
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
|
|
import { NextSeo } from 'next-seo'
|
|
import dynamic from 'next/dynamic'
|
|
import Head from 'next/head'
|
|
import { PRODUCT_MODULES_NAMES } from 'shared-data/products'
|
|
|
|
const HighlightCards = dynamic(() => import('~/components/Sections/HighlightCards'))
|
|
const CronSQLSection = dynamic(() => import('~/components/Modules/Cron/CronSQLSection'))
|
|
const ImageParagraphSection = dynamic(() => import('~/components/Sections/ImageParagraphSection'))
|
|
const CTABanner = dynamic(() => import('~/components/CTABanner'))
|
|
|
|
function CronPage() {
|
|
const pageData = CronPageData()
|
|
|
|
return (
|
|
<>
|
|
<NextSeo
|
|
title={pageData.metaTitle}
|
|
description={pageData.metaDescription}
|
|
openGraph={{
|
|
title: pageData.metaTitle,
|
|
description: pageData.metaDescription,
|
|
url: `https://supabase.com/modules/cron`,
|
|
images: [
|
|
{
|
|
url: pageData.metaImage,
|
|
},
|
|
],
|
|
}}
|
|
/>
|
|
<Head>
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{
|
|
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.cron)),
|
|
}}
|
|
/>
|
|
</Head>
|
|
<DefaultLayout className="bg-alternative!" stickyNavbar={false}>
|
|
<ModulesNav activePage={PRODUCT_MODULES_NAMES.CRON} docsUrl={pageData.docsUrl} />
|
|
<ProductModulesHeader {...pageData.heroSection} />
|
|
<SectionContainer>{pageData.videoSection.video}</SectionContainer>
|
|
<HighlightCards {...(pageData.highlightsSection as any)} />
|
|
<CronSQLSection {...pageData.section1} />
|
|
<ImageParagraphSection {...pageData.section2} />
|
|
<ImageParagraphSection {...pageData.section3} />
|
|
<ImageParagraphSection {...pageData.section4} />
|
|
<div className="bg-linear-to-t from-alternative to-transparent mt-8 lg:mt-24">
|
|
<CTABanner />
|
|
</div>
|
|
</DefaultLayout>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default CronPage
|