ip specific votes + ui fixes

This commit is contained in:
Theo Browne
2026-02-22 17:45:08 -08:00
parent 1a5c8354a0
commit 6e98a183ac
3 changed files with 12 additions and 6 deletions

View File

@@ -193,6 +193,7 @@ body {
/* ── Contestant ───────────────────────────────────────────────── */ /* ── Contestant ───────────────────────────────────────────────── */
.contestant { .contestant {
position: relative;
border-left: 3px solid var(--accent); border-left: 3px solid var(--accent);
padding: 16px 20px; padding: 16px 20px;
display: flex; display: flex;
@@ -343,14 +344,18 @@ body {
} }
.my-vote-tag { .my-vote-tag {
position: absolute;
top: 8px;
right: 8px;
font-family: var(--mono); font-family: var(--mono);
font-size: 10px; font-size: 9px;
font-weight: 700; font-weight: 700;
letter-spacing: 1px; letter-spacing: 1px;
padding: 3px 8px; padding: 2px 6px;
border: 1px solid var(--text-muted); border: 1px solid var(--text-muted);
color: var(--text-dim); color: var(--text-dim);
border-radius: 3px; border-radius: 3px;
pointer-events: none;
} }
/* ── Viewer Votes ────────────────────────────────────────────── */ /* ── Viewer Votes ────────────────────────────────────────────── */

View File

@@ -195,9 +195,9 @@ function ContestantCard({
> >
<div className="contestant__head"> <div className="contestant__head">
<ModelTag model={task.model} /> <ModelTag model={task.model} />
{isMyVote && <span className="my-vote-tag">YOUR PICK</span>}
{isWinner && <span className="win-tag">WIN</span>} {isWinner && <span className="win-tag">WIN</span>}
</div> </div>
{isMyVote && <span className="my-vote-tag">YOUR PICK</span>}
<div className="contestant__body"> <div className="contestant__body">
{!task.finishedAt ? ( {!task.finishedAt ? (

View File

@@ -229,7 +229,7 @@ function setHistoryCache(key: string, body: string, expiresAt: number) {
// ── WebSocket clients ─────────────────────────────────────────────────────── // ── WebSocket clients ───────────────────────────────────────────────────────
const clients = new Set<ServerWebSocket<WsData>>(); const clients = new Set<ServerWebSocket<WsData>>();
const viewerVoters = new Map<ServerWebSocket<WsData>, "A" | "B">(); const viewerVoters = new Map<string, "A" | "B">();
let viewerVoteBroadcastTimer: ReturnType<typeof setTimeout> | null = null; let viewerVoteBroadcastTimer: ReturnType<typeof setTimeout> | null = null;
function scheduleViewerVoteBroadcast() { function scheduleViewerVoteBroadcast() {
@@ -624,14 +624,15 @@ const server = Bun.serve<WsData>({
if (!round.viewerVotingEndsAt || Date.now() > round.viewerVotingEndsAt) return; if (!round.viewerVotingEndsAt || Date.now() > round.viewerVotingEndsAt) return;
if (msg.votedFor !== "A" && msg.votedFor !== "B") return; if (msg.votedFor !== "A" && msg.votedFor !== "B") return;
const previousVote = viewerVoters.get(ws); const ip = ws.data.ip;
const previousVote = viewerVoters.get(ip);
if (previousVote === msg.votedFor) return; // same vote, ignore if (previousVote === msg.votedFor) return; // same vote, ignore
// Undo previous vote if changing // Undo previous vote if changing
if (previousVote === "A") round.viewerVotesA = Math.max(0, (round.viewerVotesA ?? 0) - 1); if (previousVote === "A") round.viewerVotesA = Math.max(0, (round.viewerVotesA ?? 0) - 1);
else if (previousVote === "B") round.viewerVotesB = Math.max(0, (round.viewerVotesB ?? 0) - 1); else if (previousVote === "B") round.viewerVotesB = Math.max(0, (round.viewerVotesB ?? 0) - 1);
viewerVoters.set(ws, msg.votedFor); viewerVoters.set(ip, msg.votedFor);
if (msg.votedFor === "A") round.viewerVotesA = (round.viewerVotesA ?? 0) + 1; if (msg.votedFor === "A") round.viewerVotesA = (round.viewerVotesA ?? 0) + 1;
else round.viewerVotesB = (round.viewerVotesB ?? 0) + 1; else round.viewerVotesB = (round.viewerVotesB ?? 0) + 1;