| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import { useParams } from 'common'
- import { ChevronLeft } from 'lucide-react'
- import Link from 'next/link'
- import { Fragment, ReactNode } from 'react'
- import { cn } from 'ui'
- import {
- Breadcrumb,
- BreadcrumbItem,
- BreadcrumbLink,
- BreadcrumbList,
- BreadcrumbPage as BreadcrumbPageItem,
- BreadcrumbSeparator,
- } from 'ui/src/components/shadcn/ui/breadcrumb'
- import { ScaffoldDescription, ScaffoldTitle } from '../Scaffold'
- interface PageHeaderProps {
- title?: string | ReactNode
- subtitle?: string | ReactNode
- icon?: ReactNode
- breadcrumbs?: Array<{
- label?: string
- href?: string
- element?: ReactNode
- }>
- primaryActions?: ReactNode
- secondaryActions?: ReactNode
- className?: string
- isCompact?: boolean
- }
- export const PageHeader = ({
- title,
- subtitle,
- icon,
- breadcrumbs = [],
- primaryActions,
- secondaryActions,
- className,
- isCompact = false,
- }: PageHeaderProps) => {
- const { ref } = useParams()
- const displayBreadcrumbs = isCompact && title ? [...breadcrumbs, { label: title }] : breadcrumbs
- return (
- <div className={cn('space-y-4', className)}>
- {(displayBreadcrumbs.length > 0 ||
- (isCompact && (title || primaryActions || secondaryActions))) && (
- <div className={cn('flex items-center gap-4', isCompact ? 'justify-between' : 'mb-4')}>
- <div className="flex items-center gap-4 flex-1 min-w-0">
- {breadcrumbs.length > 0 ? (
- <Breadcrumb
- className={cn('text-foreground-muted', isCompact && 'text-base', 'min-w-0 flex-1')}
- >
- <BreadcrumbList className={cn(isCompact ? 'text-base' : 'text-xs', 'min-w-0')}>
- {breadcrumbs.map((item, index) => (
- <Fragment key={item.label || `breadcrumb-${index}`}>
- <BreadcrumbItem>
- {item.element ? (
- item.element
- ) : item.href ? (
- <BreadcrumbLink asChild className="flex items-center gap-2">
- <Link href={!!ref ? item.href.replace('[ref]', ref) : item.href}>
- {breadcrumbs.length === 1 && !isCompact && (
- <ChevronLeft size={16} strokeWidth={1.5} />
- )}
- {item.label}
- </Link>
- </BreadcrumbLink>
- ) : (
- <BreadcrumbPageItem className="flex items-center gap-2">
- {breadcrumbs.length === 1 && (
- <ChevronLeft size={16} strokeWidth={1.5} />
- )}
- {item.label}
- </BreadcrumbPageItem>
- )}
- </BreadcrumbItem>
- {index < breadcrumbs.length - 1 && <BreadcrumbSeparator />}
- </Fragment>
- ))}
- {isCompact && title && (
- <>
- <BreadcrumbSeparator />
- <BreadcrumbItem className="min-w-0 flex-1">
- <BreadcrumbPageItem className="min-w-0">{title}</BreadcrumbPageItem>
- </BreadcrumbItem>
- </>
- )}
- </BreadcrumbList>
- </Breadcrumb>
- ) : isCompact ? (
- <div className="min-w-0 flex-1">{title}</div>
- ) : null}
- </div>
- {isCompact && (
- <div className="flex items-center gap-2 shrink-0">
- {secondaryActions && (
- <div className="flex items-center gap-2">{secondaryActions}</div>
- )}
- {primaryActions && <div className="flex items-center gap-2">{primaryActions}</div>}
- </div>
- )}
- </div>
- )}
- {!isCompact && (
- <div className="flex items-center justify-between gap-4">
- <div className="space-y-4">
- <div className="flex items-center gap-4">
- {icon && <div className="text-foreground-light">{icon}</div>}
- <div className="space-y-1">
- {title &&
- (typeof title === 'string' ? <ScaffoldTitle>{title}</ScaffoldTitle> : title)}
- {subtitle &&
- (typeof subtitle === 'string' ? (
- <ScaffoldDescription className="text-sm text-foreground-light">
- {subtitle}
- </ScaffoldDescription>
- ) : (
- subtitle
- ))}
- </div>
- </div>
- </div>
- <div className="flex items-center gap-2">
- {secondaryActions && <div className="flex items-center gap-2">{secondaryActions}</div>}
- {primaryActions && <div className="flex items-center gap-2">{primaryActions}</div>}
- </div>
- </div>
- )}
- </div>
- )
- }
|