Skip to content

fix(dashboard): a11y contrast/ARIA fixes, dismissal persistence, servers skeleton - #360

Open
DiogoDuart3 wants to merge 5 commits into
oblien:mainfrom
DiogoDuart3:pr5-dashboard-a11y-polish
Open

fix(dashboard): a11y contrast/ARIA fixes, dismissal persistence, servers skeleton#360
DiogoDuart3 wants to merge 5 commits into
oblien:mainfrom
DiogoDuart3:pr5-dashboard-a11y-polish

Conversation

@DiogoDuart3

Copy link
Copy Markdown
Contributor

A batch of small, independent a11y and UX fixes to the dashboard, verified live via a headless screenshot + DOM-role pass at 390px before/after each change.

Accessibility (Lighthouse-driven)

  • Raised --th-text-secondary/--th-text-muted alpha (light/dark themes) to clear 4.5:1 against page/card backgrounds; the dim theme already passed.
  • Eliminated text-muted-foreground/70 double-dimming repo-wide in favor of the (now-passing) base token.
  • Deepened --st-warning-fg on the light theme (amber-600 -> amber-800) so text-warning clears 4.5:1 on its tinted banner background; dark and dim already passed.
  • The shared admin DataTable (aliases/mailboxes/domains lists) had role="row"/role="cell"/role="columnheader" on the data columns but the actions-column cells had no role at all - fails aria-required-children. Wrapped in role="table"/role="rowgroup" and added the missing roles on the actions column.
  • Added aria-label to the unlabeled domain-picker <select> duplicated across the aliases, mailboxes, and dns admin tabs.
  • Sidebar section labels (MAIN/SETTINGS/INFRASTRUCTURE/Account) used a /60 double-dim on top of the already-tuned base token - same class of bug as the /70 sweep above, different fraction.

UX polish

  • Persisted critical update-banner dismissal (was re-showing every session).
  • Scoped the mail welcome-modal's dismissal to server+domain (was dismissing globally, so switching mail servers never showed it again even though the new server had never seen it).
  • Swapped the servers list's loading spinner for a row skeleton.

Note on CI

Recent merged PRs against main (#322, #327) show Typecheck: SUCCESS / Test: FAILURE on their PR-context runs. Flagging in case it reproduces here too - doesn't look related to this change.

DiogoDuart3 and others added 5 commits July 31, 2026 13:55
The dismissal flag was keyed by serverId alone, so the modal would
never come back for a newly added domain on an already-welcomed
server (contradicts the intended "show once per domain" behavior), and
had no guard against a transient empty domain from status still
loading registering a bogus key. Now keyed by serverId+domain, and the
effect/dismiss handler both require a non-empty domain before touching
localStorage.
Critical advisories are deliberately never dropped by the shared
resolveUpdateState (packages/core) - "shown once per launch by
design," which fits a desktop process. The dashboard web app has no
such launch boundary, so the "Update to 0.4.8" banner was coming back
on every client-side navigation after being dismissed. Added a
dashboard-only persistence layer, kept separate from the existing
non-critical dismissal list and keyed to id+version (not just id), so
a dismissal doesn't accidentally suppress a later release's critical
advisory. packages/core's resolver and the desktop app's behavior are
unchanged.
Deployments and Projects already show a row skeleton while loading;
Servers was the one holdout with a lone centered spinner. Matches the
real row's shape (avatar, name/host, one meta chip, status) so the
page doesn't jump when data lands, consistent with the other two lists.
…ects

Lighthouse audit fixes:
- Raise --th-text-secondary/muted alpha (light/dark themes) to clear
  4.5:1 against page/card backgrounds; dim theme already passed.
- Eliminate text-muted-foreground/70 double-dim usage repo-wide in
  favor of the (now-passing) base token.
- Deepen --st-warning-fg on the light theme (amber-600 -> amber-800)
  so text-warning clears 4.5:1 on its tinted banner background; dark
  and dim already passed.
- Restructure the shared admin DataTable (aliases/mailboxes/domains
  lists) with role="table"/role="rowgroup" wrappers around the
  existing row/columnheader/cell roles, fixing aria-required-parent
  and aria-required-children violations.
- Add aria-label to the unlabeled domain-picker <select> duplicated
  across the aliases, mailboxes, and dns admin tabs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ntrast

D5: the actions-column cells in the shared admin DataTable (aliases,
mailboxes, domains) had no role - only the data columns from the
columns.map loop got role="cell"/"columnheader". A role="row" with a
child missing an allowed role fails aria-required-children. Added
role="columnheader" to the header row's action-column spacer and
role="cell" to the body row's action-column wrapper.

D6: the sidebar's "MAIN"/"SETTINGS"/"INFRASTRUCTURE"/"Account" section
labels used text-muted-foreground/60 - a double-dim on top of the
already-tuned base token, same class of bug as the repo-wide /70 sweep
from an earlier pass but a different opacity fraction that sweep didn't
target. Removed the /60 modifier on all four labels.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Hydralerne

Copy link
Copy Markdown
Member

amazing

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.

2 participants