Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 0 additions & 37 deletions frontend/src/components/PageHeader.module.css

This file was deleted.

44 changes: 29 additions & 15 deletions frontend/src/components/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ReactNode } from 'react';
import s from './PageHeader.module.css';
import { Cluster, Heading, Stack, Text } from '../design-system';

interface Props {
title: string;
Expand All @@ -8,27 +8,41 @@ interface Props {
breadcrumbs?: ReactNode;
}

/**
* Section / page header — title, optional subtitle, optional inline actions,
* optional breadcrumb slot above. Built entirely from design-system primitives;
* no local CSS, no hard-coded sizes or colors.
*
* Public API unchanged from the legacy implementation: every consumer that
* passes `{title, subtitle, actions, breadcrumbs}` keeps working as-is.
*/
export default function PageHeader({ title, subtitle, actions, breadcrumbs }: Props) {
return (
<div>
{breadcrumbs && <div className={s.spaced}>{breadcrumbs}</div>}
<div className={s.flex_between}>
<div>
<h1 className={s.text22}>
{title}
</h1>
<Stack as="header" gap="3" style={{ marginBottom: 'var(--space-6)' }}>
{breadcrumbs}
<Cluster
align="start"
justify="between"
gap="4"
style={{
paddingBottom: 'var(--space-5)',
borderBottom: '1px solid var(--border)',
}}
>
<Stack gap="1">
<Heading level={1}>{title}</Heading>
{subtitle && (
<p className={s.text13}>
<Text size="sm" tone="tertiary">
{subtitle}
</p>
</Text>
)}
</div>
</Stack>
{actions && (
<div className={s.flex_center}>
<Cluster gap="2" align="center">
{actions}
</div>
</Cluster>
)}
</div>
</div>
</Cluster>
</Stack>
);
}
30 changes: 28 additions & 2 deletions frontend/src/components/__tests__/PageHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { render, screen } from '@testing-library/react';
import PageHeader from '../PageHeader';

describe('PageHeader', () => {
it('renders the title', () => {
it('renders the title as a semantic <h1>', () => {
render(<PageHeader title="Test Title" />);
expect(screen.getByText('Test Title')).toBeInTheDocument();
const heading = screen.getByRole('heading', { level: 1, name: 'Test Title' });
expect(heading).toBeInTheDocument();
});

it('renders the subtitle when provided', () => {
Expand All @@ -17,4 +18,29 @@ describe('PageHeader', () => {
render(<PageHeader title="Title Only" />);
expect(screen.queryByText(/subtitle/i)).not.toBeInTheDocument();
});

it('renders actions when provided', () => {
render(
<PageHeader
title="With actions"
actions={<button type="button">Do thing</button>}
/>,
);
expect(screen.getByRole('button', { name: 'Do thing' })).toBeInTheDocument();
});

it('renders breadcrumbs slot when provided', () => {
render(
<PageHeader
title="Crumbs"
breadcrumbs={<nav aria-label="breadcrumb">crumbs-here</nav>}
/>,
);
expect(screen.getByLabelText('breadcrumb')).toHaveTextContent('crumbs-here');
});

it('wraps the header in a semantic <header> element', () => {
const { container } = render(<PageHeader title="x" />);
expect(container.querySelector('header')).not.toBeNull();
});
});
Loading