Skip to content

fix(desktop): toast polish — auto-dismiss, countdown bar, a11y#54

Merged
hqhq1025 merged 1 commit intomainfrom
wt/loop-fix-toast-polish
Apr 18, 2026
Merged

fix(desktop): toast polish — auto-dismiss, countdown bar, a11y#54
hqhq1025 merged 1 commit intomainfrom
wt/loop-fix-toast-polish

Conversation

@hqhq1025
Copy link
Copy Markdown
Collaborator

Summary

Implements audit 27 §B2 — Toast system polish.

§B2 checklist

  • 5s auto-dismiss for success/info; error persists. useEffect timer keyed on toast id, cleaned up on unmount. Removed the unconditional 4s setTimeout in pushToast.
  • min-w-72 max-w-96 instead of fixed w-80. Long titles/descriptions wrap (break-words) instead of getting truncated.
  • A11y roles per variant. Each toast item is now its own role="status" aria-live="polite" (success/info) or role="alert" aria-live="assertive" (error). The misused <output> element is replaced by <div>. Dismiss button keeps its aria-label.
  • Countdown progress bar. Thin (h-0.5) bar at the bottom of auto-dismissing toasts, animated via a new @keyframes toast-countdown (linear scaleX 1 → 0). Uses --color-text-muted at 30% alpha. motion-safe: variant means prefers-reduced-motion: reduce users see only a static bar — no animation.
  • No new dependencies. Pure Tailwind v4 + CSS variables + one CSS keyframe.

Files changed

  • apps/desktop/src/renderer/src/components/Toast.tsx — main rewrite (per-toast role/aria-live, useEffect timer, sizing, countdown bar). Exports scheduleAutoDismiss + AUTO_DISMISS_MS for unit testing.
  • apps/desktop/src/renderer/src/store.ts — drop the 4s blanket setTimeout from pushToast; the component owns the timer now.
  • apps/desktop/src/renderer/src/index.css — add @keyframes toast-countdown.
  • apps/desktop/src/renderer/src/components/__tests__/Toast.test.tsx — new Vitest unit test (5 cases) using fake timers: success/info dismiss after 5s, error never auto-dismisses, cleanup cancels the timer, AUTO_DISMISS_MS map values.

Net diff: ~106 LOC added (test included).

PRINCIPLES check

  • 🟢 Compatibility — toast public API unchanged (pushToast, dismissToast, useToast signatures preserved). Only the internal timer location moved.
  • 🟢 Upgradeability — auto-dismiss durations live in a single typed Record<ToastVariant, number | null> map; adding a new variant or tweaking timing is a one-line change.
  • 🟢 No bloat — zero new dependencies, zero new packages. One CSS keyframe + one helper function.
  • 🟢 Elegance — pure Tailwind variants for prefers-reduced-motion; per-toast role/aria-live aligns with WAI-ARIA notification patterns; component owns its own lifecycle.

Test plan

  • pnpm --filter @open-codesign/desktop test — 19 files / 143 tests pass (5 new Toast tests).
  • pnpm lint — clean (only pre-existing warnings unrelated to this PR).
  • pnpm typecheck — clean across the workspace.
  • Manual smoke: trigger success/info toast → auto-dismisses after 5s with visible countdown bar; trigger error toast → persists until X clicked; OS-level "Reduce motion" → countdown bar visible but static.

Audit 27 §B2 — toast system polish:
- Auto-dismiss success/info after 5s via useEffect timer keyed on toast id;
  error toasts persist until user dismiss.
- Replace fixed `w-80` with `min-w-72 max-w-96`; long content wraps
  instead of truncating.
- Per-toast `role`/`aria-live`: `status`/`polite` for success/info,
  `alert`/`assertive` for error. Replaces the misused `<output>` element.
- Thin countdown progress bar at the bottom of auto-dismissing toasts,
  animated via CSS keyframe; honors `prefers-reduced-motion` (motion-safe
  variant only).
- Move auto-dismiss out of `pushToast` (component-owned timer; cleaner
  than a fire-and-forget setTimeout).

No new dependencies. Pure Tailwind + tokens + one CSS keyframe.
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • No high-confidence issues found in added/modified lines.

Summary

  • Review mode: initial
  • No blocker/major/minor/nit issues identified in the current diff.
  • Residual risk/testing gap: coverage was added for scheduleAutoDismiss behavior, but there is still no component-level test for ToastItem/ToastViewport a11y semantics and countdown-bar rendering lifecycle.
  • Context note: docs/VISION.md and docs/PRINCIPLES.md were not found in this checkout (Not found in repo/docs).

Testing

  • Not run (automation)

open-codesign Bot

@hqhq1025 hqhq1025 merged commit e0a78d7 into main Apr 18, 2026
5 of 6 checks passed
@hqhq1025 hqhq1025 deleted the wt/loop-fix-toast-polish branch April 18, 2026 19:46
hqhq1025 added a commit that referenced this pull request Apr 19, 2026
Audit 27 §B2 — toast system polish:
- Auto-dismiss success/info after 5s via useEffect timer keyed on toast id;
  error toasts persist until user dismiss.
- Replace fixed `w-80` with `min-w-72 max-w-96`; long content wraps
  instead of truncating.
- Per-toast `role`/`aria-live`: `status`/`polite` for success/info,
  `alert`/`assertive` for error. Replaces the misused `<output>` element.
- Thin countdown progress bar at the bottom of auto-dismissing toasts,
  animated via CSS keyframe; honors `prefers-reduced-motion` (motion-safe
  variant only).
- Move auto-dismiss out of `pushToast` (component-owned timer; cleaner
  than a fire-and-forget setTimeout).

No new dependencies. Pure Tailwind + tokens + one CSS keyframe.
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.

1 participant