mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
chore(design-system): better breadcrumbs (#42310)
## What kind of change does this PR introduce? Minor update ## What is the current behavior? Our design system’s breadcrumbs: 1. Are not interactive 2. ~~Repeat the page title, which is directly below~~ ## What is the new behavior? These breadcrumbs: - Are hyperlinked - Show all parents, if nested - ~~Don’t repeat the page title~~ | Before | After | | --- | --- | | <img width="1024" height="756" alt="Forms-FBDF180F-F101-407C-A8EB-A06BBDB3509A" src="https://github.com/user-attachments/assets/f2592b8b-b5d4-415f-af2e-28b99d5de0a0" /> | <img width="1024" height="794" alt="Forms-95348190-C8B2-4A3A-AE55-A4A5A16CD4B4" src="https://github.com/user-attachments/assets/7b296c20-b12a-48ff-9479-6547cda73cd5" /> | ## Additional context I wonder if we should either drop the `/docs/` subdirectory or rename it. The latter would make sense if we split, say, `/product/` from `/icons/` and/or `/brand`. [Primer](https://primer.style/octicons/design-guidelines/) does this well.
This commit is contained in:
1 parent
f5667ac450
commit
57dde08672
2 files changed
+55
-6
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { Mdx } from '@/components/mdx-components'
|
||||
import { DocsPager } from '@/components/pager'
|
||||
import { DocsPager, getBreadcrumbSegments } from '@/components/pager'
|
||||
import { SourcePanel } from '@/components/source-panel'
|
||||
import { DashboardTableOfContents } from '@/components/toc'
|
||||
import { siteConfig } from '@/config/site'
|
||||
@@ -12,6 +12,7 @@ import '@/styles/mdx.css'
|
||||
import { allDocs } from 'contentlayer/generated'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { notFound } from 'next/navigation'
|
||||
import Balancer from 'react-wrap-balancer'
|
||||
import { ScrollArea, Separator } from 'ui'
|
||||
@@ -83,15 +84,39 @@ export default async function DocPage(props: DocPageProps) {
|
||||
}
|
||||
|
||||
const toc = await getTableOfContents(doc.body.raw)
|
||||
const breadcrumbSegments = getBreadcrumbSegments(doc)
|
||||
|
||||
return (
|
||||
<div className="relative xl:grid xl:grid-cols-[1fr_160px] gap-4 px-6 py-6 lg:py-8">
|
||||
<div className="mx-auto w-full min-w-0 max-w-4xl flex-1">
|
||||
<div className="mb-4 flex items-center space-x-1 text-sm text-foreground-muted">
|
||||
<div className="overflow-hidden text-ellipsis whitespace-nowrap">Docs</div>
|
||||
<ChevronRight className="h-4 w-4 text-foreground-muted" />
|
||||
<div className="text-foreground-lighter">{doc.title}</div>
|
||||
</div>
|
||||
<nav
|
||||
className="mb-4 flex items-center space-x-1 text-sm text-foreground-lighter"
|
||||
aria-label="Breadcrumb"
|
||||
>
|
||||
{breadcrumbSegments.map((segment, index) => (
|
||||
<span key={segment.title} className="flex items-center gap-1">
|
||||
{index > 0 && <ChevronRight className="h-4 w-4 shrink-0 text-foreground-muted" />}
|
||||
{segment.href ? (
|
||||
<Link
|
||||
href={segment.href}
|
||||
className="overflow-hidden text-ellipsis whitespace-nowrap hover:text-foreground transition-colors"
|
||||
>
|
||||
{segment.title}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="overflow-hidden text-ellipsis whitespace-nowrap text-foreground-lighter">
|
||||
{segment.title}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
))}
|
||||
{breadcrumbSegments.length > 0 && (
|
||||
<ChevronRight className="h-4 w-4 shrink-0 text-foreground-muted/50" />
|
||||
)}
|
||||
<span className="overflow-hidden text-ellipsis whitespace-nowrap text-foreground-muted">
|
||||
{doc.title}
|
||||
</span>
|
||||
</nav>
|
||||
<div className="space-y-2 mb-5">
|
||||
<h1 className="scroll-m-20 text-4xl tracking-tight">{doc.title}</h1>
|
||||
{doc.description && (
|
||||
|
||||
@@ -71,3 +71,27 @@ export function flatten(links: NavItemWithChildren[]): NavItem[] {
|
||||
}, [])
|
||||
.filter((link) => !link?.disabled)
|
||||
}
|
||||
|
||||
export interface BreadcrumbSegment {
|
||||
title: string
|
||||
href?: string
|
||||
}
|
||||
|
||||
export function getBreadcrumbSegments(doc: Doc): BreadcrumbSegment[] {
|
||||
const segments: BreadcrumbSegment[] = [{ title: 'Docs', href: '/docs' }]
|
||||
|
||||
for (const section of docsConfig.sidebarNav) {
|
||||
const flatItems = flatten(section.items ?? [])
|
||||
const inSection = flatItems.some((item) => item.href === doc.slug)
|
||||
if (!inSection || !section.title) continue
|
||||
|
||||
const sectionLanding = flatItems.find((item) => item.priority) ?? flatItems[0]
|
||||
const isOnLanding = sectionLanding?.href === doc.slug
|
||||
if (sectionLanding?.href && !isOnLanding) {
|
||||
segments.push({ title: section.title, href: sectionLanding.href })
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return segments
|
||||
}
|
||||
Reference in new issue
Block a user