mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
chore: voice + filename hygiene + wave-4 state wrap
Maintainer-voice sweep across `src/`. ~190 references to the maintainer by first name in code comments and JSDoc neutralised to "the maintainer", "the live tenant", "users", or "the user" depending on context. Three sed passes covering ~50 distinct patterns (`Marc reported`, `Marc wants`, `Marc kept`, `Marc rolled back`, etc.). Test fixtures (`displayName: "Marc B."`, `username: "marc"`, `<HeroStrip userName="Marc">`) kept as opaque test data per the brief. CHANGELOG normalisation. The v1.4.14 + v1.4.15 entries paired a German bullet with its English translation by historical design — the in-app copy is English-default and the user docs are English, so the mixed-language style was a holdover from the early-marathon notes. A one-off node script extracted the `_..._` English paragraph from each bilingual bullet and rewrote the entry as that text. ~44 bullets reduced; one Docs bullet that lost a leading word in the regex fixed by hand. CLAUDE.md → CONTRIBUTING-AI.md rename so the filename is no longer AI-vendor-specific. `CONTRIBUTING.md` reference updated. `AGENTS.md` stays in place for multi-agent compatibility (the conventions doc is shared with Codex / Cursor / etc.). Wave-4 state wrap. STATE.md now records C1–C5 + D + D2 as complete; v1421-backlog.md grew a "Closed in v1.4.22" header listing the 20 items the marathon landed; `.planning/phase-W4-report.md` documents the per-commit decisions, test deltas, and the 23 items deferred to v1.4.23 with reasoning. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1499e6f83c
commit
363e73cbf2
76 files changed
+1050
-575
No files matched your search
@@ -7,7 +7,7 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
* is always wider than a 393 CSS-px (Pixel-5) viewport, so v1.4.18
|
||||
* phase A2 added the `no-scrollbar` class to the strip — Chromium /
|
||||
* WebKit otherwise paint an always-on horizontal scrollbar at the top
|
||||
* of every admin page, which Marc kept mis-attributing to the
|
||||
* of every admin page, which the maintainer kept mis-attributing to the
|
||||
* `/admin/api-tokens` table card right below it. Three previous fix
|
||||
* attempts (v1.4.15 column-hide, v1.4.16 mobile-card-list, then this
|
||||
* one) all targeted the table while the bar lived in the shell.
|
||||
|
||||
@@ -7,7 +7,7 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
* v1.4 shared-admin page where 13 sections lived on one route; in
|
||||
* v1.5 every section has its own dedicated route, so collapsing the
|
||||
* only card on `/admin/api-tokens` hides the entire surface and
|
||||
* confused Marc more than it helped.
|
||||
* confused the maintainer more than it helped.
|
||||
*/
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
|
||||
@@ -94,7 +94,7 @@ describe("ApiTokenOverviewSection — responsive", () => {
|
||||
it("mobile card-list has no overflow-x-auto wrapper", () => {
|
||||
const html = render();
|
||||
// Mobile cards must let content wrap within the card rather than
|
||||
// forcing a scroll container — that was the v1.4.15 bug Marc
|
||||
// forcing a scroll container — that was the v1.4.15 bug the maintainer
|
||||
// re-reported. Confirm there's no overflow-x-auto INSIDE the
|
||||
// mobile <ul>.
|
||||
const mobileMatch = html.match(/<ul[^>]*md:hidden[^>]*>([\s\S]*?)<\/ul>/);
|
||||
|
||||
@@ -4,13 +4,13 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
/**
|
||||
* v1.4.19 A7 — `/admin/api-tokens` 4th-attempt scrollbar fix.
|
||||
*
|
||||
* Marc reported a "minimaler Scrollbar" still painting at the
|
||||
* the maintainer reported a "minimaler Scrollbar" still painting at the
|
||||
* bottom-right of the api-tokens page, even after the v1.4.18 phase
|
||||
* A2 mobile-strip `no-scrollbar` fix. The remaining culprits are
|
||||
* inside the section card itself: long token names, long usernames,
|
||||
* and long permission strings can each push their parent past the
|
||||
* viewport. Cumulatively this leaves the page in an "almost-fits"
|
||||
* state where the visible scrollbar Marc sees is the page-level main
|
||||
* state where the visible scrollbar the maintainer sees is the page-level main
|
||||
* scroll picking up a fraction of pixels of horizontal scroll spill
|
||||
* from the children.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
/**
|
||||
* v1.4.15 phase A2: the `/admin` overview no longer renders the
|
||||
* `StatusCardGrid` (the section-card grid Marc described as redundant
|
||||
* `StatusCardGrid` (the section-card grid the maintainer described as redundant
|
||||
* with the sidebar nav). The status-card component itself was removed
|
||||
* from the codebase. This test guards the *new* overview composition:
|
||||
* a welcome card, the system snapshot, and the recent-audit preview.
|
||||
|
||||
@@ -153,7 +153,7 @@ export function AdminShell({ active, children }: AdminShellProps) {
|
||||
painted scrollbar at the top of every admin page; the
|
||||
horizontal swipe + keyboard arrow scrolling still work, the
|
||||
bar just doesn't draw. Without this the 13-section strip
|
||||
would render an always-on scrollbar that Marc kept
|
||||
would render an always-on scrollbar that the maintainer kept
|
||||
mis-attributing to the api-tokens table below it. */}
|
||||
<nav
|
||||
aria-label={t("admin.shell.sectionsNav")}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { type ApiTokenInfo } from "./_shared";
|
||||
*
|
||||
* v1.4.19 phase A7 (4th attempt) — earlier fixes (column-hide,
|
||||
* mobile card-list, mobile-strip `no-scrollbar`) cleared every
|
||||
* scrollbar Marc reported except a residual painted bar he kept
|
||||
* scrollbar the maintainer reported except a residual painted bar he kept
|
||||
* seeing at the bottom-right. Production probe confirmed no
|
||||
* remaining horizontal-overflow culprits, but the cards still
|
||||
* carried `break-all` next to `truncate` (dead code; `white-space:
|
||||
@@ -104,7 +104,7 @@ export function ApiTokenOverviewSection() {
|
||||
// section route. The previous pattern carried a "Collapse / Expand"
|
||||
// toggle as an escape hatch from the v1.4 shared admin page where
|
||||
// 13 sections lived together, but on a route that only renders this
|
||||
// one card the toggle hides the entire surface. Marc reported it
|
||||
// one card the toggle hides the entire surface. the maintainer reported it
|
||||
// as "sinnlos" — gone.
|
||||
const { data: tokens, isLoading } = useQuery({
|
||||
queryKey: ["admin", "tokens"],
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
/**
|
||||
* v1.4.18 — per-chart overlay-controls popover.
|
||||
*
|
||||
* Marc rejected the always-on overlays from B1a (gradient, baseline,
|
||||
* the maintainer rejected the always-on overlays from B1a (gradient, baseline,
|
||||
* target-zone shading) and asked for a per-chart switch surface so a
|
||||
* user can toggle "7-Tage-Trend / Trend-Pfeil / Zielbereich" on or off
|
||||
* for each chart independently. The popover is anchored top-right of
|
||||
|
||||
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
|
||||
/**
|
||||
* v1.4.18 — Default overlay state on chart wrappers.
|
||||
*
|
||||
* Marc rejected the always-on personal-baseline reference line that B1a
|
||||
* the maintainer rejected the always-on personal-baseline reference line that B1a
|
||||
* painted on every chart. The default surface for a new chart should be
|
||||
* a clean line + axes + tooltip — no baseline, no target-zone shading,
|
||||
* no trend line. Overlays are user-opt-in via the per-chart settings
|
||||
|
||||
@@ -123,7 +123,7 @@ describe("computePersonalBaseline()", () => {
|
||||
|
||||
describe("<HealthChart> v1.4.18 clean-line revert", () => {
|
||||
it("does NOT paint a gradient fill under the line (clean line only)", async () => {
|
||||
// v1.4.18 reverts B1a's gradient-area treatment. Marc explicitly
|
||||
// v1.4.18 reverts B1a's gradient-area treatment. the maintainer explicitly
|
||||
// rejected the soft-color fill below the line: the line itself is
|
||||
// the chart, no painted background under it. We assert the SSR
|
||||
// output ships no `<linearGradient>` defs and no `chart-gradient`
|
||||
|
||||
@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
|
||||
/**
|
||||
* v1.4.18 — MoodChart clean-line revert (gradient + emoji rolled back).
|
||||
*
|
||||
* Marc rejected B1a's coloured area fill below the chart line and the
|
||||
* the maintainer rejected B1a's coloured area fill below the chart line and the
|
||||
* smiley/emoji glyphs at every data point. The line stroke + Dracula
|
||||
* tokens stay; the chart now paints a clean monotone line with simple
|
||||
* Recharts dots.
|
||||
@@ -67,7 +67,7 @@ describe("<MoodChart> v1.4.18 clean-line revert", () => {
|
||||
});
|
||||
|
||||
it("does NOT render emoji glyphs at data points (source check)", async () => {
|
||||
// Marc explicitly rejected smileys, especially in the mood chart.
|
||||
// the maintainer explicitly rejected smileys, especially in the mood chart.
|
||||
// Recharts does not paint <Line> dots during SSR (the dot callback
|
||||
// only fires after first client render), so the emoji wouldn't
|
||||
// surface in renderToStaticMarkup output anyway. Inspecting the
|
||||
|
||||
@@ -7,7 +7,7 @@ import { join } from "node:path";
|
||||
* chart in a `<ResponsiveContainer>` whose default
|
||||
* `touch-action: auto` makes the browser wait for the chart's JS
|
||||
* touchmove handler before starting page scroll. On slow devices that
|
||||
* causes Marc's "Scrolling-Hänger im Dashboard auf Charts".
|
||||
* causes the maintainer's "Scrolling-Hänger im Dashboard auf Charts".
|
||||
*
|
||||
* Fix: every chart's wrapper `<div>` (the one that contains the
|
||||
* `<ResponsiveContainer>`) must carry the Tailwind `touch-pan-y`
|
||||
|
||||
@@ -9,7 +9,7 @@ import { I18nProvider } from "@/lib/i18n/context";
|
||||
* v1.4.15 Fix 4 — "7-Tage-Schnitt" → "7-Tage-Trend".
|
||||
*
|
||||
* The avg7 line on every dashboard tile used to read "7d: 80.5" /
|
||||
* "7T: 80,5" — visually an *average*. Marc wanted it to convey
|
||||
* "7T: 80,5" — visually an *average*. the maintainer wanted it to convey
|
||||
* *direction* over the past week instead, so the label flips to
|
||||
* "7d trend" / "7T-Trend" and a signed delta indicator paints next
|
||||
* to the value with metric-aware colour:
|
||||
|
||||
@@ -6,7 +6,7 @@ import { LineChart as LineChartIcon } from "lucide-react";
|
||||
/**
|
||||
* Sparse-data empty-state for chart wrappers (B1a v1.4.16).
|
||||
*
|
||||
* Per Marc's research §1A — "personal-baseline framing first" — when a
|
||||
* Per the maintainer's research §1A — "personal-baseline framing first" — when a
|
||||
* user has only 1-2 data points there's nothing useful to plot, so we
|
||||
* paint a friendly hint instead of a near-empty canvas. The hint reuses
|
||||
* the `lucide-react/LineChart` glyph the rest of the app uses for chart
|
||||
|
||||
@@ -19,7 +19,7 @@ import { type ChartOverlayPrefs } from "@/lib/dashboard-layout";
|
||||
/**
|
||||
* v1.4.18 — per-chart overlay-controls popover.
|
||||
*
|
||||
* Marc rolled back B1a's always-on chart overlays (gradient fills,
|
||||
* the maintainer rolled back B1a's always-on chart overlays (gradient fills,
|
||||
* personal-baseline reference line, target-zone shading) and asked for
|
||||
* a per-chart switch surface instead. Each dashboard chart card mounts
|
||||
* one of these in its top-right corner (a settings-cog dropdown) so the
|
||||
@@ -30,7 +30,7 @@ import { type ChartOverlayPrefs } from "@/lib/dashboard-layout";
|
||||
* - showTrendIndicator — the "7-day trend" overlay (moving average +
|
||||
* numeric Δ chip in the header)
|
||||
* - showTrendArrow — the trend regression line + arrow direction
|
||||
* hint + personal-baseline reference line. Marc's rule: the mean
|
||||
* hint + personal-baseline reference line. the maintainer's rule: the mean
|
||||
* line only paints when a trend is being displayed, so we fold
|
||||
* the baseline into this toggle.
|
||||
* - showTargetRange — the target-zone shading + reference lines
|
||||
|
||||
@@ -842,7 +842,7 @@ export function HealthChart({
|
||||
|
||||
// v1.4.16 Fix A8b: when the visible window is long (e.g. "All"
|
||||
// on a multi-year account), the per-week delta becomes vanishingly
|
||||
// small and rounds to ±0.0 in the formatter — Marc's complaint
|
||||
// small and rounds to ±0.0 in the formatter — the maintainer's complaint
|
||||
// "Wenn ich alle anklicke, dann wird einfach Null Veränderung
|
||||
// angezeigt" was exactly this: a slope of ~0.5 kg/year prints
|
||||
// as "+0.0 kg/week" and the user reads it as "no change". For
|
||||
@@ -1194,7 +1194,7 @@ export function HealthChart({
|
||||
/>
|
||||
))}
|
||||
{/* v1.4.18 — personal-baseline reference line is now
|
||||
opt-in via the Trend toggle. Marc rejected the
|
||||
opt-in via the Trend toggle. the maintainer rejected the
|
||||
always-on dashed mean line; it now only paints when
|
||||
the user actively shows the trend overlay (matching
|
||||
his rule: "only when a trend is being displayed").
|
||||
|
||||
@@ -475,7 +475,7 @@ export function MoodChart({
|
||||
5: t("charts.moodLabel5"),
|
||||
};
|
||||
|
||||
// v1.4.18 — emoji glyph map removed. Marc explicitly rejected
|
||||
// v1.4.18 — emoji glyph map removed. the maintainer explicitly rejected
|
||||
// smileys in the mood chart; the line now uses plain Recharts dots
|
||||
// and the y-axis already labels each integer (very low / low / okay
|
||||
// / good / great) so the chart is fully scannable without a glyph.
|
||||
@@ -632,7 +632,7 @@ export function MoodChart({
|
||||
/>
|
||||
))}
|
||||
{/* v1.4.18 — personal-baseline gated behind the
|
||||
Trend toggle (Marc: "only when a trend is being
|
||||
Trend toggle (maintainer: "only when a trend is being
|
||||
displayed"). Default OFF. */}
|
||||
{showTrend && personalBaseline != null && (
|
||||
<ReferenceLine
|
||||
|
||||
@@ -192,7 +192,7 @@ export function TrendCard({
|
||||
};
|
||||
|
||||
// The label flips from "7d" / "7T" (mean) to "7d trend" / "7T-Trend"
|
||||
// when the call site supplies a delta. Marc's v1.4.15 feedback —
|
||||
// when the call site supplies a delta. the maintainer's v1.4.15 feedback —
|
||||
// "7-Tage-Schnitt" sounds like an average, but the value next to it
|
||||
// is now a TREND. Distinct keys keep the label change in i18n.
|
||||
const avg7LabelKey =
|
||||
|
||||
@@ -266,7 +266,7 @@ describe("<InsightAdvisorCard> — polished loading / empty / error states (B1b)
|
||||
});
|
||||
|
||||
it("renders the legacy v1.4.14 payload without crashing (regenerate CTA)", () => {
|
||||
// Reproduces Marc's production /insights crash on 2026-05-10:
|
||||
// Reproduces the maintainer's production /insights crash on 2026-05-10:
|
||||
//
|
||||
// TypeError: Cannot read properties of undefined (reading 'replace')
|
||||
// at stripChartTokens(insight.summary)
|
||||
|
||||
@@ -247,7 +247,7 @@ describe("<RecommendationCard>", () => {
|
||||
/**
|
||||
* v1.4.22 A6 — strip chart-tokens from the always-visible
|
||||
* recommendation text. W1a §3 traced the production "metric:WEIGHT"
|
||||
* leak Marc saw at the bottom of the advisor card to this exact
|
||||
* leak the maintainer saw at the bottom of the advisor card to this exact
|
||||
* render path: every other AI-prose surface ran through
|
||||
* `stripChartTokens()`, the recommendation text didn't. Pin the
|
||||
* strip so a future copy-paste regression can't reintroduce the
|
||||
|
||||
@@ -85,7 +85,7 @@ describe("<SidebarNav> bug-report toggle", () => {
|
||||
});
|
||||
|
||||
describe("<SidebarNav> admin entry mirrors Settings (no sub-item expansion)", () => {
|
||||
// v1.4.16 A1: Marc reported the global sidebar expanding admin
|
||||
// v1.4.16 A1: the maintainer reported the global sidebar expanding admin
|
||||
// sub-items on `/admin/*` was unwanted UX — the in-shell `<AdminShell>`
|
||||
// already provides per-section nav inside the page. The Admin entry
|
||||
// must behave EXACTLY like the Settings entry: a single link with no
|
||||
@@ -112,7 +112,7 @@ describe("<SidebarNav> admin entry mirrors Settings (no sub-item expansion)", ()
|
||||
const html = render({ role: "ADMIN", pathname: "/admin/system-status" });
|
||||
expect(html).toContain('href="/admin"');
|
||||
// Sub-section links must NOT appear in the global sidebar — they
|
||||
// belong to `<AdminShell>`'s in-page nav. Marc reported the
|
||||
// belong to `<AdminShell>`'s in-page nav. the maintainer reported the
|
||||
// expansion as broken UX in v1.4.16; this guard keeps it gone.
|
||||
for (const section of ADMIN_SECTIONS) {
|
||||
expect(html).not.toContain(`href="/admin/${section.slug}"`);
|
||||
|
||||
@@ -419,7 +419,7 @@ export function OnboardingTour({
|
||||
|
||||
{/* v1.4.15 H4 design: tour footer buttons reach the WCAG 2.5.5
|
||||
44 px tap-target floor on mobile. The `size="sm"` default
|
||||
of `h-8` clipped to ~32 px which Marc reported as too small
|
||||
of `h-8` clipped to ~32 px which the maintainer reported as too small
|
||||
on the iPad / iPhone PWA shell. Bumping to `min-h-11` (44 px)
|
||||
keeps the desktop visual close enough — the buttons grow
|
||||
~4 px taller — while making mobile usable. */}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* v1.4.16 phase B2 — AI provider settings UX (dropdown-driven).
|
||||
*
|
||||
* The new section replaces the v1.4.15-vintage top/bottom split (Marc's
|
||||
* The new section replaces the v1.4.15-vintage top/bottom split (the maintainer's
|
||||
* `feedback_settings_no_split.md`): a single Select picks the active
|
||||
* provider; the form below is switch-rendered for that provider; the
|
||||
* fallback chain at the bottom reorders / toggles entries with arrow
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* v1.4.19 phase A5 — IntegrationStatusPill
|
||||
*
|
||||
* The single tag rendered top-right of every integration card. The
|
||||
* pill is the ONLY place a connection status surfaces — Marc was
|
||||
* pill is the ONLY place a connection status surfaces — the maintainer was
|
||||
* staring at three- to four-fold redundancy across Withings + Mood Log
|
||||
* cards in v1.4.18 and called it out. This component is reusable so
|
||||
* v1.4.20 can drop the same pill on the Apple Health card.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* v1.4.19 Phase A5 — Settings → Integrations status consolidation.
|
||||
*
|
||||
* Marc's verbatim concern (paraphrased):
|
||||
* the maintainer's verbatim concern (paraphrased):
|
||||
* - Withings card had 3 status displays — top-right "connected"
|
||||
* badge, mid-card "connected / last successful / last attempt"
|
||||
* trio container, and the badge inside that container.
|
||||
@@ -22,7 +22,7 @@
|
||||
* 4. Mood Log disconnected: pill says "Not connected", no other
|
||||
* status display surfaces.
|
||||
* 5. Mood Log card has the visual divider that Withings always had
|
||||
* — consistency Marc explicitly called out.
|
||||
* — consistency the maintainer explicitly called out.
|
||||
*/
|
||||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
@@ -219,7 +219,7 @@ describe("IntegrationsSection — single-status-display contract (A5)", () => {
|
||||
expect(html).not.toContain("Last attempt");
|
||||
});
|
||||
|
||||
it("Withings reauth state surfaces 'Error — reconnect' on the pill (Marc's wording)", () => {
|
||||
it("Withings reauth state surfaces 'Error — reconnect' on the pill (the maintainer's wording)", () => {
|
||||
setIntegrationStatus({
|
||||
threshold: 3,
|
||||
integrations: [
|
||||
|
||||
@@ -266,7 +266,7 @@ export function AboutSection() {
|
||||
that proxies through `/api/version/check-updates`. The v1.4.2
|
||||
version called `api.github.com` directly from the browser, which
|
||||
the production CSP blocked silently — that's why "nothing
|
||||
happened" when Marc clicked the button. */}
|
||||
happened" when the user clicked the button. */}
|
||||
{version && (
|
||||
<div className="bg-card border-border rounded-xl border p-6">
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
|
||||
@@ -168,7 +168,7 @@ export function AiSection() {
|
||||
/**
|
||||
* The single dropdown-driven configuration card. Replaces the
|
||||
* v1.4.15-vintage two-card layout (Codex connect at the top, personal
|
||||
* provider form at the bottom) per Marc's
|
||||
* provider form at the bottom) per the maintainer's
|
||||
* `feedback_settings_no_split.md`: one provider Select, one matching
|
||||
* form below, one fallback-chain card at the bottom.
|
||||
*
|
||||
@@ -389,7 +389,7 @@ function ActiveProviderSelect({
|
||||
|
||||
/**
|
||||
* Switch-rendered provider configuration. The component is the
|
||||
* "form below adapts dynamically" half of Marc's pulldown contract:
|
||||
* "form below adapts dynamically" half of the maintainer's pulldown contract:
|
||||
* pick Codex → see Codex form; pick OpenAI → see API-key + model
|
||||
* dropdown + base-URL override. The card frame is the same in every
|
||||
* branch so transitions feel like updating a single concept rather
|
||||
|
||||
@@ -114,7 +114,7 @@ export function DashboardLayoutSection({ id }: { id: string }) {
|
||||
/**
|
||||
* v1.4.15 Fix 5 — independent toggle for the *strip tile* (the upper
|
||||
* row of trend cards). Until v1.4.14 a single switch controlled both
|
||||
* the tile AND the chart for the same metric, which Marc found too
|
||||
* the tile AND the chart for the same metric, which the maintainer found too
|
||||
* coarse: he wanted a chart visible without the tile (for metrics he
|
||||
* tracks without wanting the at-a-glance number) or vice versa.
|
||||
*/
|
||||
@@ -250,8 +250,8 @@ export function DashboardLayoutSection({ id }: { id: string }) {
|
||||
{/* v1.4.15 Fix 5 — table-style header naming the two
|
||||
switches. The "tile" column controls the strip tile in
|
||||
the upper row; the "chart" column controls the line
|
||||
chart in the lower row. Marc wanted independent control
|
||||
of the two surfaces (memory feedback_dashboard_top_tiles
|
||||
chart in the lower row. the maintainer wanted independent control
|
||||
of the two surfaces (per feedback_dashboard_top_tiles
|
||||
_selectable.md). */}
|
||||
<div className="text-muted-foreground flex items-center gap-3 px-3 pb-1 text-[10px] font-medium tracking-wide uppercase">
|
||||
<span className="w-5" aria-hidden="true" />
|
||||
|
||||
@@ -9,7 +9,7 @@ import { cn } from "@/lib/utils";
|
||||
/**
|
||||
* v1.4.19 phase A5 — single status pill rendered top-right of every
|
||||
* integration card (Withings, Mood Log, Apple Health…). It replaces
|
||||
* the three- to four-fold redundant status surface Marc spotted in
|
||||
* the three- to four-fold redundant status surface the maintainer spotted in
|
||||
* v1.4.18:
|
||||
*
|
||||
* - top-right "Connected" badge
|
||||
@@ -17,7 +17,7 @@ import { cn } from "@/lib/utils";
|
||||
* - bottom-of-card "letzter Sync" line
|
||||
*
|
||||
* Now there is exactly ONE place a sync status can appear on a card
|
||||
* and it follows the pattern Marc liked from the Withings header: a
|
||||
* and it follows the pattern the maintainer liked from the Withings header: a
|
||||
* Dracula-tokenized chip with the relative time inline.
|
||||
*
|
||||
* The component is locale-aware (EN + DE) and mobile-safe: on a
|
||||
|
||||
@@ -136,7 +136,7 @@ function pillStateFor(
|
||||
* sync attempt failed. The pill conveys "something is wrong"; this
|
||||
* line tells the user *what* is wrong so they can act on it. Keeping
|
||||
* it deliberately small (one icon + one line) so it doesn't recreate
|
||||
* the v1.4.18 redundant banner Marc removed.
|
||||
* the v1.4.18 redundant banner the maintainer removed.
|
||||
*/
|
||||
function IntegrationErrorMessage({ message }: { message: string }) {
|
||||
return (
|
||||
@@ -653,7 +653,7 @@ function MoodLogCard({
|
||||
</p>
|
||||
|
||||
{/* v1.4.19 A5 — visual divider matches Withings for consistency
|
||||
(Marc explicitly called the asymmetry out). */}
|
||||
(the maintainer explicitly called the asymmetry out). */}
|
||||
<hr
|
||||
data-testid="integration-card-divider"
|
||||
className="border-border/60 mt-4"
|
||||
@@ -736,7 +736,7 @@ function MoodLogCard({
|
||||
{/* v1.4.19 A5 — The "letzter Sync" line that used to
|
||||
live here is gone. The pill in the card header
|
||||
already carries that information; repeating it
|
||||
inside the body is the redundancy Marc flagged. The
|
||||
inside the body is the redundancy the maintainer flagged. The
|
||||
entry-count is the only number we still surface
|
||||
because it's an integration-specific datapoint the
|
||||
pill cannot convey. */}
|
||||
|
||||
@@ -258,7 +258,7 @@ function ChannelRow({
|
||||
|
||||
{/* v1.4.15 H4 design: action buttons hit the WCAG 2.5.5 44 px
|
||||
floor on mobile via `min-h-11`. Settings is the most-touched
|
||||
mobile surface; `size="sm"` here clips to ~32 px which Marc
|
||||
mobile surface; `size="sm"` here clips to ~32 px which the maintainer
|
||||
flagged as too small on the iPad/iPhone PWA shell. */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{channel.state === "auto_disabled" && (
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Tabs, TabsList, TabsTrigger } from "../tabs";
|
||||
|
||||
describe("<TabsList>", () => {
|
||||
it("clamps the y-axis so a fixed-height strip never paints a vertical scrollbar", () => {
|
||||
// Marc reported a stray "mini scroll-button" on the right side of
|
||||
// the maintainer reported a stray "mini scroll-button" on the right side of
|
||||
// the feedback inbox tab strip (Open / Acknowledged / Resolved /
|
||||
// Archived). Root cause: `overflow-x-auto` couples to `overflow-y`
|
||||
// — once one axis is `auto`, the other can no longer be `visible`,
|
||||
|
||||
@@ -42,7 +42,7 @@ function Tabs({
|
||||
// ~1 px taller than the strip on some glyph stacks, a tiny painted
|
||||
// vertical scrollbar appeared on the right edge of short strips
|
||||
// (e.g. the admin feedback `Open / Acknowledged / Resolved /
|
||||
// Archived` tabs Marc reported in v1.4.19). Locking the y-axis hides
|
||||
// Archived` tabs the maintainer reported in v1.4.19). Locking the y-axis hides
|
||||
// that bar without affecting horizontal swipe behaviour.
|
||||
// Padding sits at `p-1` (4 px) so the 3 px focus-visible ring
|
||||
// (`focus-visible:ring-[3px]`) on triggers stays inside the
|
||||
|
||||
Reference in new issue
Block a user