diff --git a/src/app.js b/src/app.js
index 93dd366..15d0e75 100644
--- a/src/app.js
+++ b/src/app.js
@@ -814,12 +814,14 @@
if (e.target === lightbox) lightbox.close();
});
- // ---------- weekly charts ----------
+ // ---------- daily charts (last 14 days) ----------
+ const CHART_DAYS = 14;
+
function weeklyData(events) {
const today = startOfDay(new Date());
const now = Date.now();
const days = [];
- for (let i = 6; i >= 0; i--) {
+ for (let i = CHART_DAYS - 1; i >= 0; i--) {
const d = new Date(today);
d.setDate(d.getDate() - i);
const from = startOfDay(d).getTime();
@@ -846,6 +848,12 @@
return date.toLocaleDateString(undefined, { weekday: "short" });
}
+ // With 14 columns there is no room for a label under every bar, so label
+ // today and every second day counting back from it.
+ function showDayLabel(i, len) {
+ return (len - 1 - i) % 2 === 0;
+ }
+
// Pick a chart Y maximum and tick count so every tick label is a clean
// whole number (avoids 0, 0, 1, 1, 2 from rounding fractional steps):
// 1-unit gridlines up to 10, 2-unit up to 20, 5-unit beyond.
@@ -911,7 +919,7 @@
const rawMax = Math.max(...days.map(d => d.sleepHours));
const { yMax, steps: ySteps } = niceAxisSleepHours(rawMax);
- const gap = 6;
+ const gap = 4;
const barW = (innerW - (days.length - 1) * gap) / days.length;
const parts = [];
@@ -934,10 +942,12 @@
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
`
${escapeText(title)}`
);
- parts.push(
- `` +
- `${escapeText(dayLabel(d.date, isToday))}`
- );
+ if (showDayLabel(i, days.length)) {
+ parts.push(
+ `` +
+ `${escapeText(dayLabel(d.date, isToday))}`
+ );
+ }
});
setChartSVG(svg, parts);
@@ -953,8 +963,8 @@
const rawMax = Math.max(...days.flatMap(d => [d.pees, d.poos, d.meals]));
const { yMax, steps: ySteps } = niceAxis(rawMax);
- const groupGap = 6;
- const innerBarGap = 2;
+ const groupGap = 4;
+ const innerBarGap = 1.5;
const groupW = (innerW - (days.length - 1) * groupGap) / days.length;
const barW = (groupW - 2 * innerBarGap) / 3;
@@ -989,10 +999,12 @@
);
});
- parts.push(
- `` +
- `${escapeText(dayLabel(d.date, isToday))}`
- );
+ if (showDayLabel(i, days.length)) {
+ parts.push(
+ `` +
+ `${escapeText(dayLabel(d.date, isToday))}`
+ );
+ }
});
setChartSVG(svg, parts);
@@ -1013,7 +1025,7 @@
const { yMax, steps: ySteps } = niceAxisGrams(Math.max(...days.map(d => d.grams)));
- const gap = 6;
+ const gap = 4;
const barW = (innerW - (days.length - 1) * gap) / days.length;
const parts = [];
@@ -1036,10 +1048,12 @@
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
`${escapeText(title)}`
);
- parts.push(
- `` +
- `${escapeText(dayLabel(d.date, isToday))}`
- );
+ if (showDayLabel(i, days.length)) {
+ parts.push(
+ `` +
+ `${escapeText(dayLabel(d.date, isToday))}`
+ );
+ }
});
setChartSVG(svg, parts);
diff --git a/src/changelog.json b/src/changelog.json
index c9b0fe9..b136aad 100644
--- a/src/changelog.json
+++ b/src/changelog.json
@@ -1,4 +1,5 @@
[
+ { "date": "2026-07-13", "text": "The sleep, daily counts and food charts now cover the last 14 days instead of 7" },
{ "date": "2026-07-13", "text": "The awake/asleep timer lives in the frozen top bar" },
{ "date": "2026-07-13", "text": "The day picker is a bar frozen at the top of the page" },
{ "date": "2026-07-13", "text": "Attach multiple photos to an event — the photo picker now also offers the gallery with multi-select" },
diff --git a/src/index.html b/src/index.html
index 9df038e..8f1cf9e 100644
--- a/src/index.html
+++ b/src/index.html
@@ -176,14 +176,14 @@
- Last 7 days
+ Last 14 days
Daily counts
-
+
Pees
Poos
@@ -192,7 +192,7 @@