feat(web): PageShell narrow variant for dense single-column tabs
Adds a 'narrow' prop that wraps the body in 'max-w-2xl mx-auto' while keeping the header chrome at the standard 5xl. Settings is the first consumer — its rows are dense text and look adrift at full width. The header still aligns with the other tabs so the title position stays consistent. Covered by 2 SSR tests (narrow path adds the inner wrapper, default path doesn't). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3c3a3f57d3
commit
7697ea5fcb
@ -8,7 +8,7 @@ import { PageShell } from "@/components/page-shell";
|
||||
export default async function SettingsPage() {
|
||||
const op = await getSeededOperator();
|
||||
return (
|
||||
<PageShell title="Settings">
|
||||
<PageShell title="Settings" narrow>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Operator</CardTitle>
|
||||
|
||||
@ -56,4 +56,25 @@ describe("PageShell", () => {
|
||||
expect(html).toContain("Settings");
|
||||
expect(html).toContain("just a card");
|
||||
});
|
||||
|
||||
it("constrains the body to max-w-2xl when narrow is set", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<PageShell title="Settings" narrow>
|
||||
<p>card</p>
|
||||
</PageShell>,
|
||||
);
|
||||
// Outer chrome stays at 5xl so the header keeps its alignment;
|
||||
// an inner wrapper drops the body to 2xl.
|
||||
expect(html).toMatch(/max-w-5xl/);
|
||||
expect(html).toMatch(/max-w-2xl mx-auto/);
|
||||
});
|
||||
|
||||
it("does NOT add the inner narrow wrapper by default", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<PageShell title="Reminders">
|
||||
<p>list</p>
|
||||
</PageShell>,
|
||||
);
|
||||
expect(html).not.toMatch(/max-w-2xl/);
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,6 +8,10 @@ interface PageShellProps {
|
||||
* button. When omitted, the header row collapses to just the H1
|
||||
* on desktop and renders nothing on mobile. */
|
||||
action?: ReactNode;
|
||||
/** Constrain the body to `max-w-2xl` for dense, single-column
|
||||
* content (Settings, etc). The header stays at the standard
|
||||
* 5xl chrome so the title aligns with other tabs. */
|
||||
narrow?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@ -18,7 +22,7 @@ interface PageShellProps {
|
||||
* this so the header pattern stays consistent without each page
|
||||
* repeating the same wrapper markup.
|
||||
*/
|
||||
export function PageShell({ title, action, children }: PageShellProps) {
|
||||
export function PageShell({ title, action, narrow, children }: PageShellProps) {
|
||||
return (
|
||||
<div className="px-4 py-6 sm:px-6 sm:py-8 max-w-5xl mx-auto space-y-6">
|
||||
<div className="flex items-center justify-end sm:justify-between gap-4">
|
||||
@ -27,7 +31,11 @@ export function PageShell({ title, action, children }: PageShellProps) {
|
||||
</h1>
|
||||
{action}
|
||||
</div>
|
||||
{children}
|
||||
{narrow ? (
|
||||
<div className="max-w-2xl mx-auto space-y-6">{children}</div>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user