Skip to content

Resolve relative item links and name the phase progress bar - #5

Merged
Lenoux01 merged 3 commits into
mainfrom
fix/renderer-a11y-and-relative-links
Sep 9, 2026
Merged

Lenoux01 merged 3 commits into
mainfrom
fix/renderer-a11y-and-relative-links

Conversation

@Lenoux01

@Lenoux01 Lenoux01 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Why

Two behaviours the first <Roadmap> consumers (new-campus#142, hn-monorepo#1529) had built into their local renderers and lost when they switched to @hansenexus/nextup/react@0.1.3. Both belong in the package so every site gets them.

Closes #3

What

Progress bar gets an accessible name — ui-react/index.tsx, render-html.ts (the web component and build --site share this markup; the site template has no bar of its own).

Before: role="progressbar" aria-valuenow="<pct>" aria-valuemin="0" aria-valuemax="100", no name — a screen reader announced a bare bar.
After: role="progressbar" aria-label="3 of 8 done" aria-valuemin="0" aria-valuemax="8" aria-valuenow="3". The label is the existing localized Strings.progress ("3 of 8 done" / "3 von 8 erledigt"), counted in items, not percent. Markup and .nextup-* classes are otherwise identical.

Relative item links leave resolved — new links.ts, applied in project.ts (toPublic and toInternal, so build, serve, mcp and both renderers all see the same hrefs), warned about in validate.ts (V15).

url in roadmap.yaml in the projection
docs/x.md, ./docs/x.md, /docs/x.md, docs/x.md#sec https://github.com/<meta.repo>/blob/HEAD/docs/x.md (fragment/query kept)
https://…, //cdn.…, mailto:…, tel:… untouched
#section untouched
../outside, ?query-only, or any relative link with no repo known dropped; validate warns V15 naming item + link

HEAD rather than a fetched default branch: GitHub resolves it server-side, so the output is byte-identical with and without a token and build --check never reports drift because master became main. meta.repo is required by the schema, so the "no repo" branch is only reachable through the resolveLink(url, repo | null) API; V15 fires on links that cannot map (escape the repo root, query-only).

Docs: README (yaml example + rule paragraph), roadmap-yaml.md (new ### links section; links was mislabelled "internal"), validation.md (V15 row), sites.md, CLAUDE.md ("Item links leave resolved").

Version bumped to 0.1.4. No tag, no publish. bun run schema:gen output unchanged.

How verified

bun run lint       Checked 54 files in 19ms. No fixes applied.
bun run typecheck  (three tsconfigs, clean)
bun run test       Test Files  15 passed (15)   Tests  150 passed (150)   (was 14 / 136)

New tests: links.test.ts (one case per rule above), project.test.ts (public + internal ship the resolved examples/dev-empire link docs/PLAN.md#phasing → …/blob/HEAD/docs/PLAN.md#phasing; mixed list keeps absolute/mailto/fragment and drops ../), validate.test.ts (V15 path + message), ui-react/index.test.tsx and view-model.test.ts (exact progressbar attribute string in en and de; never aria-valuemax="100"), wc/index.test.ts (attributes read back from the shadow root, label follows lang).

CLI smoke on a scratch roadmap with docs/design/blueprint-module.md and ../elsewhere.md:

$ nextup validate
roadmap.yaml: warning V15 items[0].links[1].url: "a" link "out" (../elsewhere.md) cannot be resolved against acme/smoke and is dropped from the projections — use a repo-relative path, an absolute URL, mailto: or #fragment
ok roadmap.yaml (1 items, 1 phases, 1 warning(s))          exit 0
$ nextup build --audience public --no-github
"url": "https://github.com/acme/smoke/blob/HEAD/docs/design/blueprint-module.md"   (the ../ link is gone)

🤖 Generated with Claude Code

Lenoux01 and others added 3 commits September 9, 2026 10:38
A `links[].url` like `docs/design/blueprint-module.md` was emitted verbatim, so on a consumer site it resolved against that site's origin and 404ed (new-campus#139 worked around it by hand). Both projections now resolve relative links to `https://github.com/<meta.repo>/blob/HEAD/<path>` before they leave — HEAD so the output is identical with and without a token and `build --check` never drifts on a branch rename. Absolute URLs, `mailto:` and `#fragment` pass through; a link that cannot resolve (climbs out of the repo, query-only) is dropped and `validate` warns as V15, naming the item and the link. Documented in README, roadmap-yaml.md and validation.md.

Refs #3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both renderers emitted `role="progressbar"` as a percentage with no accessible name, so a screen reader announced a bare bar. The bar now carries `aria-label` from the existing localized progress string ("3 of 8 done" / "3 von 8 erledigt"), `aria-valuemin="0"`, `aria-valuemax` = items in the phase and `aria-valuenow` = items done. Markup and class names are otherwise unchanged.

Refs #3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Lenoux01
Lenoux01 merged commit 2cc6483 into main Sep 9, 2026
5 checks passed
@Lenoux01
Lenoux01 deleted the fix/renderer-a11y-and-relative-links branch September 9, 2026 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

React/WC renderer: progress-bar accessible name; relative item links

1 participant