v4: /settings and /manage take after /notifications — the three pages the user menu and the bell lead to share one frame: a 680px column (PageShell's new narrow), a title with its icon (PageHeader: ⚙️, 🛠️, 🔔), then groups under a small capitalized label ruled to the column's end (PageGroup, the notifications' day label), their content on surface cards (.page-card, the notification items' surface). Settings drew big section headings over controls laid on the bare page, the full width wide, and Manage the same around the category manager; each section is now a card whose setting rows are ruled apart and keep their labels lined up (a subgrid of the card's columns). The notifications' column, centered by auto margins in a flex column, shrank to its content (380px with short ones); it fills its width now. Its own header, group and bell rules gave way to the shared ones, and Times, Brutalist and GeoCities dress .page-card as they dress the notification items. In the narrower column, Kanagawa's monospace no longer fit the six styles on one row, and French labels leave even less room: a segmented control of more than four options now makes two even rows at any width, as it did on phones. 670 frontend tests pass, and tsc, eslint, deno lint, deno fmt and doc:lint are clean; checked in screenshots in all six styles at 1280 and 390px, Smooth in light too, with the account's style and the notifications mocked so the shared test account was left as it was.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
28
src/components/layout/PageGroup.tsx
Normal file
28
src/components/layout/PageGroup.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Renders one labelled group of a page under a `PageHeader`: a
|
||||
* settings section, the category manager, a day of notifications.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/** Passed to {@link PageGroup} by `Settings`, `Manage` and `Notifications`. */
|
||||
export interface PageGroupProps {
|
||||
/** It shows as a small capitalized label, ruled to the column's end. */
|
||||
label: ReactNode;
|
||||
/** Usually a `.page-card`, or the notifications' list of cards. */
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
/** Renders a `<section>` headed by `label` as its h2. */
|
||||
export function PageGroup(
|
||||
{ label, children }: PageGroupProps,
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<section className="page-group">
|
||||
<h2 className="page-group-label">{label}</h2>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
35
src/components/layout/PageHeader.tsx
Normal file
35
src/components/layout/PageHeader.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Renders the title row of the pages the user menu and the bell lead to:
|
||||
* settings, manage and notifications.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
/** Passed to {@link PageHeader} by `Settings`, `Manage` and `Notifications`. */
|
||||
export interface PageHeaderProps {
|
||||
/** An emoji before the title, hidden from screen readers. */
|
||||
icon: string;
|
||||
title: ReactNode;
|
||||
/** It goes at the end of the row, such as the notifications' unread count. */
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the page's h1 with its icon, then `children`, as the first block of
|
||||
* a narrow `PageShell`; `PageGroup`s follow it.
|
||||
*/
|
||||
export function PageHeader(
|
||||
{ icon, title, children }: PageHeaderProps,
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<div className="page-header">
|
||||
<h1 className="page-title">
|
||||
<span className="page-title-icon" aria-hidden="true">{icon}</span>
|
||||
{title}
|
||||
</h1>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,17 +13,24 @@ export interface PageShellProps {
|
||||
children: ReactNode;
|
||||
/** Centers the content, for a lone card such as a form or an error. */
|
||||
centered?: boolean;
|
||||
/**
|
||||
* Narrows the content to the column the user menu's and the bell's pages
|
||||
* share, under a `PageHeader`.
|
||||
*/
|
||||
narrow?: boolean;
|
||||
}
|
||||
|
||||
/** Renders {@link AppHeader}, then the page's content as the `<main>`. */
|
||||
export function PageShell(
|
||||
{ children, centered = false }: PageShellProps,
|
||||
{ children, centered = false, narrow = false }: PageShellProps,
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<div className="page-shell">
|
||||
<AppHeader />
|
||||
<main
|
||||
className={`page-content${centered ? " page-content--centered" : ""}`}
|
||||
className={`page-content${centered ? " page-content--centered" : ""}${
|
||||
narrow ? " page-content--narrow" : ""
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
|
||||
@@ -30,8 +30,9 @@ export interface SegmentedProps<V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Past this many options, a phone lays them out in two even rows rather than
|
||||
* one row that would wrap unevenly (`.visibility-toggle--many`).
|
||||
* Past this many options, they lay out in two even rows rather than one row
|
||||
* that the style's font or the language could make wrap unevenly
|
||||
* (`.visibility-toggle--many`).
|
||||
*/
|
||||
const MAX_ONE_ROW = 4;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user