blob: 01d1dd02c9fea7a7acad04ca396ff6ff9ee186fb [file]
// packages/ui/src/primitives/section-header.tsx
//
// Convergence round 5: the ONE "section title (+ count / subtitle) +
// trailing action" header. Before this, three dialects were hand-rolled:
// skills' span-row (label + N 个), daily-review's h4 with a colored
// accent bar, and permission's h4 + small + trailing button.
//
// Styled with package-owned semantic classes; call sites keep their wrapper
// call sites keep their wrapper classes for page-pinned CSS placement.
import type { ReactNode } from 'react';
import { cn } from '../utils.js';
export interface SectionHeaderProps {
title: ReactNode;
/** `id` on the title element, for a section's `aria-labelledby` link. */
titleId?: string;
/** Muted trailing count (e.g. "3 个" / "2 份"). */
count?: ReactNode;
/** One quiet line under the title (permission's layer explainer). */
subtitle?: ReactNode;
/** Right-aligned action cluster (button / filter pills). */
action?: ReactNode;
/** Leading accent bar (daily-review's section marker). */
accent?: boolean;
/** Heading level for the title, or a non-heading `span`. `h3` is for a
* section that sits directly under a page `h2` (关于 privacy, 数据 config). */
as?: 'h3' | 'h4' | 'span';
className?: string;
}
export function SectionHeader({
title,
titleId,
count,
subtitle,
action,
accent = false,
as: Tag = 'span',
className,
}: SectionHeaderProps) {
return (
<div
className={cn('maka-section-header', className)}
data-slot="section-header"
>
<div className="maka-section-header-content">
<Tag
id={titleId}
className={cn(
'maka-section-header-title',
accent && 'maka-section-header-title-accent',
)}
data-slot="section-header-title"
>
{title}
{count != null && (
<small
className="maka-section-header-count"
data-slot="section-header-count"
>
{count}
</small>
)}
</Tag>
{subtitle != null && (
<small
className="maka-section-header-subtitle"
data-slot="section-header-subtitle"
>
{subtitle}
</small>
)}
</div>
{action != null && (
<div className="maka-section-header-action" data-slot="section-header-action">
{action}
</div>
)}
</div>
);
}