diff --git a/js/facr-frontend.js b/js/facr-frontend.js index bd643c4..ea2b277 100644 --- a/js/facr-frontend.js +++ b/js/facr-frontend.js @@ -16,8 +16,8 @@ const [d, t] = s.split(' '); const [day, month, year] = d.split('.').map(Number); const [hour, minute] = t.split(':').map(Number); - const dt = new Date(Date.UTC(year, month-1, day, hour, minute)); - // adjust to Prague timezone visually + // Interpret as local time (Europe/Prague). Using local constructor avoids UTC offset skew. + const dt = new Date(year, month-1, day, hour, minute); return dt; }catch(e){ return null; } } @@ -34,9 +34,24 @@ .facr-tab{ padding:6px 10px; margin:4px; border-radius:16px; border:1px solid #c42221; color:#c42221; background:#ffffff; font-weight:600; } .facr-tab.active{ background:#c42221; color:#ffffff; } .facr-tab:hover{ background:#c42221cc; color:#ffffff; } + .facr-inline-status{ margin-left:8px; font-weight:700; font-size:14px; white-space:nowrap; color:inherit; display:inline-block; vertical-align:middle; } + /* Default (desktop): show middle only */ + #facr-countdown{ display:none !important; } + .facr-inline-status{ display:none !important; } + .facr-mob-center-score{ display:none; font-weight:700; font-size:24px; line-height:1; } + /* Mobile: keep only the bottom countdown by default */ + @media (max-width: 767px){ + #facr-mid{ display:none !important; } + #facr-countdown{ display:block !important; } + .facr-inline-status{ display:none !important; } + .facr-mob-center-score{ display:inline-block !important; } + /* If finished, hide the bottom countdown */ + .facr-finished #facr-countdown{ display:none !important; } + } @media (max-width: 480px){ #facr-mid{ font-size:28px !important; min-width:100px; } .facr-tab{ padding:4px 8px; font-size:14px; } + .facr-inline-status{ font-size:12px; margin-left:6px; } .facr-nav{ padding:4px 8px; } } `; @@ -158,11 +173,27 @@ return; } - // Prefer first future match; if none, show the latest recent within 3 days + // Selection policy: + // 1) If there is any finished match within the last 3 days across competitions, + // show the latest such finished match (keep result visible for 3 days) + // 2) Otherwise, show the first future match + // 3) If none, show the latest overall (shouldn't happen as items filtered by 3d window per-comp) const now = new Date(); - let autoIdx = items.findIndex(it => it.dt >= now); - if(autoIdx === -1) autoIdx = items.length - 1; - const idx = Math.min(state.matchIndex || autoIdx, items.length-1); + const threeDms = 3*24*60*60*1000; + let latestRecentIdx = -1; + let latestRecentTime = -Infinity; + items.forEach((it, i) => { + const dtms = it.dt.getTime(); + if(dtms <= now.getTime() && now.getTime() - dtms <= threeDms){ + if(dtms > latestRecentTime){ latestRecentTime = dtms; latestRecentIdx = i; } + } + }); + let preferredIdx = latestRecentIdx; + if(preferredIdx === -1){ + preferredIdx = items.findIndex(it => it.dt >= now); + if(preferredIdx === -1) preferredIdx = items.length - 1; + } + const idx = Math.min(state.matchIndex || preferredIdx, items.length-1); const { comp, match:m } = items[idx]; const compName = truncate(escapeHTML(comp.name || comp.code || 'Soutěž'), 60); @@ -179,26 +210,60 @@ const isToday = matchDayCZ === todayCZ(); const startDt = m.date_time ? parseCZDate(m.date_time) : null; const diffMsPre = startDt ? (startDt.getTime() - new Date().getTime()) : 0; - const midText = (!isToday && diffMsPre > 0) ? `Za ${fmtCountdownLong(diffMsPre)}` : (m.score || '-'); + const midText = (diffMsPre > 0) ? `Za ${fmtCountdownLong(diffMsPre)}` : (m.score || '-'); + + // Determine status flags and parse score parts if any + const now2_forTpl = new Date(); + const startMs_forTpl = m.date_time ? parseCZDate(m.date_time).getTime() : 0; + const diff_forTpl = startMs_forTpl - now2_forTpl.getTime(); + const twoH_forTpl = 2*60*60*1000; + const threeD_forTpl = 3*24*60*60*1000; + const isFuture = diff_forTpl > 0; + const isLive = Math.abs(diff_forTpl) <= twoH_forTpl; + const isRecentFinished = (!isFuture && !isLive && -diff_forTpl < threeD_forTpl); + const scoreStr = m.score || ''; + const s1 = scoreStr && scoreStr.includes(':') ? escapeHTML(scoreStr.split(':')[0]) : ''; + const s2 = scoreStr && scoreStr.includes(':') ? escapeHTML(scoreStr.split(':')[1]) : ''; + // Date/time formatting for display lines + const dtForDisp = startDt || (m.date_time ? parseCZDate(m.date_time) : null); + const dd = dtForDisp ? String(dtForDisp.getDate()).padStart(1,'') : ''; + const mm = dtForDisp ? String(dtForDisp.getMonth()+1).padStart(1,'') : ''; + const yyyy = dtForDisp ? dtForDisp.getFullYear() : ''; + const HH = dtForDisp ? String(dtForDisp.getHours()).padStart(2,'0') : ''; + const MM = dtForDisp ? String(dtForDisp.getMinutes()).padStart(2,'0') : ''; + const dateOnly = dtForDisp ? `${dd}. ${mm}. ${yyyy}` : ''; + const timeToken = (m.date_time || '').split(' ')[1] || ''; + const timeOnly = dtForDisp ? `${HH}:${MM}` : ''; + const timeDisplay = dtForDisp ? ((timeToken === '' || timeToken === '00:00') ? 'Bude upřesněno' : timeOnly) : ''; + const venue = m.venue || ''; + const wrapperExtraClass = (isRecentFinished && s1 && s2) ? ' facr-finished' : ''; + + const headerLabel = isLive ? 'Aktuální zápas' : (isFuture ? 'Nadcházející zápas' : (isRecentFinished ? 'Poslední zápas' : `Zápasy (${idx+1}/${items.length})`)); root.innerHTML = ` -