{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "page-header",
  "title": "Page Header",
  "author": "AniBT <https://anibt.net>",
  "description": "AniBT section head in one compact row: a tilted sticker mark, the 20/800 title, a figure in the round face, an ellipsised description and the page's tool group.",
  "registryDependencies": [
    "@anibt/theme"
  ],
  "files": [
    {
      "path": "registry/anibt/ui/page-header.tsx",
      "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * PageHeader — the AniBT 「贴纸手账」 section head: one compact row.\n *\n * An optional section mark (a small white sticker tilted −4°, the glyph in\n * pink; it tips the other way under the pointer) → the title at 20/800 → a\n * figure in the round face (`2,184 部`) → a 12px muted description that\n * ellipsises beside the title and hides below `lg` → then, pushed right, the\n * tool group: the page's own tabs, its controls and its one candy action.\n *\n * Nothing in the title cluster wraps. Below `md` the tool group takes its own\n * full-width line and scrolls sideways (with a fade at the right edge) rather\n * than folding — so a header never grows a tall empty band.\n *\n * `compact` is the denser workbench head (18px title, 24px mark).\n * `headingLevel` keeps the outline honest when a shell already prints an h1.\n */\ntype PageHeaderProps = Omit<React.ComponentProps<\"header\">, \"title\"> & {\n  /** The section mark: a lucide icon component, or any node (an emoji, an svg). */\n  icon?: React.ComponentType<{ className?: string }> | React.ReactNode\n  /** `time` paints the mark blue — for a schedule, a timetable, \"now\". */\n  iconTone?: \"mark\" | \"time\"\n  title: React.ReactNode\n  /** The figure beside the title: `2,184 部`, `12 条`. */\n  meta?: React.ReactNode\n  description?: React.ReactNode\n  /** The page's own tabs, at the left of the tool group. */\n  tabs?: React.ReactNode\n  /** Search, filters, sort. */\n  toolbar?: React.ReactNode\n  /** The page's buttons, at the right end. */\n  actions?: React.ReactNode\n  compact?: boolean\n  headingLevel?: \"h1\" | \"h2\" | \"h3\"\n}\n\nfunction PageHeader({\n  icon,\n  iconTone = \"mark\",\n  title,\n  meta,\n  description,\n  tabs,\n  toolbar,\n  actions,\n  compact = false,\n  headingLevel: Heading = \"h1\",\n  className,\n  children,\n  ...props\n}: PageHeaderProps) {\n  const hasTools = Boolean(tabs || toolbar || actions)\n\n  return (\n    <header\n      data-slot=\"page-header\"\n      data-compact={compact ? \"true\" : undefined}\n      className={cn(\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2\", compact ? \"pb-2\" : \"pb-3\", className)}\n      {...props}\n    >\n      <div data-slot=\"page-header-title\" className=\"group/page-header flex min-w-0 flex-1 items-center gap-3\">\n        {icon ? <PageHeaderMark icon={icon} tone={iconTone} size={compact ? \"sm\" : \"default\"} /> : null}\n        <Heading\n          className={cn(\n            \"shrink-0 font-extrabold tracking-[0.02em] whitespace-nowrap text-foreground\",\n            compact ? \"text-[18px] leading-7\" : \"text-[20px] leading-7\"\n          )}\n        >\n          {title}\n        </Heading>\n        {meta ? <span className=\"anibt-num shrink-0 text-[12px] whitespace-nowrap text-muted-foreground\">{meta}</span> : null}\n        {description ? (\n          <p className=\"anibt-ell hidden text-[12px] text-muted-foreground lg:block\">{description}</p>\n        ) : null}\n      </div>\n\n      {hasTools ? (\n        <div\n          data-slot=\"page-header-tools\"\n          className={cn(\n            \"-my-1 flex w-full min-w-0 items-center gap-2 overflow-x-auto py-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\",\n            toolbar && \"[mask-image:linear-gradient(to_right,black_0%,black_92%,transparent_100%)]\",\n            \"md:ml-auto md:w-auto md:shrink-0 md:overflow-x-visible md:[mask-image:none]\"\n          )}\n        >\n          {tabs}\n          {toolbar ? <div className=\"flex shrink-0 items-center gap-2\">{toolbar}</div> : null}\n          {actions ? <div className=\"flex shrink-0 items-center gap-2\">{actions}</div> : null}\n        </div>\n      ) : null}\n\n      {children ? <div className=\"w-full min-w-0\">{children}</div> : null}\n    </header>\n  )\n}\n\n/**\n * The section mark on its own: a 28px white sticker (24 in `sm`), tilted, the\n * glyph in pink (or blue with `tone=\"time\"`). It tips the other way when the\n * pointer is on its header. Decorative.\n */\nfunction PageHeaderMark({\n  icon,\n  tone = \"mark\",\n  size = \"default\",\n  className,\n}: {\n  icon: React.ComponentType<{ className?: string }> | React.ReactNode\n  tone?: \"mark\" | \"time\"\n  size?: \"sm\" | \"default\"\n  className?: string\n}) {\n  const content = isComponent(icon) ? React.createElement(icon, { className: \"size-4\" }) : icon\n  return (\n    <span\n      data-slot=\"page-header-mark\"\n      aria-hidden=\"true\"\n      className={cn(\n        \"anibt-rim flex shrink-0 -rotate-[4deg] items-center justify-center rounded-[6px] bg-card transition-transform duration-[400ms] ease-anibt-spring group-hover/page-header:scale-105 group-hover/page-header:rotate-[4deg] [&_svg]:size-4\",\n        tone === \"time\" ? \"text-anibt-time\" : \"text-anibt-mark\",\n        size === \"sm\" ? \"size-6\" : \"size-7\",\n        className\n      )}\n    >\n      {content}\n    </span>\n  )\n}\n\nfunction isComponent(value: unknown): value is React.ComponentType<{ className?: string }> {\n  return (\n    typeof value === \"function\" ||\n    (typeof value === \"object\" && value !== null && \"$$typeof\" in value && !React.isValidElement(value))\n  )\n}\n\nexport { PageHeader, PageHeaderMark }\nexport type { PageHeaderProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "layout"
  ],
  "type": "registry:ui"
}