mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 21:32:18 +00:00
The front door reads the same ledger every screen reads: a record that never entered the flow sees the welcome, one mid-way is sent to the step it owes, a finished one is offered the questions again. The shell prints the counter and an ordered step list off the step machine, so it shows exactly the screens this flow has, and every screen moves focus to its heading on arrival. "Skip for now" is a real exit — it stamps the account past the first-run redirect and opens the checklist on the dashboard — and the one-time medical disclaimer now gates it as well as "Set up", because a skip that reached the dashboard without it would be a way round the acknowledgment. The five-step wizard's welcome carousel, goal picker and source grid go with it; the numbered step route follows in the next commit.
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef, type ReactNode } from "react";
|
|
|
|
/**
|
|
* The `h1` of every setup screen, and the one place focus goes when a screen
|
|
* arrives.
|
|
*
|
|
* Moving focus to the heading on each step is what lets a screen-reader user
|
|
* follow the flow: without it, a client-side navigation leaves focus on the
|
|
* button that was just pressed, which no longer exists, and the new question
|
|
* is never announced. `preventScroll` keeps the viewport where the layout
|
|
* put it — the heading is at the top of the column anyway.
|
|
*
|
|
* Semibold rather than the app-wide bold PageHeader H1: the onboarding hero
|
|
* is the documented exception (UI-STANDARDS §5). Do not sweep to font-bold.
|
|
*/
|
|
export function StepHeading({
|
|
id,
|
|
title,
|
|
description,
|
|
}: {
|
|
id: string;
|
|
title: ReactNode;
|
|
description?: ReactNode;
|
|
}) {
|
|
const ref = useRef<HTMLHeadingElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
ref.current?.focus({ preventScroll: true });
|
|
}, []);
|
|
|
|
return (
|
|
<header className="space-y-2">
|
|
<h1
|
|
ref={ref}
|
|
id={id}
|
|
tabIndex={-1}
|
|
className="text-2xl font-semibold tracking-tight outline-none"
|
|
>
|
|
{title}
|
|
</h1>
|
|
{description ? (
|
|
<p className="text-muted-foreground text-base leading-relaxed">
|
|
{description}
|
|
</p>
|
|
) : null}
|
|
</header>
|
|
);
|
|
}
|