mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
While a turn runs the Coach now shows a single row: a brain icon, the current step in the answer's text size with a shimmer passing through it and fading dots, and a chevron once there are steps to open. There is no running clock any more, and the interim table preview with its sparkline no longer renders under the row; interim tables stay in state until the answer's own results show them. When the answer is done the row reads "Thought process · N steps" with proper plurals, and "Answer needed" while a clarifying question waits. It never opens by itself, and a row opened during the run closes when the turn ends. Opened, the steps form a vertical list with an icon per kind of work on a thin connector line, and a reasoning round shows its summary under its title. The shimmer and the dots are a `text-shimmer` utility and a reusable WaitingText component, both still under reduced motion. The demo's write block now carries `meta.errorCode: "demo.readOnly"`, listed in the error-code catalogue, and the Coach answers it with an honest line instead of the provider-outage copy. Removes the interim preview component, the elapsed-seconds and summary helpers, and their message keys in all seven locales.
51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
|
|
/** A trailing ellipsis, three dots or the single character. */
|
|
const TRAILING_ELLIPSIS = /(?:\.\.\.|…)\s*$/u;
|
|
|
|
/** The stagger of the three dots, one class each (no inline style). */
|
|
const DOT_DELAYS = [
|
|
"[animation-delay:0s]",
|
|
"[animation-delay:0.2s]",
|
|
"[animation-delay:0.4s]",
|
|
] as const;
|
|
|
|
/**
|
|
* Text that is still waiting on something: a trailing "..." or "…" becomes
|
|
* three dots that fade in turn (`waiting-dot` in `globals.css`), so the line
|
|
* reads as alive without a spinner beside it. Text without a trailing
|
|
* ellipsis renders as it is. Under reduced motion the dots stand still.
|
|
*
|
|
* `textClassName` styles the words alone, never the dots: a text effect
|
|
* clipped to the glyphs (`text-shimmer`) does not reliably reach a child
|
|
* that animates its own opacity, so the dots keep the surrounding colour.
|
|
*
|
|
* The dots are ordinary full stops, so the text reads and copies as
|
|
* "Thinking...". A surface that announces its status elsewhere hides this
|
|
* text from assistive technology itself.
|
|
*/
|
|
export function WaitingText({
|
|
text,
|
|
textClassName,
|
|
}: {
|
|
text: string;
|
|
textClassName?: string;
|
|
}) {
|
|
const match = TRAILING_ELLIPSIS.exec(text);
|
|
const words = match ? text.slice(0, match.index) : text;
|
|
return (
|
|
<>
|
|
<span className={textClassName}>{words}</span>
|
|
{match ? (
|
|
<span data-slot="waiting-dots">
|
|
{DOT_DELAYS.map((delay) => (
|
|
<span key={delay} className={cn("waiting-dot", delay)}>
|
|
.
|
|
</span>
|
|
))}
|
|
</span>
|
|
) : null}
|
|
</>
|
|
);
|
|
}
|