diff --git a/frontend/src/components/PageHeader.module.css b/frontend/src/components/PageHeader.module.css deleted file mode 100644 index 60d9cd63..00000000 --- a/frontend/src/components/PageHeader.module.css +++ /dev/null @@ -1,37 +0,0 @@ -.spaced { - margin-bottom: 8px; -} - -.flex_between { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: 24px; - padding-bottom: 20px; - border-bottom: 1px solid var(--border); -} - -.text22 { - margin: 0; - font-size: 26px; - font-weight: 700; - background: linear-gradient(180deg, #fff, rgba(255, 255, 255, 0.6)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - letter-spacing: -0.03em; - line-height: 1.15; -} - -.text13 { - margin: 4px 0 0; - font-size: 13px; - color: var(--text-tertiary); - font-weight: 400; -} - -.flex_center { - display: flex; - gap: 8px; - align-items: center; -} diff --git a/frontend/src/components/PageHeader.tsx b/frontend/src/components/PageHeader.tsx index 344ab8ed..916fa3fe 100644 --- a/frontend/src/components/PageHeader.tsx +++ b/frontend/src/components/PageHeader.tsx @@ -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; @@ -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 ( -
- {breadcrumbs &&
{breadcrumbs}
} -
-
-

- {title} -

+ + {breadcrumbs} + + + {title} {subtitle && ( -

+ {subtitle} -

+ )} -
+ {actions && ( -
+ {actions} -
+ )} -
-
+ + ); } diff --git a/frontend/src/components/__tests__/PageHeader.test.tsx b/frontend/src/components/__tests__/PageHeader.test.tsx index 7b063ce8..b5f5dc70 100644 --- a/frontend/src/components/__tests__/PageHeader.test.tsx +++ b/frontend/src/components/__tests__/PageHeader.test.tsx @@ -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

', () => { render(); - 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', () => { @@ -17,4 +18,29 @@ describe('PageHeader', () => { render(); expect(screen.queryByText(/subtitle/i)).not.toBeInTheDocument(); }); + + it('renders actions when provided', () => { + render( + Do thing} + />, + ); + expect(screen.getByRole('button', { name: 'Do thing' })).toBeInTheDocument(); + }); + + it('renders breadcrumbs slot when provided', () => { + render( + crumbs-here} + />, + ); + expect(screen.getByLabelText('breadcrumb')).toHaveTextContent('crumbs-here'); + }); + + it('wraps the header in a semantic
element', () => { + const { container } = render(); + expect(container.querySelector('header')).not.toBeNull(); + }); });