Download src/components/shared/SharedSectionHeader.tsx from asnannp/DocDoeAI: direct link, hf CLI and curl.
- Browser
- Download file 4.87 kB
-
https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/components/shared/SharedSectionHeader.tsx
- Command line
-
hf download hf://spaces/asnannp/DocDoeAI/src/components/shared/SharedSectionHeader.tsx
-
curl -L -o SharedSectionHeader.tsx https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/components/shared/SharedSectionHeader.tsx
4.87 kB
| "use client"; | |
| import { HTMLAttributes } from "react"; | |
| import { clsx } from "clsx"; | |
| // ============================================================================= | |
| // SectionHeader Types | |
| // ============================================================================= | |
| export interface SectionHeaderProps extends HTMLAttributes<HTMLDivElement> { | |
| title: string; | |
| subtitle?: string; | |
| actionText?: string; | |
| actionHref?: string; | |
| actionOnClick?: () => void; | |
| icon?: React.ReactNode; | |
| titleSize?: "page" | "section" | "card" | "small"; | |
| showDivider?: boolean; | |
| } | |
| export interface PageHeaderProps extends SectionHeaderProps { | |
| backHref?: string; | |
| backText?: string; | |
| actionSlot?: React.ReactNode; | |
| } | |
| // ============================================================================= | |
| // SharedSectionHeader Component | |
| // ============================================================================= | |
| export function SharedSectionHeader({ | |
| title, | |
| subtitle, | |
| actionText, | |
| actionHref, | |
| actionOnClick, | |
| icon, | |
| titleSize = "section", | |
| showDivider = false, | |
| className, | |
| ...props | |
| }: SectionHeaderProps) { | |
| // Map title size to styles | |
| const titleStyles = { | |
| page: { | |
| className: "text-[26px] font-bold tracking-[-0.02em] text-[var(--text-primary)]", | |
| }, | |
| section: { | |
| className: "text-[24px] font-bold tracking-[-0.02em] text-[var(--text-primary)]", | |
| }, | |
| card: { | |
| className: "text-[18px] font-bold text-[var(--text-primary)]", | |
| }, | |
| small: { | |
| className: "text-[15px] font-semibold text-[var(--text-primary)]", | |
| }, | |
| }; | |
| const style = titleStyles[titleSize]; | |
| return ( | |
| <div className={clsx("space-y-4", className)} {...props}> | |
| <div className="flex items-start justify-between gap-4"> | |
| <div className="flex items-center gap-3"> | |
| {icon && ( | |
| <div className="grid size-8 shrink-0 place-items-center rounded-md bg-[var(--accent-primary)]/10"> | |
| {icon} | |
| </div> | |
| )} | |
| <div> | |
| <h2 className={style.className}>{title}</h2> | |
| {subtitle && ( | |
| <p className="mt-1 text-[14px] leading-relaxed text-[var(--text-secondary)]"> | |
| {subtitle} | |
| </p> | |
| )} | |
| </div> | |
| </div> | |
| {(actionText || actionHref || actionOnClick) && ( | |
| <div className="flex items-center"> | |
| {actionHref ? ( | |
| <a | |
| href={actionHref} | |
| className="text-[13px] font-semibold text-[var(--accent-primary)] hover:underline" | |
| > | |
| {actionText} | |
| </a> | |
| ) : actionOnClick ? ( | |
| <button | |
| type="button" | |
| onClick={actionOnClick} | |
| className="text-[13px] font-semibold text-[var(--accent-primary)] hover:underline" | |
| > | |
| {actionText} | |
| </button> | |
| ) : null} | |
| </div> | |
| )} | |
| </div> | |
| {showDivider ? <div className="h-px w-full bg-[var(--border-subtle)]" aria-hidden="true" /> : null} | |
| </div> | |
| ); | |
| } | |
| // ============================================================================= | |
| // Section Label (uppercase small label) | |
| // ============================================================================= | |
| export function SectionLabel({ | |
| children, | |
| className, | |
| accent = false, | |
| ...props | |
| }: HTMLAttributes<HTMLParagraphElement> & { accent?: boolean }) { | |
| return ( | |
| <p | |
| className={clsx( | |
| "text-[11px] font-bold uppercase tracking-wider", | |
| accent ? "text-[var(--accent-primary)]" : "text-[var(--text-muted)]", | |
| className, | |
| )} | |
| {...props} | |
| > | |
| {children} | |
| </p> | |
| ); | |
| } | |
| // ============================================================================= | |
| // Page Header (with back link option) | |
| // ============================================================================= | |
| export function PageHeader({ | |
| title, | |
| subtitle, | |
| backHref, | |
| backText = "Back", | |
| actionSlot, | |
| className, | |
| ...props | |
| }: PageHeaderProps) { | |
| return ( | |
| <div className={clsx("space-y-2", className)} {...props}> | |
| {backHref && ( | |
| <a | |
| href={backHref} | |
| className="inline-flex items-center gap-1.5 text-[12px] text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition" | |
| > | |
| ← {backText} | |
| </a> | |
| )} | |
| <div className="flex items-center justify-between gap-4"> | |
| <div className="flex items-center gap-3"> | |
| <div> | |
| <h2 className="text-[26px] font-bold tracking-[-0.02em] text-[var(--text-primary)]">{title}</h2> | |
| {subtitle && ( | |
| <p className="mt-1 text-[14px] leading-relaxed text-[var(--text-secondary)]"> | |
| {subtitle} | |
| </p> | |
| )} | |
| </div> | |
| </div> | |
| {actionSlot && <div className="flex gap-2">{actionSlot}</div>} | |
| </div> | |
| </div> | |
| ); | |
| } | |