diff --git a/public/css/shared.css b/public/css/shared.css index f436b20..bc23b8b 100644 --- a/public/css/shared.css +++ b/public/css/shared.css @@ -592,3 +592,72 @@ a:hover { color: var(--ink-3); margin-top: 2px; } + +/* ── Table Toolbar + Pill Toggle ─────────────── */ + +.table-toolbar { + display: flex; + justify-content: flex-end; + margin-bottom: 12px; +} + +.pill-toggle { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 12px 5px 10px; + border-radius: 999px; + border: 1px solid var(--line-2); + background: var(--paper-2); + color: var(--ink-2); + font-size: 12px; + font-weight: 600; + font-family: var(--font-sans); + cursor: pointer; + transition: background 150ms ease, border-color 150ms ease, color 150ms ease; +} + +.pill-toggle:hover { + background: var(--hover); + border-color: var(--line); +} + +.pill-toggle[aria-pressed="true"] { + background: color-mix(in oklab, var(--accent) 10%, white); + border-color: color-mix(in oklab, var(--accent) 35%, var(--line-2)); + color: var(--accent-text); +} + +.pill-icon { + width: 12px; + height: 12px; + flex-shrink: 0; +} + +.pill-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--ink-3); + opacity: 0.4; + transition: background 150ms ease, opacity 150ms ease, box-shadow 150ms ease; +} + +.pill-toggle[aria-pressed="true"] .pill-dot { + background: var(--accent); + opacity: 1; + box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 20%, transparent); +} + +/* ── Sparklines ───────────────────────────────── */ + +.sparkline { + display: inline-block; + vertical-align: middle; + line-height: 0; + margin-top: 4px; +} + +body[data-sparklines="off"] .sparkline { + display: none; +} diff --git a/public/js/players.js b/public/js/players.js index 5741082..63a5806 100644 --- a/public/js/players.js +++ b/public/js/players.js @@ -480,3 +480,20 @@ function closeAddPlayerModal(event) { document.getElementById('add-player-modal').style.display = 'none'; pendingPlayerData = null; } + +// ── Sparkline toggle ─────────────────────────────── +document.addEventListener('DOMContentLoaded', function() { + var btn = document.getElementById('trendchart-toggle'); + if (!btn) return; + + var state = localStorage.getItem('ratingtracker.sparklines') || 'on'; + document.body.dataset.sparklines = state; + btn.setAttribute('aria-pressed', state === 'on' ? 'true' : 'false'); + + btn.addEventListener('click', function() { + var next = document.body.dataset.sparklines === 'on' ? 'off' : 'on'; + document.body.dataset.sparklines = next; + btn.setAttribute('aria-pressed', next === 'on' ? 'true' : 'false'); + localStorage.setItem('ratingtracker.sparklines', next); + }); +}); diff --git a/views/pages/index.ejs b/views/pages/index.ejs index 0287684..b1b5a58 100644 --- a/views/pages/index.ejs +++ b/views/pages/index.ejs @@ -19,6 +19,15 @@
+
+ +
`; %> diff --git a/views/partials/ratings-table.ejs b/views/partials/ratings-table.ejs index c73a84f..1795b94 100644 --- a/views/partials/ratings-table.ejs +++ b/views/partials/ratings-table.ejs @@ -1,3 +1,33 @@ +<% +function renderSparkline(values) { + if (!values || values.length < 2) return ''; + var w = 96, h = 28; + var min = Math.min.apply(null, values); + var max = Math.max.apply(null, values); + var range = max - min || 1; + var xStep = w / (values.length - 1); + + var pts = values.map(function(v, i) { + return { + x: (i * xStep).toFixed(1), + y: (((max - v) / range) * (h - 4) + 2).toFixed(1) + }; + }); + + var linePath = pts.map(function(p, i) { + return (i === 0 ? 'M' : 'L') + ' ' + p.x + ' ' + p.y; + }).join(' '); + + var last = pts[pts.length - 1]; + var areaPath = linePath + ' L ' + last.x + ' ' + h + ' L 0 ' + h + ' Z'; + + return '' + + '' + + '' + + '' + + ''; +} +%> <% if (ratings.length === 0) { %>

No ratings found.

<% } else { %> @@ -20,6 +50,8 @@ var deltaPredicted = player.deltaPredicted ?? null; var deltaPredictedPillText = deltaPredicted != null ? (deltaPredicted > 0 ? '+' + deltaPredicted : deltaPredicted.toString()) : null; var deltaPredictedPillClass = deltaPredicted > 0 ? 'up' : deltaPredicted < 0 ? 'down' : 'flat'; + + var sparklineSvg = renderSparkline(player.monthlyHistory || []); %> <%= index + 1 %> @@ -36,6 +68,9 @@ <% if (ratingChangePillText) { %> <%= ratingChangePillText %> <% } %> + <% if (sparklineSvg) { %> + <%- sparklineSvg %> + <% } %>