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);