diff --git a/public/index.html b/public/index.html index 92ad49c..7633ff2 100644 --- a/public/index.html +++ b/public/index.html @@ -400,6 +400,86 @@ opacity: 0.7; } + /* ── Results Leaderboard ───────────────────────────────── */ + .results-header { + text-align: center; + margin-bottom: 16px; + } + .results-header h2 { font-size: 1.1rem; color: var(--accent); margin-bottom: 4px; } + .results-header p { font-size: 0.75rem; color: var(--text-muted); } + .results-category { + margin-bottom: 20px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 12px 14px; + } + .results-category-header { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 10px; + font-size: 0.8rem; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + } + .results-row { + display: flex; + align-items: center; + gap: 10px; + padding: 7px 0; + border-bottom: 1px solid var(--border); + } + .results-row:last-child { border-bottom: none; } + .results-rank { + font-size: 0.85rem; + font-weight: 700; + width: 28px; + text-align: center; + flex-shrink: 0; + } + .results-rank.gold { color: #ffd700; } + .results-rank.silver { color: #c0c0c0; } + .results-rank.bronze { color: #cd7f32; } + .results-name { + flex: 1; + font-size: 0.82rem; + color: var(--text); + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .results-name.winner { + color: var(--accent); + font-weight: 700; + } + .results-votes { + font-size: 0.75rem; + color: var(--text-muted); + flex-shrink: 0; + } + .results-bar-bg { + flex: 2; + height: 4px; + background: var(--surface2); + border-radius: 2px; + overflow: hidden; + } + .results-bar-fill { + height: 100%; + border-radius: 2px; + transition: width 0.6s cubic-bezier(0.4,0,0.2,1); + } + .results-share { + text-align: center; + margin-top: 16px; + font-size: 0.72rem; + color: var(--text-muted); + } + /* ── Toast ──────────────────────────────────────────────── */ .toast { position: fixed; @@ -629,17 +709,32 @@ // ── Init ─────────────────────────────────────────────────── function init() { + // Check for ?view=results URL param — skip name modal, go to results + const params = new URLSearchParams(location.search); + const viewResults = params.get('view') === 'results'; + if (state.voterName) { applyVoterName(state.voterName); } + + // If view=results, skip name modal and go to results tab + if (viewResults) { + activeTab = 'results'; + document.getElementById('nameModal').classList.add('hidden'); + } + connectWS(); renderTabs(); - document.getElementById('voterNameInput').addEventListener('keydown', e => { - if (e.key === 'Enter') submitName(); - }); - document.getElementById('voterNameInput').focus(); + render(); - // Number keys 1-5 to switch tabs + if (!viewResults) { + document.getElementById('voterNameInput').addEventListener('keydown', e => { + if (e.key === 'Enter') submitName(); + }); + document.getElementById('voterNameInput').focus(); + } + + // Number keys 1-6 to switch tabs document.addEventListener('keydown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; const num = parseInt(e.key); @@ -749,7 +844,7 @@ onkeydown="handleTabKey(event, '${cat.id}')"> ${cat.emoji} ${cat.name} - ${state.options.filter(o => o.categoryId === cat.id).length} + ${cat.id === 'results' ? '' : state.options.filter(o => o.categoryId === cat.id).length} `).join(''); bar.setAttribute('role', 'tablist'); @@ -782,7 +877,54 @@ // ── Render options ──────────────────────────────────────── function render() { const list = document.getElementById('optionsList'); - const opts = state.options.filter(o => o.categoryId === activeTab); + + // ── Results tab ────────────────────────────────────────── + if (activeTab === 'results') { + const votingCats = state.categories.filter(c => c.id !== 'results'); + const totalVotes = state.options.reduce((sum, o) => sum + o.votes.length, 0); + const statusText = state.pollsOpen + ? `🏈 ${state.totalVoters} voter${state.totalVoters !== 1 ? 's' : ''} · ${totalVotes} total votes · Polls OPEN` + : `🏆 ${state.totalVoters} voter${state.totalVoters !== 1 ? 's' : ''} · ${totalVotes} total votes · Polls CLOSED`; + + list.innerHTML = ` +
${statusText}
+