Ctrl K
ComunidadGuías…

components/PageHeader.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
'use client';

import { truncateWord } from '@/utils/text';
import React, { PropsWithChildren, ReactNode } from 'react';
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from '@/components/ui/breadcrumb';
import Link from 'next/link';

type PageHeader = {
  title?: string | null;
  titleSlot?: ReactNode; // replaces the title text, e.g. an inline editor
  description?: string | null;
  imageUrl?: string | null;
  coverSlot?: ReactNode; // pinned to the cover's top-end corner, e.g. an edit control
  breadcrumbs?: Array<{ name: string; href: string }>;
};

export default function PageHeader({
  ...props
}: PropsWithChildren<PageHeader>) {
  return (
    <div className="relative border-b border-border bg-background overflow-hidden">
      {/* Decorative background elements */}
      <div className="absolute top-0 right-0 -translate-y-1/2 translate-x-1/2 w-96 h-96 bg-primary/5 rounded-full blur-3xl transform-gpu pointer-events-none" />
      <div className="absolute bottom-0 left-0 translate-y-1/2 -translate-x-1/2 w-64 h-64 bg-primary/3 rounded-full blur-2xl transform-gpu pointer-events-none" />

      {props.imageUrl && (
        <div className="absolute inset-0 z-0 pointer-events-none">
          <div
            className="absolute inset-0 bg-cover bg-center opacity-25"
            style={{ backgroundImage: `url(${props.imageUrl})` }}
          />
          <div className="absolute inset-0 bg-gradient-to-r from-background to-transparent" />
        </div>
      )}

      {props.coverSlot && (
        <div className="absolute top-3 end-3 z-20">{props.coverSlot}</div>
      )}

      <div className="relative z-10 max-w-7xl mx-auto px-4 md:px-6 lg:px-8 py-4 md:py-10">
        <div
          className="flex flex-col md:flex-row md:items-end md:justify-between gap-6"
        >
          <div className="flex-1 space-y-4 min-w-0">
            {props.breadcrumbs && (
              <Breadcrumb>
                <BreadcrumbList className="flex-wrap text-[12px] font-[600] uppercase tracking-wider text-muted-foreground">
                  {props.breadcrumbs.map((item, index, arr) => (
                    <React.Fragment key={index}>
                      <BreadcrumbItem className="min-w-0">
                        {index < arr.length - 1 ? (
                          <BreadcrumbLink
                            asChild
                            className="hover:text-foreground transition-colors overflow-hidden text-ellipsis"
                          >
                            <Link href={item.href}>
                              {truncateWord(item.name, 20)}
                            </Link>
                          </BreadcrumbLink>
                        ) : (
                          <BreadcrumbPage className="text-foreground/80 overflow-hidden text-ellipsis">
                            {truncateWord(item.name, 20)}
                          </BreadcrumbPage>
                        )}
                      </BreadcrumbItem>
                      {index < arr.length - 1 && <BreadcrumbSeparator />}
                    </React.Fragment>
                  ))}
                </BreadcrumbList>
              </Breadcrumb>
            )}

            <div className="space-y-2">
              <h1
                className="text-3xl md:text-4xl lg:text-[42px] font-[800] tracking-tight text-foreground leading-[0.95] break-words"
                title={props.title ?? ''}
              >
                {props.titleSlot ? (
                  props.titleSlot
                ) : props.title ? (
                  truncateWord(props.title, 50)
                ) : (
                  <span className="text-muted-foreground/70 animate-pulse">
                    Loading...
                  </span>
                )}
              </h1>
              {props.description && (
                <p className="text-sm md:text-[16px] text-foreground/80 max-w-2xl font-[450] leading-relaxed">
                  {props.description}
                </p>
              )}
            </div>
          </div>

          {props.children && (
            <div
              className="flex items-center gap-1.5 sm:gap-3 bg-muted/50 p-1.5 rounded-[20px] border border-border backdrop-blur-sm self-start md:self-end w-full md:w-auto overflow-hidden"
            >
              {props.children}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}