Files
supabase/apps/docs/components/Breadcrumbs.tsx
T
6851d7a5ba fix(design-system): missing path and deps (#38307)
* Refactor Drawer component and add date-fns dependency

Refactored the Drawer component for improved slot-based structure, updated styles, and added 'use client' directive. Added 'date-fns' as a dependency in design-system, updated tsconfig paths for icons, and marked ToggleGroup as a client component.

* nit: add env for svg path

* fix: instructions

* chore: new generated llms

* Rebuild the pnpm-lock file.

* fix: update vaul dep in ui for drawer

* chore: update radix dialog deps

* fix: clipPath prop on chart tooltip svg

* fix: update dialog deps

* fix: update hover card deps

* fix: remove legacy next link from nav menu docs

* fix: radio group dep update

* fix: scroll area example key

* fix: sheet form readOnly

* fix: slider dep update

* fix: hide empty toast view

* fix: toggle and toggle group dep update

* Rebuild the lockfile.

* chore: updating branch

* fix: remove unused prop in docs

Removes unused prop on Drawer component inside docs causing type error

* Update apps/design-system/registry/default/example/scroll-area-demo.tsx

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>

* chore: remove commented out menu item

* chore: remove types/node in common

---------

Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-09-02 09:54:06 +01:00

203 lines
6.5 KiB
TypeScript

'use client'
import Link from 'next/link'
import { usePathname, useSearchParams } from 'next/navigation'
import React, { Fragment, Suspense } from 'react'
import { useBreakpoint } from 'common'
import {
Breadcrumb_Shadcn_ as Breadcrumb,
BreadcrumbList_Shadcn_ as BreadcrumbList,
BreadcrumbItem_Shadcn_ as BreadcrumbItem,
BreadcrumbLink_Shadcn_ as BreadcrumbLink,
BreadcrumbSeparator_Shadcn_ as BreadcrumbSeparator,
BreadcrumbPage_Shadcn_ as BreadcrumbPage,
BreadcrumbEllipsis_Shadcn_ as BreadcrumbEllipsis,
Button,
cn,
Drawer,
DrawerClose,
DrawerContent,
DrawerFooter,
DrawerTrigger,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from 'ui'
import * as NavItems from '~/components/Navigation/NavigationMenu/NavigationMenu.constants'
import { getMenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu.utils'
interface BreadcrumbsProps extends React.HTMLAttributes<HTMLDivElement> {
minLength?: number
forceDisplayOnMobile?: boolean
}
export default function Breadcrumbs(props: BreadcrumbsProps) {
return (
<Suspense>
<BreadcrumbsInternal {...props} />
</Suspense>
)
}
const BreadcrumbsInternal = ({
className,
minLength = 2,
forceDisplayOnMobile = false,
}: BreadcrumbsProps) => {
const breadcrumbs = useBreadcrumbs()
const [open, setOpen] = React.useState(false)
const isMobile = useBreakpoint('md')
const ITEMS_TO_DISPLAY = isMobile ? 4 : 3
if (!breadcrumbs?.length || breadcrumbs?.length < minLength) return null
const appendedBreadcrumbs = breadcrumbs?.slice(
-ITEMS_TO_DISPLAY + 1,
isMobile && !forceDisplayOnMobile ? -1 : undefined
)
return (
<Breadcrumb className={cn(className)}>
<BreadcrumbList className="text-foreground-lighter p-0">
{breadcrumbs.length >= ITEMS_TO_DISPLAY && (
<>
<BreadcrumbItem>
{breadcrumbs[0].url ? (
<BreadcrumbLink asChild>
<Link href={breadcrumbs[0].url}>
{breadcrumbs[0].title || breadcrumbs[0].name}
</Link>
</BreadcrumbLink>
) : (
<BreadcrumbPage>{breadcrumbs[0].title || breadcrumbs[0].name}</BreadcrumbPage>
)}
</BreadcrumbItem>
<BreadcrumbSeparator />
</>
)}
{breadcrumbs.length > ITEMS_TO_DISPLAY && (
<>
<BreadcrumbItem>
{!isMobile ? (
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger className="flex items-center gap-1" aria-label="Toggle menu">
<BreadcrumbEllipsis className="h-4 w-4" />
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
{breadcrumbs.slice(1, -2).map((crumb, index) => (
<DropdownMenuItem
key={index}
className={cn(!crumb.url && 'pointer-events-none')}
>
{crumb.url ? (
<Link href={crumb.url}>{crumb.title || crumb.name}</Link>
) : (
crumb.title || crumb.name
)}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : (
<Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger aria-label="Toggle Menu">
<BreadcrumbEllipsis className="h-4 w-4" />
</DrawerTrigger>
<DrawerContent>
<div className="grid gap-1 px-4">
{breadcrumbs.slice(1, -2).map((crumb, index) =>
crumb.url ? (
<Link key={index} href={crumb.url}>
{crumb.title || crumb.name}
</Link>
) : (
crumb.title || crumb.name
)
)}
</div>
<DrawerFooter className="pt-4">
<DrawerClose asChild>
<Button type="outline">Close</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
)}
</BreadcrumbItem>
<BreadcrumbSeparator />
</>
)}
{appendedBreadcrumbs?.map((crumb, index) => (
<Fragment key={index}>
<BreadcrumbItem
className={cn(
'flex items-center overflow-hidden',
index === appendedBreadcrumbs.length - 1 && 'md:text-foreground-light'
)}
>
{crumb.url ? (
<BreadcrumbLink asChild>
<Link href={crumb.url}>{crumb.title || crumb.name}</Link>
</BreadcrumbLink>
) : (
<BreadcrumbPage>{crumb.title || crumb.name}</BreadcrumbPage>
)}
</BreadcrumbItem>
<BreadcrumbSeparator
className={cn(index === appendedBreadcrumbs.length - 1 && 'md:hidden')}
/>
</Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
)
}
function useBreadcrumbs() {
const pathname = usePathname()
const isTroubleshootingPage = pathname.startsWith('/guides/troubleshooting')
if (isTroubleshootingPage) {
const breadcrumbs = [{ name: 'Troubleshooting', url: '/guides/troubleshooting' }]
return breadcrumbs
}
const isAiPromptsPage = pathname.startsWith('/guides/getting-started/ai-prompts')
if (isAiPromptsPage) {
const breadcrumbs = [
{ name: 'Getting started', url: '/guides/getting-started' },
{ name: 'AI Tools' },
{ name: 'Prompts', url: '/guides/getting-started/ai-prompts' },
]
return breadcrumbs
}
const menuId = getMenuId(pathname)
const menu = NavItems[menuId]
return findMenuItemByUrl(menu, pathname, [])
}
function findMenuItemByUrl(menu: any, targetUrl: string, parents: any[] = []) {
// If the menu has items, recursively search through them
if (menu.items) {
for (let item of menu.items) {
const result = findMenuItemByUrl(item, targetUrl, [...parents, menu])
if (result) {
return result
}
}
}
// Check if the current menu object itself has the target URL
if (menu.url === targetUrl) {
return [...parents, menu]
}
// If the URL is not found, return null
return null
}