mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 04:15:04 +03:00
## Summary Emits `BreadcrumbList` JSON-LD on every `/docs/guides/*` page served by `GuideTemplate`. Search engines and AI crawlers get an explicit hierarchical signal for the docs site (the marketing site already shipped JSON-LD via #45451). The chain prepends `Docs > Guides` to the existing resolver output, so a page like `/docs/guides/auth/passwords` produces a 5-level chain with the leaf URL set per Google's spec. ## Changes - New `apps/docs/lib/breadcrumbs.ts`: pure pathname → chain resolver, server-safe. Extracted from the existing client `useBreadcrumbs` hook so the same logic runs in both contexts. - New `apps/docs/lib/json-ld.ts`: `serializeJsonLd` + `breadcrumbListSchema` mirroring `apps/www/lib/json-ld.ts`. - `Breadcrumbs.tsx` (visual) now delegates to the shared resolver — single source of truth for visual + SEO chains. - `GuideTemplate` takes a required `pathname` prop and emits `<script type="application/ld+json">` next to `<Breadcrumbs />`. Skipped when the chain is empty (e.g., page not in nav menu). Middle items without URLs (e.g., the "Auth" section root) omit `item`, matching the visual breadcrumb. - 8 explicit-prop callers updated; `[[...slug]]` callers already spread `data` (which carries `pathname`). ## Scope **Out of scope:** - `/docs/reference/*` (SDK reference) — no breadcrumbs rendered today, would need separate traversal over spec JSON. - `/guides/troubleshooting/*` — uses its own template, not `GuideTemplate`. - `TechArticle` per-page schema — high maintenance for marginal value. ## Testing (Vercel preview) ```bash curl -s https://<preview>/docs/guides/auth/passwords | grep -oE '<script type="application/ld\+json"[^>]*>[^<]+</script>' ``` Expect a script tag with the chain `Docs > Guides > Auth > Flows (How-tos) > Password-based`, leaf URL `https://supabase.com/docs/guides/auth/passwords`. - [x] `/docs/guides/auth/passwords` — 5-item chain, leaf URL present - [x] `/docs/guides/getting-started/features` — 4-item chain, all items have URLs - [x] `/docs/guides/getting-started/ai-prompts/<slug>` — special-case chain (`Getting started > AI Tools > Prompts > <slug>`), leaf URL falls back to pathname - [x] `/docs/guides/database/database-advisors` (explicit-prop caller) — chain renders - [x] Visual breadcrumb on the same pages still renders correctly - [ ] Validate output through [Google Rich Results Test](https://search.google.com/test/rich-results) on a deployed preview URL - [x] `/docs/guides/troubleshooting/<slug>` — no JSON-LD emitted (different template, intentional) ## Linear - fixes GROWTH-820 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added JSON-LD breadcrumb markup to guide pages to improve search/discovery. * **Improvements** * Centralized breadcrumb generation for consistent, accurate breadcrumbs across guides. * Multiple guide pages updated to ensure breadcrumbs and page context display correctly. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { type TOCHeader } from '~/components/GuidesSidebar'
|
|
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
|
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
|
|
import type { Parameter } from '~/lib/refGenerator/refTypes'
|
|
import specFile from '~/spec/cli_v1_config.yaml' with { type: 'yml' }
|
|
import ReactMarkdown from 'react-markdown'
|
|
import { CodeBlock } from 'ui-patterns/CodeBlock'
|
|
import { Heading } from 'ui/src/components/CustomHTMLElements'
|
|
|
|
const meta = {
|
|
title: 'Supabase CLI config',
|
|
}
|
|
|
|
const generateMetadata = genGuideMeta(() => ({
|
|
pathname: '/guides/cli/config',
|
|
meta,
|
|
}))
|
|
|
|
const tocList: TOCHeader[] = []
|
|
const content = specFile.info.tags.map((tag: { id: string; title: string }, id: number) => {
|
|
tocList.push({ id: `${id}`, text: tag.title, link: `${tag.id}-config`, level: 2 })
|
|
return (
|
|
<div>
|
|
<Heading tag="h2">{tag.title} Config</Heading>
|
|
{specFile.parameters
|
|
.filter((param: Parameter) => param.tags && param.tags[0] === tag.id)
|
|
.map((parameter: Parameter, id: number) => {
|
|
tocList.push({ id: `${id}`, text: parameter.id, link: `#${parameter.id}`, level: 3 })
|
|
return <Info parameter={parameter} />
|
|
})}
|
|
</div>
|
|
)
|
|
})
|
|
|
|
const Config = () => {
|
|
const editLink = newEditLink('supabase/supabase/blob/master/apps/docs/spec/cli_v1_config.yaml')
|
|
|
|
return (
|
|
<GuideTemplate meta={meta} editLink={editLink} pathname="/guides/local-development/cli/config">
|
|
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
|
<div>{content}</div>
|
|
</GuideTemplate>
|
|
)
|
|
}
|
|
|
|
function Info({ parameter }: { parameter: Parameter }) {
|
|
return (
|
|
<div className="mt-8">
|
|
<div>
|
|
<Heading tag="h3" parseAnchors={false} customAnchor={parameter.id}>
|
|
<code>{parameter.title}</code>
|
|
</Heading>
|
|
|
|
<div className="border-b pb-8" key={parameter.id}>
|
|
<div className=" mb-16">
|
|
<div>
|
|
<table className="table-auto">
|
|
<thead>
|
|
<tr>
|
|
<th className="text-left">Name</th>
|
|
<th className="text-left">Default</th>
|
|
<th className="text-left">Required</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>{parameter.id}</td>
|
|
<td>{parameter.default ? parameter.default.toString() : 'None'}</td>
|
|
<td>{parameter.required !== undefined && parameter.required.toString()}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div className="mb-4 scroll-mt-16 mt-0 ">
|
|
<p className="text-sm font-bold uppercase">Description</p>
|
|
<ReactMarkdown>{parameter.description}</ReactMarkdown>
|
|
</div>
|
|
{parameter.usage && (
|
|
<div className="mb-4 scroll-mt-16 mt-0 ">
|
|
<p className="text-sm font-bold uppercase">Usage</p>
|
|
<CodeBlock className="useless-code-block-class" language="py">
|
|
{parameter.usage}
|
|
</CodeBlock>
|
|
</div>
|
|
)}
|
|
{parameter.links && (
|
|
<div>
|
|
<p className="text-sm font-bold uppercase">See also</p>
|
|
<ul>
|
|
{parameter.links.map((link) => (
|
|
<li key={link.link}>
|
|
<a href={link.link}>{link.name}</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default Config
|
|
export { generateMetadata }
|