fix(day): fit the GKI tile's pair line in its column

The single-reading line spelled out both readings with their names and
units and was cut off after the glucose in every layout. Show the two
numbers with one unit, which fits the tile, and keep the worded pair for
assistive tech.
This commit is contained in:
Marc-André Bombeck committed 2026-11-11 00:46:30 +01:00
1 parent a7e98b980e
commit 128cf55ab6
12 files changed
+95 -12

No files matched your search

+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Alle {count} Werte",
"valuesFewer": "Weniger Werte",
"gkiPair": "Blutzucker {glucose} {unit} / Ketone {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Letzter von {count}",
"gkiCountFew": "Letzter von {count}",
"gkiCountOther": "Letzter von {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "All {count} values",
"valuesFewer": "Fewer values",
"gkiPair": "Glucose {glucose} {unit} / ketones {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Latest of {count}",
"gkiCountFew": "Latest of {count}",
"gkiCountOther": "Latest of {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Los {count} valores",
"valuesFewer": "Menos valores",
"gkiPair": "Glucosa {glucose} {unit} / cetonas {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Último de {count}",
"gkiCountFew": "Último de {count}",
"gkiCountOther": "Último de {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Les {count} valeurs",
"valuesFewer": "Moins de valeurs",
"gkiPair": "Glycémie {glucose} {unit} / cétones {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Dernier sur {count}",
"gkiCountFew": "Dernier sur {count}",
"gkiCountOther": "Dernier sur {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Tutti i {count} valori",
"valuesFewer": "Meno valori",
"gkiPair": "Glicemia {glucose} {unit} / chetoni {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Ultimo di {count}",
"gkiCountFew": "Ultimo di {count}",
"gkiCountOther": "Ultimo di {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "수치 {count}개 모두",
"valuesFewer": "수치 줄여 보기",
"gkiPair": "혈당 {glucose} {unit} / 케톤 {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "{count}개 중 최근",
"gkiCountFew": "{count}개 중 최근",
"gkiCountOther": "{count}개 중 최근",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Alle {count} waarden",
"valuesFewer": "Minder waarden",
"gkiPair": "Glucose {glucose} {unit} / ketonen {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Laatste van {count}",
"gkiCountFew": "Laatste van {count}",
"gkiCountOther": "Laatste van {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Wszystkie {count} wartości",
"valuesFewer": "Mniej wartości",
"gkiPair": "Glukoza {glucose} {unit} / ketony {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Ostatni z {count}",
"gkiCountFew": "Ostatni z {count}",
"gkiCountOther": "Ostatni z {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Todos os {count} valores",
"valuesFewer": "Menos valores",
"gkiPair": "Glicose {glucose} {unit} / cetonas {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Último de {count}",
"gkiCountFew": "Último de {count}",
"gkiCountOther": "Último de {count}",
+1
View File
@@ -13727,6 +13727,7 @@
"valuesAllOther": "Все {count} значений",
"valuesFewer": "Меньше значений",
"gkiPair": "Глюкоза {glucose} {unit} / кетоны {ketones} {unit}",
"gkiPairShort": "{glucose} / {ketones} {unit}",
"gkiCountOne": "Последний из {count}",
"gkiCountFew": "Последний из {count}",
"gkiCountOther": "Последний из {count}",
@@ -0,0 +1,60 @@
import { describe, expect, it } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { locales } from "@/lib/i18n/config";
/**
* The GKI tile sits in a two-column grid, about 150 px of text wide at phone
* width and in the 420 px day layer alike. The pair line under the index has
* to fit there whole, so both readings stay readable; the worded pair goes to
* assistive tech.
*/
const POINT = {
at: "2026-11-01T08:00:00.000Z",
value: 3.8,
ketoneId: "k1",
glucoseId: "g1",
glucoseAt: "2026-11-01T08:00:00.000Z",
ketonesMmol: 0.25,
glucoseMmol: 12.5,
};
async function render(locale: string) {
const { I18nProvider } = await import("@/lib/i18n/context");
const { DayGkiTile } = await import("../day-gki-tile");
const messages = (await import(`../../../../messages/${locale}.json`))
.default;
return renderToStaticMarkup(
<I18nProvider initialLocale={locale as never} initialMessages={messages}>
<DayGkiTile points={[POINT]} />
</I18nProvider>,
);
}
function visiblePair(html: string): string {
const match = html.match(
/<span aria-hidden="true" class="[^"]*truncate text-xs[^"]*">([^<]*)<\/span>/,
);
if (!match) throw new Error(`no visible pair line in ${html}`);
return match[1]!;
}
describe("<DayGkiTile>", () => {
it.each([...locales])(
"keeps the pair line short enough for the tile in %s",
async (locale) => {
const line = visiblePair(await render(locale));
expect(line).toMatch(/12[.,]5/);
expect(line).toMatch(/0[.,]25/);
expect(line.length).toBeLessThanOrEqual(20);
},
);
it("names both readings for assistive tech", async () => {
const html = await render("en");
expect(html).toMatch(
/<span class="sr-only">Glucose 12\.5 mmol\/L \/ ketones 0\.25 mmol\/L<\/span>/,
);
});
});
+25 -12
View File
@@ -23,6 +23,14 @@ export function DayGkiTile({ points }: { points: readonly DayGki[] }) {
const fmt = useFormatters();
const latest = points[points.length - 1];
if (!latest) return null;
const pair = {
glucose: fmt.number(latest.glucoseMmol, 1),
ketones: fmt.number(
latest.ketonesMmol,
ketoneFractionDigits(latest.ketonesMmol),
),
unit: GKI_COMPONENT_UNIT,
};
return (
<li data-slot="day-gki" className="flex min-w-0">
<Link
@@ -36,18 +44,23 @@ export function DayGkiTile({ points }: { points: readonly DayGki[] }) {
<span className="truncate text-base font-semibold tabular-nums">
{fmt.number(latest.value, 1)}
</span>
<span className="text-muted-foreground truncate text-xs tabular-nums">
{points.length > 1
? tCount("day.gkiCount", points.length)
: t("day.gkiPair", {
glucose: fmt.number(latest.glucoseMmol, 1),
ketones: fmt.number(
latest.ketonesMmol,
ketoneFractionDigits(latest.ketonesMmol),
),
unit: GKI_COMPONENT_UNIT,
})}
</span>
{points.length > 1 ? (
<span className="text-muted-foreground truncate text-xs tabular-nums">
{tCount("day.gkiCount", points.length)}
</span>
) : (
<>
{/* The tile is about 150 px of text wide: the numbers alone fit,
the worded pair is for assistive tech. */}
<span
aria-hidden="true"
className="text-muted-foreground truncate text-xs tabular-nums"
>
{t("day.gkiPairShort", pair)}
</span>
<span className="sr-only">{t("day.gkiPair", pair)}</span>
</>
)}
</Link>
</li>
);