From 77d714a9b03f522032b5b4b8db050b98e4c931f2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 5 May 2026 01:25:21 +0000
Subject: [PATCH 1/5] Initial plan
From 6b95e404bdd2de4af3598d0dffa5f26eb65b290a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 5 May 2026 01:29:13 +0000
Subject: [PATCH 2/5] Initial plan: add y-axis labels to history graphs
Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/e82ead79-3fc3-47ad-b938-294d7a161784
Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
---
package-lock.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 287fef3..38d62f9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "brain-speed-exercises",
- "version": "0.1.0",
+ "version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "brain-speed-exercises",
- "version": "0.1.0",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
"electron-debug": "^4",
From 119ad4667113e46ff70aeef8b52a73bbdc5bc040 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 5 May 2026 01:32:24 +0000
Subject: [PATCH 3/5] Add y-axis labels to history graphs
Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/e82ead79-3fc3-47ad-b938-294d7a161784
Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
---
app/components/historyView.js | 62 ++++++++++++++++++++++--
app/components/tests/historyView.test.js | 43 ++++++++++++++++
app/styles/history.css | 45 +++++++++++++++++
3 files changed, 147 insertions(+), 3 deletions(-)
diff --git a/app/components/historyView.js b/app/components/historyView.js
index 25a6306..5fe0b08 100644
--- a/app/components/historyView.js
+++ b/app/components/historyView.js
@@ -188,7 +188,7 @@ export function createTotalPlayTimeChart(summaryData) {
const svgW = 600;
const svgH = 120;
const pad = {
- top: 10, right: 20, bottom: 28, left: 10,
+ top: 10, right: 20, bottom: 28, left: 52,
};
const plotW = svgW - pad.left - pad.right;
const plotH = svgH - pad.top - pad.bottom;
@@ -200,6 +200,28 @@ export function createTotalPlayTimeChart(summaryData) {
svg.setAttribute('class', 'history-total-chart__svg');
svg.setAttribute('role', 'img');
+ // Y-axis gridlines and tick labels at 0%, 50%, and 100% of scale.
+ [1, 0.5, 0].forEach((fraction) => {
+ const yPos = pad.top + plotH - Math.round(fraction * plotH);
+ const timeMs = Math.round(fraction * maxMs);
+
+ const gridLine = document.createElementNS(SVG_NS, 'line');
+ gridLine.setAttribute('x1', String(pad.left));
+ gridLine.setAttribute('y1', String(yPos));
+ gridLine.setAttribute('x2', String(svgW - pad.right));
+ gridLine.setAttribute('y2', String(yPos));
+ gridLine.setAttribute('class', 'history-total-chart__grid-line');
+ svg.appendChild(gridLine);
+
+ const yLabel = document.createElementNS(SVG_NS, 'text');
+ yLabel.setAttribute('x', String(pad.left - 4));
+ yLabel.setAttribute('y', String(yPos));
+ yLabel.setAttribute('dominant-baseline', 'middle');
+ yLabel.setAttribute('class', 'history-total-chart__y-label');
+ yLabel.textContent = formatDuration(timeMs);
+ svg.appendChild(yLabel);
+ });
+
// Calculate pixel coordinates for each data point.
const points = summaryData.map((d, i) => {
const x = pad.left + (n === 1 ? plotW / 2 : (i / (n - 1)) * plotW);
@@ -241,6 +263,30 @@ export function createTotalPlayTimeChart(summaryData) {
return wrapper;
}
+/**
+ * Create a y-axis element for the bar chart showing time-scale labels.
+ *
+ * Renders tick labels at the top (maximum value), middle (half of maximum),
+ * and bottom (zero) of the bar area so readers can interpret bar heights.
+ *
+ * @private
+ * @param {number} maxMs - Maximum milliseconds shown at the top of the scale.
+ * @returns {HTMLElement} A div element serving as the y-axis scale indicator.
+ */
+function createBarChartYAxis(maxMs) {
+ const yAxis = document.createElement('div');
+ yAxis.className = 'history-chart__y-axis';
+
+ [maxMs, Math.round(maxMs / 2), 0].forEach((ms) => {
+ const tick = document.createElement('span');
+ tick.className = 'history-chart__y-tick';
+ tick.textContent = formatDuration(ms);
+ yAxis.appendChild(tick);
+ });
+
+ return yAxis;
+}
+
/**
* Build the DOM for a single day-column in the per-game bar chart.
*
@@ -318,7 +364,17 @@ export function createBarChart(summaryData, gameIds, manifests) {
recentData.forEach((dayData) => {
recentGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
});
- chartEl.appendChild(recentGrid);
+
+ // Chart area: y-axis on the left, grids on the right.
+ const chartArea = document.createElement('div');
+ chartArea.className = 'history-chart__chart-area';
+ chartArea.appendChild(createBarChartYAxis(maxMs));
+
+ const gridsContainer = document.createElement('div');
+ gridsContainer.className = 'history-chart__grids';
+ gridsContainer.appendChild(recentGrid);
+ chartArea.appendChild(gridsContainer);
+ chartEl.appendChild(chartArea);
// Grid for older (initially hidden) days, followed by the toggle button.
if (hasMore) {
@@ -328,7 +384,7 @@ export function createBarChart(summaryData, gameIds, manifests) {
olderData.forEach((dayData) => {
olderGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
});
- chartEl.appendChild(olderGrid);
+ gridsContainer.appendChild(olderGrid);
const olderCount = olderData.length;
const showMoreBtn = document.createElement('button');
diff --git a/app/components/tests/historyView.test.js b/app/components/tests/historyView.test.js
index f610c39..01c5aa2 100644
--- a/app/components/tests/historyView.test.js
+++ b/app/components/tests/historyView.test.js
@@ -307,6 +307,24 @@ describe('createBarChart()', () => {
const btn = chart.querySelector('.history-chart__show-more-btn');
expect(btn).toBeNull();
});
+
+ it('includes a y-axis element', () => {
+ const chart = createBarChart(summaryData, gameIds, MANIFESTS);
+ const yAxis = chart.querySelector('.history-chart__y-axis');
+ expect(yAxis).not.toBeNull();
+ });
+
+ it('y-axis contains three tick labels', () => {
+ const chart = createBarChart(summaryData, gameIds, MANIFESTS);
+ const ticks = chart.querySelectorAll('.history-chart__y-tick');
+ expect(ticks.length).toBe(3);
+ });
+
+ it('y-axis bottom tick label shows 00:00', () => {
+ const chart = createBarChart(summaryData, gameIds, MANIFESTS);
+ const ticks = [...chart.querySelectorAll('.history-chart__y-tick')];
+ expect(ticks[ticks.length - 1].textContent).toBe('00:00');
+ });
});
// ── createBarChart show-more ──────────────────────────────────────────────────
@@ -429,6 +447,31 @@ describe('createTotalPlayTimeChart()', () => {
expect(labels[0].textContent).toBe('01-01');
});
+ it('SVG contains three y-axis labels at 0%, 50%, and 100% of scale', () => {
+ const chart = createTotalPlayTimeChart(summaryData);
+ const yLabels = chart.querySelectorAll('.history-total-chart__y-label');
+ expect(yLabels.length).toBe(3);
+ });
+
+ it('y-axis top label shows the maximum total time', () => {
+ const chart = createTotalPlayTimeChart(summaryData);
+ const yLabels = [...chart.querySelectorAll('.history-total-chart__y-label')];
+ // summaryData max total: 2024-01-02 has 120000 ms for game-a alone → "02:00"
+ expect(yLabels[0].textContent).toBe('02:00');
+ });
+
+ it('y-axis bottom label shows 00:00', () => {
+ const chart = createTotalPlayTimeChart(summaryData);
+ const yLabels = [...chart.querySelectorAll('.history-total-chart__y-label')];
+ expect(yLabels[yLabels.length - 1].textContent).toBe('00:00');
+ });
+
+ it('SVG contains three horizontal grid lines', () => {
+ const chart = createTotalPlayTimeChart(summaryData);
+ const gridLines = chart.querySelectorAll('.history-total-chart__grid-line');
+ expect(gridLines.length).toBe(3);
+ });
+
it('includes a title paragraph', () => {
const chart = createTotalPlayTimeChart(summaryData);
const title = chart.querySelector('.history-total-chart__title');
diff --git a/app/styles/history.css b/app/styles/history.css
index af377d4..ba29466 100644
--- a/app/styles/history.css
+++ b/app/styles/history.css
@@ -205,12 +205,57 @@
fill: var(--text-subtle);
}
+.history-total-chart__grid-line {
+ stroke: var(--border-color);
+ stroke-width: 1;
+ stroke-dasharray: 3 3;
+}
+
+.history-total-chart__y-label {
+ font-size: 10px;
+ fill: var(--text-subtle);
+ text-anchor: end;
+}
+
/* ── History bar chart ───────────────────────────────────────────────────── */
.history-chart {
margin-bottom: 1.5rem;
}
+/* Flex row wrapping the y-axis and the grids container. */
+.history-chart__chart-area {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.25rem;
+}
+
+/* Y-axis scale indicator aligned with the bar heights. */
+.history-chart__y-axis {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: flex-end;
+ height: 160px; /* Must match .history-chart__bars height. */
+ padding-right: 0.375rem;
+ border-right: 1px solid var(--border-color);
+ flex-shrink: 0;
+ min-width: 2.5rem;
+}
+
+.history-chart__y-tick {
+ font-size: 0.65rem;
+ color: var(--text-subtle);
+ white-space: nowrap;
+ line-height: 1;
+}
+
+/* Scroll container for the day-group grids. */
+.history-chart__grids {
+ flex: 1;
+ min-width: 0;
+}
+
/* Grid container for day groups — 2 columns. */
.history-chart__grid {
display: grid;
From fafa2a2afd6de70db7c941688b4879f1311c2925 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 5 May 2026 01:58:25 +0000
Subject: [PATCH 4/5] Fix bar chart per-group y-axis and thin line chart x-axis
labels
Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/3d0a8ea6-eb98-4e20-baf0-b109d392c3d3
Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
---
app/components/historyView.js | 57 +++++++++++++---------
app/components/tests/historyView.test.js | 25 +++++++++-
app/styles/history.css | 61 +++++++++++-------------
3 files changed, 85 insertions(+), 58 deletions(-)
diff --git a/app/components/historyView.js b/app/components/historyView.js
index 5fe0b08..916398a 100644
--- a/app/components/historyView.js
+++ b/app/components/historyView.js
@@ -30,6 +30,14 @@ const COLOR_SLOT_COUNT = 10;
*/
export const INITIAL_VISIBLE_DAYS = 6;
+/**
+ * Maximum number of x-axis date labels shown on the total play-time line chart.
+ * When there are more data points than this, labels are thinned so they remain readable.
+ *
+ * @type {number}
+ */
+export const MAX_X_LABELS = 10;
+
/**
* Extract all unique YYYY-MM-DD date keys present across all games' dailyTime maps.
*
@@ -163,7 +171,8 @@ export function createDataTable(summaryData, gameIds, manifests) {
* Create a total play-time line chart showing daily totals across all games.
*
* Renders an SVG line chart with one data point per day connected by a line,
- * giving a quick at-a-glance trend of overall activity. Labeled with MM-DD dates.
+ * giving a quick at-a-glance trend of overall activity. X-axis is labeled with
+ * MM-DD dates, thinned to at most {@link MAX_X_LABELS} labels to avoid crowding.
*
* @param {Array<{date: string, total: number}>} summaryData - Per-day totals.
* @returns {HTMLElement} A
element containing the total play-time line chart.
@@ -238,7 +247,9 @@ export function createTotalPlayTimeChart(summaryData) {
svg.appendChild(polyline);
// Dot and date label for each point.
- points.forEach((p) => {
+ // Thin x-axis labels so they remain readable when there are many data points.
+ const labelStep = Math.max(1, Math.ceil(n / MAX_X_LABELS));
+ points.forEach((p, i) => {
const circle = document.createElementNS(SVG_NS, 'circle');
circle.setAttribute('cx', p.x);
circle.setAttribute('cy', p.y);
@@ -250,13 +261,15 @@ export function createTotalPlayTimeChart(summaryData) {
circle.appendChild(tooltipTitle);
svg.appendChild(circle);
- const label = document.createElementNS(SVG_NS, 'text');
- label.setAttribute('x', p.x);
- label.setAttribute('y', svgH - 4);
- label.setAttribute('text-anchor', 'middle');
- label.setAttribute('class', 'history-total-chart__x-label');
- label.textContent = p.date.slice(5); // Display as MM-DD.
- svg.appendChild(label);
+ if (i % labelStep === 0) {
+ const label = document.createElementNS(SVG_NS, 'text');
+ label.setAttribute('x', p.x);
+ label.setAttribute('y', svgH - 4);
+ label.setAttribute('text-anchor', 'middle');
+ label.setAttribute('class', 'history-total-chart__x-label');
+ label.textContent = p.date.slice(5); // Display as MM-DD.
+ svg.appendChild(label);
+ }
});
wrapper.appendChild(svg);
@@ -290,6 +303,9 @@ function createBarChartYAxis(maxMs) {
/**
* Build the DOM for a single day-column in the per-game bar chart.
*
+ * Each day group includes its own y-axis scale indicator on the left so that
+ * every cell in the grid is self-contained and readable without a shared axis.
+ *
* @param {object} dayData - Summary entry for one day.
* @param {string[]} gameIds - Game IDs to render bars for.
* @param {number} maxMs - Maximum total ms across all days (for scaling).
@@ -300,6 +316,11 @@ function createDayGroup(dayData, gameIds, maxMs, manifests) {
const group = document.createElement('div');
group.className = 'history-chart__group';
+ // Body: y-axis on the left, bars on the right.
+ const groupBody = document.createElement('div');
+ groupBody.className = 'history-chart__group-body';
+ groupBody.appendChild(createBarChartYAxis(maxMs));
+
const barsWrap = document.createElement('div');
barsWrap.className = 'history-chart__bars';
@@ -323,11 +344,13 @@ function createDayGroup(dayData, gameIds, maxMs, manifests) {
totalBar.title = `Total: ${formatDuration(totalMs)}`;
barsWrap.appendChild(totalBar);
+ groupBody.appendChild(barsWrap);
+
const dateLabel = document.createElement('span');
dateLabel.className = 'history-chart__label';
dateLabel.textContent = dayData.date.slice(5); // Display as MM-DD.
- group.appendChild(barsWrap);
+ group.appendChild(groupBody);
group.appendChild(dateLabel);
return group;
}
@@ -364,17 +387,7 @@ export function createBarChart(summaryData, gameIds, manifests) {
recentData.forEach((dayData) => {
recentGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
});
-
- // Chart area: y-axis on the left, grids on the right.
- const chartArea = document.createElement('div');
- chartArea.className = 'history-chart__chart-area';
- chartArea.appendChild(createBarChartYAxis(maxMs));
-
- const gridsContainer = document.createElement('div');
- gridsContainer.className = 'history-chart__grids';
- gridsContainer.appendChild(recentGrid);
- chartArea.appendChild(gridsContainer);
- chartEl.appendChild(chartArea);
+ chartEl.appendChild(recentGrid);
// Grid for older (initially hidden) days, followed by the toggle button.
if (hasMore) {
@@ -384,7 +397,7 @@ export function createBarChart(summaryData, gameIds, manifests) {
olderData.forEach((dayData) => {
olderGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
});
- gridsContainer.appendChild(olderGrid);
+ chartEl.appendChild(olderGrid);
const olderCount = olderData.length;
const showMoreBtn = document.createElement('button');
diff --git a/app/components/tests/historyView.test.js b/app/components/tests/historyView.test.js
index 01c5aa2..bf64da7 100644
--- a/app/components/tests/historyView.test.js
+++ b/app/components/tests/historyView.test.js
@@ -19,6 +19,7 @@ import {
createTotalPlayTimeChart,
buildHistoryPanel,
INITIAL_VISIBLE_DAYS,
+ MAX_X_LABELS,
} from '../historyView.js';
// ── Test fixtures ─────────────────────────────────────────────────────────────
@@ -314,10 +315,11 @@ describe('createBarChart()', () => {
expect(yAxis).not.toBeNull();
});
- it('y-axis contains three tick labels', () => {
+ it('y-axis contains three tick labels per day group', () => {
const chart = createBarChart(summaryData, gameIds, MANIFESTS);
const ticks = chart.querySelectorAll('.history-chart__y-tick');
- expect(ticks.length).toBe(3);
+ // 3 ticks per group × number of days in summaryData
+ expect(ticks.length).toBe(summaryData.length * 3);
});
it('y-axis bottom tick label shows 00:00', () => {
@@ -447,6 +449,25 @@ describe('createTotalPlayTimeChart()', () => {
expect(labels[0].textContent).toBe('01-01');
});
+ it('shows all x-axis labels when data points are within MAX_X_LABELS', () => {
+ // summaryData has 3 points, well under MAX_X_LABELS (10)
+ const chart = createTotalPlayTimeChart(summaryData);
+ const labels = chart.querySelectorAll('.history-total-chart__x-label');
+ expect(labels.length).toBe(dates.length);
+ });
+
+ it('thins x-axis labels to at most MAX_X_LABELS when there are many data points', () => {
+ // Build summaryData with MAX_X_LABELS + 5 data points to trigger thinning.
+ const manyDates = Array.from({ length: MAX_X_LABELS + 5 }, (_, i) => {
+ const d = new Date(2024, 0, i + 1);
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
+ });
+ const manyData = manyDates.map((date) => ({ date, total: 60000 }));
+ const chart = createTotalPlayTimeChart(manyData);
+ const labels = chart.querySelectorAll('.history-total-chart__x-label');
+ expect(labels.length).toBeLessThanOrEqual(MAX_X_LABELS);
+ });
+
it('SVG contains three y-axis labels at 0%, 50%, and 100% of scale', () => {
const chart = createTotalPlayTimeChart(summaryData);
const yLabels = chart.querySelectorAll('.history-total-chart__y-label');
diff --git a/app/styles/history.css b/app/styles/history.css
index ba29466..1fcb668 100644
--- a/app/styles/history.css
+++ b/app/styles/history.css
@@ -223,39 +223,6 @@
margin-bottom: 1.5rem;
}
-/* Flex row wrapping the y-axis and the grids container. */
-.history-chart__chart-area {
- display: flex;
- align-items: flex-start;
- gap: 0.25rem;
-}
-
-/* Y-axis scale indicator aligned with the bar heights. */
-.history-chart__y-axis {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: flex-end;
- height: 160px; /* Must match .history-chart__bars height. */
- padding-right: 0.375rem;
- border-right: 1px solid var(--border-color);
- flex-shrink: 0;
- min-width: 2.5rem;
-}
-
-.history-chart__y-tick {
- font-size: 0.65rem;
- color: var(--text-subtle);
- white-space: nowrap;
- line-height: 1;
-}
-
-/* Scroll container for the day-group grids. */
-.history-chart__grids {
- flex: 1;
- min-width: 0;
-}
-
/* Grid container for day groups — 2 columns. */
.history-chart__grid {
display: grid;
@@ -298,7 +265,33 @@
flex-direction: column;
align-items: center;
gap: 0.25rem;
- min-width: 60px;
+}
+
+/* Flex row: per-group y-axis scale on the left, bars on the right. */
+.history-chart__group-body {
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+}
+
+/* Per-group y-axis scale indicator (one per day cell). */
+.history-chart__y-axis {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: flex-end;
+ height: 160px; /* Must match .history-chart__bars height. */
+ padding-right: 0.25rem;
+ border-right: 1px solid var(--border-color);
+ flex-shrink: 0;
+ min-width: 1.75rem;
+}
+
+.history-chart__y-tick {
+ font-size: 0.6rem;
+ color: var(--text-subtle);
+ white-space: nowrap;
+ line-height: 1;
}
.history-chart__bar {
From d8cf10aabc47eeecb8f95b164cb0c74a8b2ec2e7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 5 May 2026 02:08:20 +0000
Subject: [PATCH 5/5] Scale each bar chart day group to its own daily max (not
shared global max)
Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/76eb25ae-aec9-4eb1-bcf4-9fde6983cd84
Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
---
app/components/historyView.js | 29 ++++++++++++------------
app/components/tests/historyView.test.js | 14 ++++++++++--
2 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/app/components/historyView.js b/app/components/historyView.js
index 916398a..4c232e8 100644
--- a/app/components/historyView.js
+++ b/app/components/historyView.js
@@ -303,30 +303,33 @@ function createBarChartYAxis(maxMs) {
/**
* Build the DOM for a single day-column in the per-game bar chart.
*
- * Each day group includes its own y-axis scale indicator on the left so that
- * every cell in the grid is self-contained and readable without a shared axis.
+ * Each day group scales its bars and y-axis to its own total play time, so
+ * the y-axis labels are meaningful for the specific day being displayed.
*
* @param {object} dayData - Summary entry for one day.
* @param {string[]} gameIds - Game IDs to render bars for.
- * @param {number} maxMs - Maximum total ms across all days (for scaling).
* @param {Array<{id: string, name: string}>} [manifests] - Manifest list for names.
* @returns {HTMLElement} A `.history-chart__group` element.
*/
-function createDayGroup(dayData, gameIds, maxMs, manifests) {
+function createDayGroup(dayData, gameIds, manifests) {
+ // Scale this group to its own total so bars fill the available height and
+ // the y-axis tick labels reflect this day's actual values.
+ const dayMaxMs = Math.max(dayData.total, 1);
+
const group = document.createElement('div');
group.className = 'history-chart__group';
// Body: y-axis on the left, bars on the right.
const groupBody = document.createElement('div');
groupBody.className = 'history-chart__group-body';
- groupBody.appendChild(createBarChartYAxis(maxMs));
+ groupBody.appendChild(createBarChartYAxis(dayMaxMs));
const barsWrap = document.createElement('div');
barsWrap.className = 'history-chart__bars';
gameIds.forEach((gameId, colIndex) => {
const ms = dayData[gameId] || 0;
- const heightPct = Math.round((ms / maxMs) * 100);
+ const heightPct = Math.round((ms / dayMaxMs) * 100);
const bar = document.createElement('div');
const colorIndex = colIndex % COLOR_SLOT_COUNT;
bar.className = `history-chart__bar history-chart__bar--color-${colorIndex}`;
@@ -335,13 +338,11 @@ function createDayGroup(dayData, gameIds, maxMs, manifests) {
barsWrap.appendChild(bar);
});
- // Total bar (grey).
- const totalMs = dayData.total;
- const totalPct = Math.round((totalMs / maxMs) * 100);
+ // Total bar (grey) — always 100% height since dayMaxMs === dayData.total.
const totalBar = document.createElement('div');
totalBar.className = 'history-chart__bar history-chart__bar--total';
- totalBar.style.height = `${totalPct}%`;
- totalBar.title = `Total: ${formatDuration(totalMs)}`;
+ totalBar.style.height = '100%';
+ totalBar.title = `Total: ${formatDuration(dayData.total)}`;
barsWrap.appendChild(totalBar);
groupBody.appendChild(barsWrap);
@@ -367,8 +368,6 @@ function createDayGroup(dayData, gameIds, maxMs, manifests) {
* @returns {HTMLElement}
*/
export function createBarChart(summaryData, gameIds, manifests) {
- const maxMs = Math.max(...summaryData.map((d) => d.total), 1);
-
const chartEl = document.createElement('div');
chartEl.className = 'history-chart';
chartEl.setAttribute('aria-hidden', 'true'); // Table is the accessible version.
@@ -385,7 +384,7 @@ export function createBarChart(summaryData, gameIds, manifests) {
const recentGrid = document.createElement('div');
recentGrid.className = 'history-chart__grid';
recentData.forEach((dayData) => {
- recentGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
+ recentGrid.appendChild(createDayGroup(dayData, gameIds, manifests));
});
chartEl.appendChild(recentGrid);
@@ -395,7 +394,7 @@ export function createBarChart(summaryData, gameIds, manifests) {
olderGrid.className = 'history-chart__grid';
olderGrid.hidden = true;
olderData.forEach((dayData) => {
- olderGrid.appendChild(createDayGroup(dayData, gameIds, maxMs, manifests));
+ olderGrid.appendChild(createDayGroup(dayData, gameIds, manifests));
});
chartEl.appendChild(olderGrid);
diff --git a/app/components/tests/historyView.test.js b/app/components/tests/historyView.test.js
index bf64da7..c0e5c3d 100644
--- a/app/components/tests/historyView.test.js
+++ b/app/components/tests/historyView.test.js
@@ -327,9 +327,19 @@ describe('createBarChart()', () => {
const ticks = [...chart.querySelectorAll('.history-chart__y-tick')];
expect(ticks[ticks.length - 1].textContent).toBe('00:00');
});
-});
-// ── createBarChart show-more ──────────────────────────────────────────────────
+ it('each day group y-axis top tick reflects that day\'s own total time', () => {
+ // summaryData uses dates ['2024-01-01', '2024-01-02'].
+ // 2024-01-01: game-a=60000 + game-b=30000 = total 90000 ms → '01:30'
+ // 2024-01-02: game-a=120000 + game-b=0 = total 120000 ms → '02:00'
+ // Groups are rendered newest-first: [2024-01-02, 2024-01-01].
+ const chart = createBarChart(summaryData, gameIds, MANIFESTS);
+ const groups = [...chart.querySelectorAll('.history-chart__group')];
+ const topTickOf = (group) => group.querySelector('.history-chart__y-tick').textContent;
+ expect(topTickOf(groups[0])).toBe('02:00'); // 2024-01-02 total = 120000 ms
+ expect(topTickOf(groups[1])).toBe('01:30'); // 2024-01-01 total = 90000 ms
+ });
+});
describe('createBarChart() show-more behaviour', () => {
const dates = getAllDates(PROGRESS_MANY_DAYS);