diff --git a/src/app.js b/src/app.js index ed81050..9242346 100644 --- a/src/app.js +++ b/src/app.js @@ -291,6 +291,24 @@ return `${wk} (${monthPhrase}) old`; } + // Compact one-line age for space-tight spots (header): keeps the weeks + months + // breakdown but abbreviated — "16 wk · 3 mo 3 wk", "5 mo 2 wk", "3 wk". + function formatAgeShort(birthday, at) { + const a = ageParts(birthday, at); + if (!a) return ""; + const wk = `${a.weeks} wk`; + if (a.months < 1) return wk; + const mo = `${a.months} mo${a.remWeeks > 0 ? ` ${a.remWeeks} wk` : ""}`; + if (a.months >= 4) return mo; + return `${wk} · ${mo}`; + } + + // Weeks-only age for dense lists (weight rows): "16 wk". + function formatAgeWeeks(birthday, at) { + const a = ageParts(birthday, at); + return a ? `${a.weeks} wk` : ""; + } + // Rough age-based daily sleep goal (hours), for the trend chart's goal band: // 0–8 weeks 20–22h, 8–16 weeks 18–20h, then 16–18h to 6 months and 14–16h to // 12 months. No birthday (or an adult dog) → no goal. @@ -1669,7 +1687,7 @@ li.className = "ww weight-ww"; const date = document.createElement("span"); date.className = "ww-range"; - const age = formatAge(birthday, w.at); + const age = formatAgeWeeks(birthday, w.at); const dateStr = new Date(w.at).toLocaleDateString(undefined, { month: "short", day: "numeric" }); date.textContent = age ? `${dateStr} · ${age}` : dateStr; const val = document.createElement("span"); @@ -1888,7 +1906,7 @@ const ageEl = document.getElementById("puppy-age"); title.textContent = cfg.name ? `🐶 ${cfg.name}` : "🐶 Puppy Tracker"; document.title = cfg.name ? `${cfg.name} · Puppy Tracker` : "Puppy Tracker"; - const ageText = formatAge(cfg.birthday); + const ageText = formatAgeShort(cfg.birthday); ageEl.textContent = ageText; ageEl.hidden = !ageText; // Use the puppy's name in the sleep-timeline heading rather than assuming a diff --git a/src/changelog.json b/src/changelog.json index debea2d..6c68b13 100644 --- a/src/changelog.json +++ b/src/changelog.json @@ -1,4 +1,5 @@ [ + { "date": "2026-08-01", "text": "Tidied the header on long names and ages — the name now truncates instead of shoving the buttons, and the age reads as a compact \"16 wk · 3 mo 3 wk\"; weight-log rows are a single line again (\"Aug 1 · 16 wk\")" }, { "date": "2026-07-26", "text": "Added a fan-chart view of the pedigree (toggle it in the header): your dog at the centre with each generation fanning outward as a ring, so many generations fit at once without the tree sprawling sideways — tap a wedge for that dog, and repeated ancestors keep their colour" }, { "date": "2026-07-26", "text": "Added a Collapse all / Expand all toggle to the pedigree, to fold the whole tree down to your dog or open every branch at once" }, { "date": "2026-07-26", "text": "The pedigree is now zoomable — use the +/− buttons, ⌘/Ctrl-scroll, or pinch on a phone — to fit a wide tree on screen or zoom in for detail; your zoom level is remembered" }, diff --git a/src/style.css b/src/style.css index 2a364a2..1544d90 100644 --- a/src/style.css +++ b/src/style.css @@ -78,13 +78,24 @@ h1 { display: flex; flex-direction: column; gap: 2px; + flex: 1 1 auto; min-width: 0; } +/* Truncate the name so a long one never runs into the action buttons. Scoped to + the header title so the auth-screen heading is unaffected. */ +#app-title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} .puppy-age { font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums; + /* One line in the common case; on a very narrow screen it wraps rather than + truncating, so the age is never cut off. The name (#app-title) is what + truncates to keep the buttons clear. */ } .header-actions { @@ -644,7 +655,16 @@ dialog menu { .weight-summary .stat-value.up { color: var(--gain); } .weight-summary .stat-value.down { color: var(--danger); } .ww.weight-ww { cursor: pointer; } -.ww.weight-ww .ww-dur { text-align: right; } +/* Keep each weight row to one line: the date/age column shrinks and ellipses, + the weight value stays a fixed size, right-aligned and always visible. */ +.ww.weight-ww .ww-range { + min-width: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.ww.weight-ww .ww-dur { flex: 0 0 auto; text-align: right; } .legend { display: flex;