From c711b4afc5393142cf6cbb4e38b1df9cd71be66e Mon Sep 17 00:00:00 2001 From: Dinesh Pandiyan Date: Wed, 28 Oct 2026 10:00:55 +1100 Subject: [PATCH] feat: pulse loading status detail line --- DESIGN.md | 4 +++- apps/web/src/WorkspaceLoading.tsx | 4 +++- apps/web/src/loading.css | 7 +++++++ apps/web/src/style.css | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index d870f976..990d19aa 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -664,7 +664,9 @@ Do not add motion for decoration. New animation must honor - Skeletons use `--border-muted`, existing spacing and radius tokens, and a gentle shared opacity pulse. Disable animation under `prefers-reduced-motion`. Keep placeholders out of the accessibility tree and tab order; label the busy region - with a concise status at the bottom of the review surface. Do not invent file + with a concise status at the bottom of the review surface. Its detail line + pulses between `--fg` and `--muted` on the skeleton rhythm, static under + reduced motion. Do not invent file names, counts, progress percentages or addition/deletion colors. - Replace skeletons as data arrives, without a minimum display delay. Stored manifest loading uses the same diff-frame skeleton without unmounting Pierre. diff --git a/apps/web/src/WorkspaceLoading.tsx b/apps/web/src/WorkspaceLoading.tsx index 4db4e0c4..4c1d639e 100644 --- a/apps/web/src/WorkspaceLoading.tsx +++ b/apps/web/src/WorkspaceLoading.tsx @@ -113,7 +113,9 @@ export function WorkspaceLoading({ collecting }: { collecting: boolean }) {

{collecting ? "Collecting latest changes" : "Loading review"}

-

{collecting ? "Reading checkouts…" : "Reading stored changes…"}

+

+ {collecting ? "Reading checkouts…" : "Reading stored changes…"} +

diff --git a/apps/web/src/loading.css b/apps/web/src/loading.css index aa0d07e7..4947e79d 100644 --- a/apps/web/src/loading.css +++ b/apps/web/src/loading.css @@ -183,6 +183,13 @@ opacity: 0.45; } } +/* Referenced by the loading status's animate-status-pulse utility. Shares the + skeleton rhythm; dims only to --muted so the text stays legible. */ +@keyframes status-pulse { + 50% { + color: var(--muted); + } +} @media (max-width: 1011px) { .loading-sidebar { display: none; diff --git a/apps/web/src/style.css b/apps/web/src/style.css index e5f95957..91da9b5d 100644 --- a/apps/web/src/style.css +++ b/apps/web/src/style.css @@ -639,6 +639,8 @@ main { --color-backdrop: var(--backdrop); --animate-spinner: refresh-spin var(--duration-spin) linear infinite; --animate-skeleton: skeleton-pulse var(--duration-pulse) ease-in-out infinite; + --animate-status-pulse: status-pulse var(--duration-pulse) ease-in-out + infinite; } @layer base {