From 16c045e7ccd1421558c4218472df769a1691b05b Mon Sep 17 00:00:00 2001 From: Samuel Enocsson Date: Mon, 8 Jun 2026 08:24:09 +0200 Subject: [PATCH 1/2] feat: add refresh button to mobile player card (#26) --- public/css/mobile.css | 21 +++++++++++++++++++++ public/js/players.js | 14 ++++++++++---- views/partials/ratings-cards.ejs | 5 +++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/public/css/mobile.css b/public/css/mobile.css index ccc5c87..41ab2e9 100644 --- a/public/css/mobile.css +++ b/public/css/mobile.css @@ -342,6 +342,27 @@ transform: rotate(180deg); } + /* Refresh button: hidden by default, revealed only when the card is open. + Larger than the desktop icon to give a comfortable touch target (≥44px). */ + .m-card__head .m-refresh-icon { + display: none; + } + + .m-card.is-open .m-card__head .m-refresh-icon { + display: grid; + width: 44px; + height: 44px; + margin-left: 0; + font-size: 15px; + opacity: 0.7; + flex-shrink: 0; + } + + .m-card.is-open .m-card__head .m-refresh-icon:active { + opacity: 1; + color: var(--accent); + } + .m-card__body { display: grid; grid-template-columns: minmax(0, 1fr) auto; diff --git a/public/js/players.js b/public/js/players.js index 7334ee4..ffd4024 100644 --- a/public/js/players.js +++ b/public/js/players.js @@ -131,10 +131,16 @@ async function clearCache() { // Refreshes both the current rating and the prediction in one click, then // re-swaps the table so every derived value (deltas, pills, sparkline) reflects // the new state. Cheaper than fine-grained DOM updates and guaranteed consistent -// because the server renders the truth. +// because the server renders the truth. The mobile cards partial is included +// inside ratings-table, so swapping #ratings-table re-renders both views at once. async function refreshPlayerData(pdgaNumber) { - const icon = document.querySelector(`#row-${pdgaNumber} .cell-actions .refresh-icon`); - if (icon) icon.classList.add('spinning'); + // The desktop row exists in the DOM even on mobile (hidden via CSS), so spin + // both possible icons; only the one visible in the active viewport is seen. + const icons = [ + document.querySelector(`#row-${pdgaNumber} .cell-actions .refresh-icon`), + document.querySelector(`#m-card-${pdgaNumber} .m-refresh-icon`) + ].filter(Boolean); + icons.forEach(icon => icon.classList.add('spinning')); try { await Promise.allSettled([ fetch(`/api/refresh-player/${pdgaNumber}`, { method: 'POST' }), @@ -144,7 +150,7 @@ async function refreshPlayerData(pdgaNumber) { } catch (error) { console.error('Error refreshing player data:', error); } finally { - if (icon) icon.classList.remove('spinning'); + icons.forEach(icon => icon.classList.remove('spinning')); } } diff --git a/views/partials/ratings-cards.ejs b/views/partials/ratings-cards.ejs index 009de31..eec74ad 100644 --- a/views/partials/ratings-cards.ejs +++ b/views/partials/ratings-cards.ejs @@ -65,6 +65,11 @@ function renderSparkline(values, opts) { <%= player.name %> #<%= player.pdgaNumber %> + From 2ef7de4e5886cb4676d71594da2070adf9880e60 Mon Sep 17 00:00:00 2001 From: Samuel Enocsson Date: Mon, 8 Jun 2026 08:44:51 +0200 Subject: [PATCH 2/2] fix: spin only the icon glyph in mobile refresh button (#26) --- public/css/mobile.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/css/mobile.css b/public/css/mobile.css index 41ab2e9..a92c8e7 100644 --- a/public/css/mobile.css +++ b/public/css/mobile.css @@ -363,6 +363,17 @@ color: var(--accent); } + /* Spin only the icon glyph, not the 44px button box — otherwise the button's + lingering touch-hover frame (background + border) rotates too, which looks odd. */ + .m-card.is-open .m-card__head .m-refresh-icon.spinning { + animation: none; + } + + .m-card.is-open .m-card__head .m-refresh-icon.spinning i { + display: inline-block; + animation: spin 0.8s linear infinite; + } + .m-card__body { display: grid; grid-template-columns: minmax(0, 1fr) auto;