Skip to content

Commit f7642e6

Browse files
committed
Add page header level modifiers
1 parent 4270adc commit f7642e6

4 files changed

Lines changed: 42 additions & 1 deletion

File tree

packages/web/src/features/shared/components/mobile-page-header.test.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,20 @@ describe("MobilePageHeader", () => {
1717
const leading = header?.querySelector(".page-header__leading");
1818

1919
expect(header).not.toBeNull();
20+
expect(header).toHaveClass("page-header--secondary");
21+
expect(header).toHaveAttribute("data-level", "secondary");
2022
expect(leading).not.toBeNull();
2123
expect(within(leading as HTMLElement).getByText("Open Workspace")).toBeInTheDocument();
2224
expect(screen.queryByText("WORKSPACE")).not.toBeInTheDocument();
2325
});
26+
27+
it("passes the requested level through without showing the kicker by default", () => {
28+
render(<MobilePageHeader title="Launch Task" kicker="Agent" level="primary" />);
29+
30+
const header = document.querySelector(".mobile-page-header");
31+
32+
expect(header).toHaveClass("page-header--primary");
33+
expect(header).toHaveAttribute("data-level", "primary");
34+
expect(screen.queryByText("Agent")).not.toBeInTheDocument();
35+
});
2436
});

packages/web/src/features/shared/components/page-header.test.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ describe("PageHeader", () => {
1717
const leading = header?.querySelector(".page-header__leading");
1818
const actions = header?.querySelector(".page-header__actions");
1919

20+
expect(header).toHaveClass("page-header--secondary");
21+
expect(header).toHaveAttribute("data-level", "secondary");
2022
expect(leading).not.toBeNull();
2123
expect(actions).not.toBeNull();
2224
expect(
@@ -38,4 +40,14 @@ describe("PageHeader", () => {
3840
expect(within(copy as HTMLElement).getByText("Config")).toBeInTheDocument();
3941
expect(screen.queryByRole("button", { name: "Edit" })).not.toBeInTheDocument();
4042
});
43+
44+
it("renders stable primary level hooks for shared styling", () => {
45+
render(<PageHeader title="Workspace Settings" level="primary" />);
46+
47+
const header = document.querySelector(".page-header");
48+
49+
expect(header).toHaveClass("page-header--primary");
50+
expect(header).toHaveAttribute("data-level", "primary");
51+
expect(header).not.toHaveClass("page-header--secondary");
52+
});
4153
});

packages/web/src/features/shared/components/page-header.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ArrowLeft } from "lucide-react";
33
import type { ReactNode } from "react";
44

55
type PageHeaderTitleElement = "div" | "h1" | "h2" | "h3" | "span";
6+
type PageHeaderLevel = "primary" | "secondary";
67

78
export interface PageHeaderProps {
89
title: string;
@@ -12,6 +13,7 @@ export interface PageHeaderProps {
1213
kicker?: ReactNode;
1314
rightSlot?: ReactNode;
1415
titleAs?: PageHeaderTitleElement;
16+
level?: PageHeaderLevel;
1517
className?: string;
1618
}
1719

@@ -23,12 +25,13 @@ export function PageHeader({
2325
kicker,
2426
rightSlot,
2527
titleAs = "h2",
28+
level = "secondary",
2629
className,
2730
}: PageHeaderProps) {
2831
const TitleTag = titleAs;
2932

3033
return (
31-
<div className={clsx("page-header", className)}>
34+
<div className={clsx("page-header", `page-header--${level}`, className)} data-level={level}>
3235
<div className="page-header__leading">
3336
{onBack ? (
3437
<button

packages/web/src/styles/components.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,11 @@
671671
color: var(--text-tertiary);
672672
}
673673

674+
.page-header--primary .page-header__kicker {
675+
font-size: var(--text-sm);
676+
letter-spacing: 0.1em;
677+
}
678+
674679
.page-header__title {
675680
margin: 0;
676681
max-width: 100%;
@@ -683,6 +688,15 @@
683688
text-align: left;
684689
}
685690

691+
.page-header--primary .page-header__title {
692+
font-size: var(--text-lg);
693+
line-height: 1.1;
694+
}
695+
696+
.page-header--secondary .page-header__title {
697+
line-height: 1.25;
698+
}
699+
686700
.page-header__back {
687701
display: inline-flex;
688702
align-items: center;

0 commit comments

Comments
 (0)