Custom fonts in the appearance pickers, admin screen and licence page #304

Closed
opened 2026-08-01 06:19:35 +02:00 by opus-5 · 0 comments
Contributor

Depends on #303.

Follow-up to the custom-font backend issue: the management screen, the
font pickers, and the licence page.

Depends on the backend issue — the endpoints and the shared catalogue
lookup have to exist first.

Admin management screen

A section in the site-admin settings for uploading and managing custom
fonts:

  • Upload a family: family name, category (sans-serif | serif | monospace), licence label, optional licence URL, and one file per
    weight.
  • List existing families with their weights and licence.
  • Add a weight to an existing family; delete a family.
  • Before deleting, show which ponds currently use the family and state
    plainly that those ponds fall back to the default look — the backend
    supplies this list.

Localised de+en like every other UI surface.

Telling custom fonts apart in the pickers

This is the point of the exercise: in the pond Appearance settings, the
three font slots (heading, body, mono) must show at a glance which
families are shipped with the instance and which the operator provided.

Group them with <optgroup> rather than a badge or an icon:

  • "Mitgelieferte Schriften" / "Bundled fonts"
  • "Eigene Schriften" / "Custom fonts"

optgroup is the right tool because the grouping is then part of the
control's semantics, not a visual hint — screen readers announce the
group when moving into it, and it survives the native select rendering on
mobile. A coloured badge or a suffix in the label would convey the same
thing to sighted mouse users only.

Custom families appear only in the group matching their category, exactly
as catalogue families do.

Licence page

apps/web/src/pages/FontCatalogPage.tsx lists the catalogue families
with their licences. Custom fonts join the list, marked as provided by
the operator, showing the licence label and linking the licence URL when
one was given.

This is what makes an attribution requirement satisfiable — many
commercial font licences require naming the foundry or the licence, and
an operator who cannot point at such a page cannot comply.

Accessibility

  • The upload form's file inputs have visible, localised labels; the file
    type requirement (WOFF2, optionally WOFF) is stated in text, not only
    enforced on rejection.
  • Validation errors from the backend — wrong format, colliding family,
    file too large — are announced, not just coloured. They go through the
    existing form error path so they reach assistive technology.
  • The optgroup labels are real labels, not placeholder options.
  • The delete confirmation is reachable and operable by keyboard and names
    the consequence in text.
  • Upload progress and completion are perceivable without relying on
    colour or motion alone.
  • Any new screen goes into apps/web/e2e/a11y.spec.ts per the standing
    accessibility rule (ADR 0017, code/CLAUDE.md).

Acceptance criteria

  • A site admin can complete the whole cycle in the UI: upload a
    family with several weights, see it listed, use it in a pond, and
    delete it.
  • The three font pickers show bundled and custom families in separate,
    labelled groups, in de and en.
  • Choosing a custom font changes the pond's appearance in the browser,
    and the exported PDF matches.
  • The licence page lists custom fonts with licence and link.
  • Deleting a font names the affected ponds first.
  • Keyboard-only walkthrough of the management screen works end to end;
    the a11y spec covers it.
  • pnpm lint, pnpm typecheck, pnpm i18n:check and the a11y spec
    pass.
Depends on #303. Follow-up to the custom-font backend issue: the management screen, the font pickers, and the licence page. Depends on the backend issue — the endpoints and the shared catalogue lookup have to exist first. ## Admin management screen A section in the site-admin settings for uploading and managing custom fonts: - Upload a family: family name, category (`sans-serif | serif | monospace`), licence label, optional licence URL, and one file per weight. - List existing families with their weights and licence. - Add a weight to an existing family; delete a family. - Before deleting, show which ponds currently use the family and state plainly that those ponds fall back to the default look — the backend supplies this list. Localised de+en like every other UI surface. ## Telling custom fonts apart in the pickers This is the point of the exercise: in the pond Appearance settings, the three font slots (heading, body, mono) must show at a glance which families are shipped with the instance and which the operator provided. Group them with `<optgroup>` rather than a badge or an icon: - "Mitgelieferte Schriften" / "Bundled fonts" - "Eigene Schriften" / "Custom fonts" `optgroup` is the right tool because the grouping is then part of the control's semantics, not a visual hint — screen readers announce the group when moving into it, and it survives the native select rendering on mobile. A coloured badge or a suffix in the label would convey the same thing to sighted mouse users only. Custom families appear only in the group matching their category, exactly as catalogue families do. ## Licence page `apps/web/src/pages/FontCatalogPage.tsx` lists the catalogue families with their licences. Custom fonts join the list, marked as provided by the operator, showing the licence label and linking the licence URL when one was given. This is what makes an attribution requirement satisfiable — many commercial font licences require naming the foundry or the licence, and an operator who cannot point at such a page cannot comply. ## Accessibility - The upload form's file inputs have visible, localised labels; the file type requirement (WOFF2, optionally WOFF) is stated in text, not only enforced on rejection. - Validation errors from the backend — wrong format, colliding family, file too large — are announced, not just coloured. They go through the existing form error path so they reach assistive technology. - The optgroup labels are real labels, not placeholder options. - The delete confirmation is reachable and operable by keyboard and names the consequence in text. - Upload progress and completion are perceivable without relying on colour or motion alone. - Any new screen goes into `apps/web/e2e/a11y.spec.ts` per the standing accessibility rule (ADR 0017, `code/CLAUDE.md`). ## Acceptance criteria - [ ] A site admin can complete the whole cycle in the UI: upload a family with several weights, see it listed, use it in a pond, and delete it. - [ ] The three font pickers show bundled and custom families in separate, labelled groups, in de and en. - [ ] Choosing a custom font changes the pond's appearance in the browser, and the exported PDF matches. - [ ] The licence page lists custom fonts with licence and link. - [ ] Deleting a font names the affected ponds first. - [ ] Keyboard-only walkthrough of the management screen works end to end; the a11y spec covers it. - [ ] `pnpm lint`, `pnpm typecheck`, `pnpm i18n:check` and the a11y spec pass.
opus-5 added this to the M33 — Tweaks & Feinschliff milestone 2026-08-01 06:19:35 +02:00
opus-5 added the
effort:M
frontend
labels 2026-08-01 06:19:35 +02:00
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#304
No description provided.