feat(www): emit BreadcrumbList JSON-LD on marketing surfaces (#45478)

## 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`.
This commit is contained in:
Pamela Chia authored and GitHub committed 2026-05-05 23:57:53 +08:00
1 parent 2e904abebf
commit c26b64a033
20 files changed
+277 -63

No files matched your search

+10 -1
View File
@@ -9,8 +9,9 @@ import {
getAbsoluteBlogSocialImage,
toAbsoluteBlogImageUrl,
} from '@/lib/blog-images'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { SITE_ORIGIN } from '@/lib/constants'
import { blogPostingSchema, serializeJsonLd } from '@/lib/json-ld'
import { blogPostingSchema, breadcrumbListSchema, serializeJsonLd } from '@/lib/json-ld'
import { getAllPostSlugs, getPostdata, getSortedPosts } from '@/lib/posts'
import type { Blog, BlogData, PostReturnType } from '@/types/post'
@@ -171,6 +172,10 @@ export default async function BlogPostPage({ params }: { params: Promise<Params>
datePublished: frontmatter.date,
authors: blogAuthors.length > 0 ? blogAuthors : [{ name: 'Supabase' }],
})
const breadcrumbJsonLd = breadcrumbListSchema([
...breadcrumbs.blogIndex,
{ name: frontmatter.title, url: `https://supabase.com/blog/${slug}` },
])
return (
<>
@@ -178,6 +183,10 @@ export default async function BlogPostPage({ params }: { params: Promise<Params>
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: serializeJsonLd(blogJsonLd) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: serializeJsonLd(breadcrumbJsonLd) }}
/>
<BlogPostClient {...props} />
</>
)
+23 -11
View File
@@ -4,6 +4,8 @@ import type { Metadata } from 'next'
import type PostTypes from 'types/post'
import BlogClient from './BlogClient'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd } from '@/lib/json-ld'
import { getSortedPosts } from '@/lib/posts'
export const revalidate = 30
@@ -39,17 +41,27 @@ export default async function BlogPage() {
const totalListPosts = Math.max(0, allPosts.length - 1)
return (
<DefaultLayout>
<h1 className="sr-only">Supabase blog</h1>
<div className="container relative mx-auto px-4 py-4 md:py-8 xl:py-10 sm:px-16 xl:px-20">
{featuredPost && <FeaturedThumb key={featuredPost.slug} {...(featuredPost as PostTypes)} />}
</div>
<div className="border-default border-t">
<div className="container mx-auto px-4 py-4 md:py-8 xl:py-10 sm:px-16 xl:px-20">
<BlogClient initialBlogs={listPosts} totalPosts={totalListPosts} />
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.blogIndex)),
}}
/>
<DefaultLayout>
<h1 className="sr-only">Supabase blog</h1>
<div className="container relative mx-auto px-4 py-4 md:py-8 xl:py-10 sm:px-16 xl:px-20">
{featuredPost && (
<FeaturedThumb key={featuredPost.slug} {...(featuredPost as PostTypes)} />
)}
</div>
</div>
</DefaultLayout>
<div className="border-default border-t">
<div className="container mx-auto px-4 py-4 md:py-8 xl:py-10 sm:px-16 xl:px-20">
<BlogClient initialBlogs={listPosts} totalPosts={totalListPosts} />
</div>
</div>
</DefaultLayout>
</>
)
}
+15 -3
View File
@@ -1,6 +1,8 @@
import type { Metadata } from 'next'
import { getNotionEvents } from '~/lib/events'
import { EventClientRenderer } from '~/components/Events/new/EventClientRenderer'
import { breadcrumbs } from '~/lib/breadcrumbs'
import { getNotionEvents } from '~/lib/events'
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'View all Supabase events and meetups.',
@@ -11,5 +13,15 @@ export const metadata: Metadata = {
export default async function EventsPage() {
const notionEvents = await getNotionEvents()
return <EventClientRenderer notionEvents={notionEvents} />
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.eventsIndex)),
}}
/>
<EventClientRenderer notionEvents={notionEvents} />
</>
)
}
+13 -1
View File
@@ -1,6 +1,8 @@
import type { Metadata } from 'next'
import PricingContent from './PricingContent'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd } from '@/lib/json-ld'
export const metadata: Metadata = {
title: 'Pricing & Fees | Supabase',
@@ -25,5 +27,15 @@ export const metadata: Metadata = {
}
export default function PricingPage() {
return <PricingContent />
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.pricing)),
}}
/>
<PricingContent />
</>
)
}
+23
View File
@@ -0,0 +1,23 @@
import type { BreadcrumbItem } from './json-ld'
const SITE = 'https://supabase.com'
const home: BreadcrumbItem = { name: 'Home', url: SITE }
export const breadcrumbs = {
blogIndex: [home, { name: 'Blog', url: `${SITE}/blog` }],
customersIndex: [home, { name: 'Customer Stories', url: `${SITE}/customers` }],
eventsIndex: [home, { name: 'Events', url: `${SITE}/events` }],
database: [home, { name: 'Database', url: `${SITE}/database` }],
auth: [home, { name: 'Auth', url: `${SITE}/auth` }],
storage: [home, { name: 'Storage', url: `${SITE}/storage` }],
edgeFunctions: [home, { name: 'Edge Functions', url: `${SITE}/edge-functions` }],
realtime: [home, { name: 'Realtime', url: `${SITE}/realtime` }],
vector: [home, { name: 'Vector', url: `${SITE}/modules/vector` }],
cron: [home, { name: 'Cron', url: `${SITE}/modules/cron` }],
queues: [home, { name: 'Queues', url: `${SITE}/modules/queues` }],
pricing: [home, { name: 'Pricing', url: `${SITE}/pricing` }],
careers: [home, { name: 'Careers', url: `${SITE}/careers` }],
company: [home, { name: 'Company', url: `${SITE}/company` }],
features: [home, { name: 'Features', url: `${SITE}/features` }],
} satisfies Record<string, BreadcrumbItem[]>
+18
View File
@@ -83,6 +83,24 @@ export function softwareApplicationSchema(input: SoftwareApplicationSchemaInput)
}
}
export interface BreadcrumbItem {
name: string
url: string
}
export function breadcrumbListSchema(items: BreadcrumbItem[]) {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
}
}
interface BlogPostingSchemaInput {
url: string
headline: string
+8 -1
View File
@@ -19,7 +19,8 @@ import AuthProviders from '@/data/auth.json'
import MainProducts from '@/data/MainProducts'
import ApiExamples from '@/data/products/auth/auth-api-examples'
import AuthSqlRulesExamples from '@/data/products/auth/auth-sql-rules-examples'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const SplitCodeBlockCarousel = dynamic(
() => import('~/components/Carousels/SplitCodeBlockCarousel')
@@ -70,6 +71,12 @@ function AuthPage() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.auth)),
}}
/>
</Head>
<DefaultLayout>
<ProductsNav activePage={PRODUCT_NAMES.AUTHENTICATION} />
+11
View File
@@ -3,10 +3,13 @@ import Globe from '~/components/Globe'
import DefaultLayout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
import career from '~/data/career.json'
import { breadcrumbs } from '~/lib/breadcrumbs'
import { filterGenericJob, groupJobsByTeam, JobItemProps, PLACEHOLDER_JOB_ID } from '~/lib/careers'
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
import Styles from '~/styles/career.module.css'
import { GetServerSideProps } from 'next'
import { NextSeo } from 'next-seo'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
@@ -109,6 +112,14 @@ const CareerPage = ({ jobs, placeholderJob, contributors }: CareersPageProps) =>
],
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.careers)),
}}
/>
</Head>
<DefaultLayout>
<header className="container relative mx-auto px-6 pt-12 pb-8 lg:pt-24 lg:px-16 xl:px-20 text-center space-y-4">
<h1 className="text-sm text-brand md:text-base">
+16 -10
View File
@@ -1,22 +1,20 @@
import { useRouter } from 'next/router'
import Layout from '~/components/Layouts/Default'
import SectionHeader from 'components/UI/SectionHeader'
import SectionContainer from '~/components/Layouts/SectionContainer'
import { breadcrumbs } from '~/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
import CTABanner from 'components/CTABanner/index'
import ImageGrid from 'components/ImageGrid'
import SectionContainer from '~/components/Layouts/SectionContainer'
import PressData from 'data/Press'
import SectionHeader from 'components/UI/SectionHeader'
import CommunityData from 'data/Community'
import CompaniesData from 'data/Companies'
import InvestorData from 'data/Investors'
import PressData from 'data/Press'
import { NextSeo } from 'next-seo'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Button, Card_legacy_, Space } from 'ui'
import { NextSeo } from 'next-seo'
type Props = {}
@@ -43,6 +41,14 @@ const Index = ({}: Props) => {
],
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.company)),
}}
/>
</Head>
<Layout>
<Header />
<Community />
+17 -11
View File
@@ -1,21 +1,21 @@
import fs from 'fs'
import { useRouter } from 'next/router'
import Head from 'next/head'
import { NextSeo } from 'next-seo'
import { generateRss } from '~/lib/rss'
import { getSortedPosts } from '~/lib/posts'
import DefaultLayout from '~/components/Layouts/Default'
import { getSortedPosts } from '~/lib/posts'
import { generateRss } from '~/lib/rss'
import styles from '~/styles/customers.module.css'
import type PostTypes from '~/types/post'
import { motion } from 'framer-motion'
import styles from '~/styles/customers.module.css'
import { NextSeo } from 'next-seo'
import Head from 'next/head'
import Link from 'next/link'
import { GlassPanel } from 'ui-patterns/GlassPanel'
import CustomersFilters from '../components/CustomerStories/CustomersFilters'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { Button, cn } from 'ui'
import { GlassPanel } from 'ui-patterns/GlassPanel'
import CustomersFilters from '../components/CustomerStories/CustomersFilters'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd } from '@/lib/json-ld'
export async function getStaticProps() {
const allPostsData: any[] = getSortedPosts({ directory: '_customers' })
@@ -99,6 +99,12 @@ function CustomerStoriesPage(props: any) {
title="RSS feed for customer stories"
href={`${basePath}/customers-rss.xml`}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.customersIndex)),
}}
/>
</Head>
<NextSeo
title={meta.title}
+23 -8
View File
@@ -1,17 +1,19 @@
import matter from 'gray-matter'
import { ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react'
import { MDXRemote } from 'next-mdx-remote'
import { NextSeo } from 'next-seo'
import Image from 'next/image'
import Link from 'next/link'
import { Button } from 'ui'
import CTABanner from '~/components/CTABanner'
import DefaultLayout from '~/components/Layouts/Default'
import { breadcrumbs } from '~/lib/breadcrumbs'
import { SITE_ORIGIN } from '~/lib/constants'
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
import mdxComponents from '~/lib/mdx/mdxComponents'
import { mdxSerialize } from '~/lib/mdx/mdxSerialize'
import { getAllPostSlugs, getPostdata, getSortedPosts } from '~/lib/posts'
import matter from 'gray-matter'
import { ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react'
import { MDXRemote } from 'next-mdx-remote'
import { NextSeo } from 'next-seo'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import { Button } from 'ui'
// table of contents extractor
const toc = require('markdown-toc')
@@ -89,6 +91,11 @@ function CaseStudyPage(props: any) {
url: `${SITE_ORIGIN}/customers/${slug}`,
}
const breadcrumbItems = [
...breadcrumbs.customersIndex,
{ name: meta_title ?? title, url: `https://supabase.com/customers/${slug}` },
]
return (
<>
<NextSeo
@@ -112,6 +119,14 @@ function CaseStudyPage(props: any) {
],
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbItems)),
}}
/>
</Head>
<DefaultLayout>
<div
className="
+8 -1
View File
@@ -24,7 +24,8 @@ import ExtensionsExamplesData from '@/data/products/database/extensions-examples
import HighlightsCards from '@/data/products/database/highlight-cards'
import SqlViewCarouselData from '@/data/products/database/sql-view-carousel.json'
import TableViewCarouselData from '@/data/products/database/table-view-carousel.json'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const NewFeatureCard = dynamic(() => import('~/components/NewFeatureCard'))
const ImageCarousel = dynamic(() => import('~/components/Carousels/ImageCarousel'))
@@ -88,6 +89,12 @@ function Database() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.database)),
}}
/>
</Head>
<DefaultLayout>
<ProductsNav activePage={PRODUCT_NAMES.DATABASE} />
+8 -1
View File
@@ -13,7 +13,8 @@ import { useRouter } from 'next/router'
import React from 'react'
import { PRODUCT_NAMES, PRODUCT_SHORTNAMES } from 'shared-data/products'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const ExamplesCarousel = dynamic(() => import('~/components/Examples/ExamplesCarousel'))
const GlobalPresenceSection = dynamic(
@@ -62,6 +63,12 @@ function EdgeFunctions() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.edgeFunctions)),
}}
/>
</Head>
<DefaultLayout>
<ProductsNav activePage={PRODUCT_NAMES.FUNCTIONS} />
+19
View File
@@ -15,6 +15,7 @@ import { ChevronLeft, X as XIcon } from 'lucide-react'
import type { GetStaticProps, InferGetStaticPropsType } from 'next'
import { MDXRemote } from 'next-mdx-remote'
import { NextSeo } from 'next-seo'
import Head from 'next/head'
import NextImage from 'next/image'
import Link from 'next/link'
import { Button } from 'ui'
@@ -24,7 +25,9 @@ import ShareArticleActions from '@/components/Blog/ShareArticleActions'
import DefaultLayout from '@/components/Layouts/Default'
import SectionContainer from '@/components/Layouts/SectionContainer'
import authors from '@/lib/authors.json'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { capitalize, isNotNullOrUndefined } from '@/lib/helpers'
import { breadcrumbListSchema, serializeJsonLd } from '@/lib/json-ld'
import mdxComponents from '@/lib/mdx/mdxComponents'
import { mdxSerialize } from '@/lib/mdx/mdxSerialize'
import { getAllPostSlugs, getPostdata } from '@/lib/posts'
@@ -221,6 +224,22 @@ const EventPage = ({ event }: InferGetStaticPropsType<typeof getStaticProps>) =>
},
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(
breadcrumbListSchema([
...breadcrumbs.eventsIndex,
{
name: event.meta_title ?? event.title,
url: `https://supabase.com/events/${event.slug}`,
},
])
),
}}
/>
</Head>
<DefaultLayout>
<div className="flex flex-col w-full bg-alternative border-b border-muted">
<SectionContainer className="py-2! flex items-start">
+11
View File
@@ -2,11 +2,14 @@ import DefaultLayout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
import Panel from '~/components/Panel'
import { features } from '~/data/features'
import { breadcrumbs } from '~/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd } from '~/lib/json-ld'
import { motion } from 'framer-motion'
import { debounce } from 'lib/helpers'
import { Search } from 'lucide-react'
import { NextSeo } from 'next-seo'
import { useRouter } from 'next/compat/router'
import Head from 'next/head'
import Link from 'next/link'
import React, { useCallback, useEffect, useState } from 'react'
import { Button, Checkbox, cn, InputGroup, InputGroupAddon, InputGroupInput } from 'ui'
@@ -103,6 +106,14 @@ function FeaturesPage() {
url: '/customers',
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.features)),
}}
/>
</Head>
<DefaultLayout>
<SectionContainer className="py-0! sm:px-0!">
<div className="border border-muted rounded-xl bg-alternative my-4 px-6 py-8 md:py-10 lg:px-16 lg:py-20 xl:px-20 bg-center bg-cover bg-[url('/images/features/features-cover-light.svg')] dark:bg-[url('/images/features/features-cover-dark.svg')]">
+15 -6
View File
@@ -1,13 +1,14 @@
import { NextSeo } from 'next-seo'
import dynamic from 'next/dynamic'
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 SectionContainer from '~/components/Layouts/SectionContainer'
import { PRODUCT_MODULES_NAMES } from 'shared-data/products'
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'))
@@ -33,6 +34,14 @@ function CronPage() {
],
}}
/>
<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} />
+15 -6
View File
@@ -1,13 +1,14 @@
import { NextSeo } from 'next-seo'
import dynamic from 'next/dynamic'
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 SectionContainer from '~/components/Layouts/SectionContainer'
import { PRODUCT_MODULES_NAMES } from 'shared-data/products'
import QueuesPageData from '~/data/products/modules/queues'
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 QueuesSQLSection = dynamic(() => import('~/components/Modules/Queues/QueuesSQLSection'))
@@ -34,6 +35,14 @@ function CronPage() {
],
}}
/>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.queues)),
}}
/>
</Head>
<DefaultLayout className="bg-alternative!" stickyNavbar={false}>
<ModulesNav activePage={PRODUCT_MODULES_NAMES.QUEUES} docsUrl={pageData.docsUrl} />
<ProductModulesHeader {...pageData.heroSection} />
+8 -1
View File
@@ -9,7 +9,8 @@ import dynamic from 'next/dynamic'
import Head from 'next/head'
import { PRODUCT_MODULES_NAMES, PRODUCT_MODULES_SHORTNAMES } from 'shared-data/products'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const ProductModulesHeader = dynamic(() => import('~/components/Sections/ProductModulesHeader'))
const HighlightCards = dynamic(() => import('~/components/Sections/HighlightCards'))
@@ -61,6 +62,12 @@ function VectorPage() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.vector)),
}}
/>
</Head>
<DefaultLayout className="bg-alternative!" stickyNavbar={false}>
<ModulesNav activePage={PRODUCT_MODULES_NAMES.VECTOR} docsUrl={pageData.docsUrl} />
+8 -1
View File
@@ -20,7 +20,8 @@ import { useRouter } from 'next/router'
import { PRODUCT_NAMES } from 'shared-data/products'
import { Button } from 'ui'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const SingleQuote = dynamic(() => import('~/components/Sections/SingleQuote'))
@@ -82,6 +83,12 @@ function RealtimePage() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.realtime)),
}}
/>
</Head>
<DefaultLayout>
<ProductsNav activePage={PRODUCT_NAMES.REALTIME} />
+8 -1
View File
@@ -19,7 +19,8 @@ import Solutions from '@/data/MainProducts'
import ApiExamples from '@/data/products/storage/api-examples'
import DashboardViewData from '@/data/products/storage/dashboard-carousel.json'
import StoragePermissionsData from '@/data/products/storage/permissions-examples'
import { serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
import { breadcrumbs } from '@/lib/breadcrumbs'
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
const APISection = dynamic(() => import('~/components/Sections/APISection'))
const SingleQuote = dynamic(() => import('~/components/Sections/SingleQuote'))
@@ -69,6 +70,12 @@ function StoragePage() {
),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.storage)),
}}
/>
</Head>
<DefaultLayout>
<ProductsNav activePage={PRODUCT_NAMES.STORAGE} />