mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 12:22:03 +00:00
fix(insights): MED-bucket polish across coach + report surfaces
- weekly-report eyebrow chip drops uppercase + tracking-wide for the
sentence-case rule the rest of the app follows; print stylesheet
now neutralises bg + colour so monochrome output reads clean
(Design-M4, Design-L3).
- correlation-card "Try a 7-day experiment" CTA flips from default to
outline while disabled. Disabled-primary read as "the system is
broken right now"; outline reads as "this is on the roadmap"
(Design-M7).
- coach-drawer settings cog aria-label switches to the coming-soon
tooltip copy so SR users hear the same "arrives in v1.4.21" message
sighted users see (Design-M9).
- sources-rail static "fresh" dot becomes aria-hidden — v1.4.20 has
no real freshness state behind it; SR users no longer hear "Fresh"
five times in a row (Design-L4).
- summariseTitle slices on Unicode code points rather than UTF-16
code units so a user message ending mid-emoji ("🩺") no longer
produces a half-character on disk (Code-LOW-04).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
340239423b
commit
9f3baf940d
5 files changed
+26
-11
No files matched your search
@@ -186,7 +186,10 @@ export function CoachDrawer({
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled
|
||||
aria-label={t("insights.coach.settings")}
|
||||
// Match the visible disabled state — sighted users
|
||||
// see a coming-soon tooltip; SR users hear the same
|
||||
// copy instead of a working "Coach settings" label.
|
||||
aria-label={t("insights.coach.settingsTooltip")}
|
||||
data-slot="coach-drawer-settings"
|
||||
className="size-8"
|
||||
>
|
||||
|
||||
@@ -98,10 +98,13 @@ export function SourcesRail({ className }: SourcesRailProps) {
|
||||
<span className="text-foreground flex-1 text-xs font-medium">
|
||||
{t(row.metricKey)}
|
||||
</span>
|
||||
{/* Fresh / stale indicator — v1.4.20 is a static dot.
|
||||
v1.4.21 will reuse <IntegrationStatusPill>. */}
|
||||
{/* Fresh / stale indicator — v1.4.20 is a static dot
|
||||
with no real freshness state behind it (v1.4.21 plugs
|
||||
in <IntegrationStatusPill>). aria-hidden so SR users
|
||||
don't hear "Fresh" five times in a row for what is
|
||||
actually a placeholder. */}
|
||||
<span
|
||||
aria-label={t("insights.coach.sourcesFresh")}
|
||||
aria-hidden="true"
|
||||
className="bg-dracula-green size-1.5 rounded-full"
|
||||
/>
|
||||
</li>
|
||||
|
||||
@@ -131,7 +131,11 @@ export function CorrelationCard({ result }: CorrelationCardProps) {
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="default"
|
||||
// Outline variant so the disabled placeholder reads as
|
||||
// "this is on the roadmap" rather than "the system is
|
||||
// broken right now". Flip back to default when the
|
||||
// 7-day experiment feature ships in v1.5.
|
||||
variant="outline"
|
||||
disabled
|
||||
data-slot="correlation-card-cta"
|
||||
className="gap-1.5"
|
||||
|
||||
@@ -162,7 +162,7 @@ export function WeeklyReportPresentation({
|
||||
>
|
||||
<span
|
||||
data-slot="weekly-report-eyebrow"
|
||||
className="bg-dracula-purple/15 text-dracula-purple inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[11px] font-medium uppercase tracking-wide"
|
||||
className="bg-dracula-purple/15 text-dracula-purple inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[11px] font-medium print:bg-transparent print:px-0 print:text-foreground"
|
||||
>
|
||||
<FileText className="h-3 w-3" aria-hidden="true" />
|
||||
{t("insights.report.eyebrow")}
|
||||
|
||||
@@ -34,11 +34,16 @@ const TITLE_MAX = 80;
|
||||
export function summariseTitle(input: string): string {
|
||||
const collapsed = input.replace(/\s+/g, " ").trim();
|
||||
if (collapsed.length === 0) return "New conversation";
|
||||
if (collapsed.length <= TITLE_MAX) return collapsed;
|
||||
// Cut at TITLE_MAX-1 chars and append a single-character ellipsis so
|
||||
// the visible width matches TITLE_MAX. Cuts at the word boundary
|
||||
// when one is within reach of the limit.
|
||||
const sliced = collapsed.slice(0, TITLE_MAX - 1);
|
||||
// Spread to a code-point array so the slice respects multi-code-unit
|
||||
// characters (emoji like "🩺" land as a single grapheme rather than
|
||||
// a half "?"). The visible-length metric is grapheme count, not
|
||||
// UTF-16 code units.
|
||||
const points = [...collapsed];
|
||||
if (points.length <= TITLE_MAX) return collapsed;
|
||||
// Cut at TITLE_MAX-1 code points and append a single-character
|
||||
// ellipsis so the visible width matches TITLE_MAX. Cuts at the word
|
||||
// boundary when one is within reach of the limit.
|
||||
const sliced = points.slice(0, TITLE_MAX - 1).join("");
|
||||
const lastSpace = sliced.lastIndexOf(" ");
|
||||
const cut = lastSpace > TITLE_MAX - 20 ? sliced.slice(0, lastSpace) : sliced;
|
||||
return `${cut.trimEnd()}…`;
|
||||
|
||||
Reference in new issue
Block a user