Rijkshuisstijl restyle + wizard fixes

Chrome: two-tier Rijksoverheid header (white brand bar + lint-blue
breadcrumb bar, route-driven), dark multi-column footer, white page
surface. Session shown via a shared SESSION_PORT token (keeps shared/
free of the auth context).

Overview ("Mijn overzicht") rebuilt to the NL Design System #392 pattern:
side-nav + "Wat moet ik regelen" task list (derived) + "Mijn registratie"
cards. New shared components: card, task-list, side-nav; pure
tasksFromProfile (+spec).

Wizards: grey form panel, connected numbered stepper, form-field
"(verplicht)" markers + styled description/error, full-width inputs.
Propagated to login, detail, change-request, address-fields.

Bug fixes:
- wizard-shell: add FormsModule so NgForm intercepts submit (wizards now
  advance; no native GET leaking choices into the URL).
- wizard-shell: error-summary links focus the field instead of navigating
  (a fragment href resolved against <base href="/"> reloaded to "/" and
  bounced to login).
- wizard-shell: error-summary focus only on the rising edge, so typing
  while errors are shown no longer scrolls the page up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 13:21:54 +02:00
parent d08f3877f7
commit 7a582ae2fa
30 changed files with 677 additions and 149 deletions

View File

@@ -83,12 +83,12 @@ const HANDMATIG = '__handmatig__'; // sentinel option: "my diploma isn't listed"
[value]="{ straat: draft().straat ?? '', postcode: draft().postcode ?? '', woonplaats: draft().woonplaats ?? '' }"
[errors]="{ straat: err('straat'), postcode: err('postcode'), woonplaats: err('woonplaats') }"
(fieldChange)="set($event.key, $event.value)" />
<app-form-field label="Hoe wilt u correspondentie ontvangen?" fieldId="correspondentie" [error]="err('correspondentie')">
<app-form-field label="Hoe wilt u correspondentie ontvangen?" fieldId="correspondentie" required [error]="err('correspondentie')">
<app-radio-group name="correspondentie" [options]="kanalen" [invalid]="!!err('correspondentie')"
[ngModel]="draft().correspondentie ?? ''" (ngModelChange)="setKanaal($event)" />
</app-form-field>
@if (draft().correspondentie === 'email') {
<app-form-field label="E-mailadres" fieldId="email" [error]="err('email')">
<app-form-field label="E-mailadres" fieldId="email" required [error]="err('email')">
<app-text-input inputId="email" type="email" [invalid]="!!err('email')" [ngModel]="draft().email ?? ''" (ngModelChange)="set('email', $event)" name="email" placeholder="naam@voorbeeld.nl" />
</app-form-field>
}
@@ -97,7 +97,7 @@ const HANDMATIG = '__handmatig__'; // sentinel option: "my diploma isn't listed"
@case ('beroep') {
<app-async [data]="lookupRd()">
<ng-template appAsyncLoaded let-data>
<app-form-field label="Kies het diploma waarmee u zich wilt registreren" fieldId="diploma" [error]="err('diploma')">
<app-form-field label="Kies het diploma waarmee u zich wilt registreren" fieldId="diploma" required [error]="err('diploma')">
<app-radio-group name="diploma" [options]="diplomaOptions($any(data))" [invalid]="!!err('diploma')"
[ngModel]="diplomaKeuze()" (ngModelChange)="onDiplomaKeuze($any(data), $event)" />
</app-form-field>