mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
* 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>
203 lines
6.5 KiB
TypeScript
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
|
|
}
|