diff --git a/public/css/mobile.css b/public/css/mobile.css index d5f9c4f..53b9032 100644 --- a/public/css/mobile.css +++ b/public/css/mobile.css @@ -13,6 +13,7 @@ .mobile-add-bar { display: none; } .mobile-section-head { display: none; } .m-tab-pill { display: none; } +.m-search-input { display: none; } /* ═══════════════════════════════════════════════════ */ @media (max-width: 880px) { @@ -24,6 +25,37 @@ .add-bar { display: none !important; } .footnote { display: none !important; } + /* Hide desktop search card on mobile (mobile has .m-search-input instead) */ + .card-section { display: none; } + + /* ── Mobile course search input ─────────────────── */ + + .m-search-input { + display: block; + width: 100%; + height: 38px; + padding: 0 12px; + background: var(--paper-2); + border: 1px solid var(--line-2); + border-radius: 10px; + font-family: var(--font-sans); + font-size: 14px; + color: var(--ink); + outline: none; + box-sizing: border-box; + transition: border-color 150ms ease, box-shadow 150ms ease; + } + + .m-search-input::placeholder { + color: var(--ink-3); + opacity: 0.7; + } + + .m-search-input:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 14%, transparent); + } + /* Hide desktop table but keep .table-card as wrapper */ .table-card > #ratings-table table, #ratings-table table, diff --git a/public/css/players.css b/public/css/players.css index 635d7b3..ac98cae 100644 --- a/public/css/players.css +++ b/public/css/players.css @@ -10,16 +10,6 @@ display: none; } -@media (max-width: 768px) { - .mobile-only { - display: block; - } - - .player-name { - font-weight: 600; - } -} - /* ── Rating values ────────────────────────────── */ .rating-value { @@ -286,19 +276,6 @@ background: #059669; } -/* ── Responsive ───────────────────────────────── */ - -@media (max-width: 768px) { - .chart-container { - height: 250px; - margin: 5px 0; - } - - .chart-title { - font-size: 13px; - } -} - /* ── Target Rating Calculator ─────────────────── */ .target-rating-icon { diff --git a/public/js/courses.js b/public/js/courses.js index 566d25b..2f692c9 100644 --- a/public/js/courses.js +++ b/public/js/courses.js @@ -31,32 +31,37 @@ function toggleCourseLayouts(courseId) { } // ── Mobile course card toggle ────────────────────── -var openMobileCourseId = null; +let openMobileCourseId = null; function toggleMobileCourseLayouts(courseId) { - var card = document.getElementById('m-course-' + courseId); + const card = document.getElementById('m-course-' + courseId); if (!card) return; - var isOpen = card.classList.contains('is-open'); + const isOpen = card.classList.contains('is-open'); // Close previously open card if (openMobileCourseId !== null && openMobileCourseId !== courseId) { - var prevCard = document.getElementById('m-course-' + openMobileCourseId); - if (prevCard) prevCard.classList.remove('is-open'); + const prevCard = document.getElementById('m-course-' + openMobileCourseId); + if (prevCard) { + prevCard.classList.remove('is-open'); + prevCard.setAttribute('aria-expanded', 'false'); + } openMobileCourseId = null; } if (isOpen) { card.classList.remove('is-open'); + card.setAttribute('aria-expanded', 'false'); openMobileCourseId = null; return; } card.classList.add('is-open'); + card.setAttribute('aria-expanded', 'true'); openMobileCourseId = courseId; // Lazy-load layouts on first expand - var container = document.getElementById('m-layouts-container-' + courseId); + const container = document.getElementById('m-layouts-container-' + courseId); if (container && container.dataset.loaded !== 'true') { htmx.ajax('GET', '/partials/course-layouts/' + courseId, { target: '#m-layouts-container-' + courseId, swap: 'innerHTML' }); container.dataset.loaded = 'true'; diff --git a/public/js/players.js b/public/js/players.js index dff8c10..ac65cbd 100644 --- a/public/js/players.js +++ b/public/js/players.js @@ -31,8 +31,8 @@ function initChartsIn(rootEl) { if (container.dataset.charted === 'true') return; if (!container.dataset.history) return; try { - var history = JSON.parse(container.dataset.history); - var isMobile = container.dataset.variant === 'mobile'; + const history = JSON.parse(container.dataset.history); + const isMobile = container.dataset.variant === 'mobile'; if (isMobile) { createRatingChart(container, history, { w: 360, @@ -782,32 +782,37 @@ async function refreshHistoryThenCalculate(pdgaNumber) { } // ── Mobile player card toggle ────────────────────── -var openMobilePdgaNumber = null; +let openMobilePdgaNumber = null; function toggleMobilePlayerCard(pdgaNumber) { - var card = document.getElementById('m-card-' + pdgaNumber); + const card = document.getElementById('m-card-' + pdgaNumber); if (!card) return; - var isOpen = card.classList.contains('is-open'); + const isOpen = card.classList.contains('is-open'); // Close previously open card if (openMobilePdgaNumber !== null && openMobilePdgaNumber !== pdgaNumber) { - var prevCard = document.getElementById('m-card-' + openMobilePdgaNumber); - if (prevCard) prevCard.classList.remove('is-open'); + const prevCard = document.getElementById('m-card-' + openMobilePdgaNumber); + if (prevCard) { + prevCard.classList.remove('is-open'); + prevCard.setAttribute('aria-expanded', 'false'); + } openMobilePdgaNumber = null; } if (isOpen) { card.classList.remove('is-open'); + card.setAttribute('aria-expanded', 'false'); openMobilePdgaNumber = null; return; } card.classList.add('is-open'); + card.setAttribute('aria-expanded', 'true'); openMobilePdgaNumber = pdgaNumber; // Init charts inside the expand panel - var expand = card.querySelector('.m-card__expand'); + const expand = card.querySelector('.m-card__expand'); if (expand) { initChartsIn(expand); } @@ -816,20 +821,20 @@ function toggleMobilePlayerCard(pdgaNumber) { // ── Mobile add player ────────────────────────────── async function searchAndAddPlayerMobile(event) { if (event) event.preventDefault(); - var input = document.getElementById('pdga-number-input-mobile'); - var pdgaNumber = input ? input.value.trim() : ''; + const input = document.getElementById('pdga-number-input-mobile'); + const pdgaNumber = input ? input.value.trim() : ''; if (!pdgaNumber) { alert('Please enter a PDGA number'); return; } - var button = event && event.target ? event.target.querySelector('button[type="submit"]') : null; + const button = event && event.target ? event.target.querySelector('button[type="submit"]') : null; if (button) { button.disabled = true; button.textContent = 'Searching...'; } try { - var response = await fetch('/api/search-player/' + pdgaNumber); - var data = await response.json(); + const response = await fetch('/api/search-player/' + pdgaNumber); + const data = await response.json(); if (!response.ok) { showErrorModal(data.error || 'Player not found'); diff --git a/views/pages/courses.ejs b/views/pages/courses.ejs index 9f93f00..8b94723 100644 --- a/views/pages/courses.ejs +++ b/views/pages/courses.ejs @@ -25,6 +25,18 @@ + + +
`; %> diff --git a/views/partials/course-cards.ejs b/views/partials/course-cards.ejs index ab372f9..70e0e87 100644 --- a/views/partials/course-cards.ejs +++ b/views/partials/course-cards.ejs @@ -3,27 +3,25 @@ var _query = (typeof query !== 'undefined') ? query : null; var _total = (typeof total !== 'undefined') ? total : courses.length; %> +<% if (courses.length === 0) { %> +No courses found.
+<% } else { %>No courses found.
-<% } else { %>No players tracked yet.
+<% } else { %>No players tracked yet.
-<% } else { %>