diff --git a/frontend.tsx b/frontend.tsx index 9719130..a1de7c0 100644 --- a/frontend.tsx +++ b/frontend.tsx @@ -5,8 +5,20 @@ import "./frontend.css"; // ── Types ──────────────────────────────────────────────────────────────────── type Model = { id: string; name: string }; -type TaskInfo = { model: Model; startedAt: number; finishedAt?: number; result?: string; error?: string }; -type VoteInfo = { voter: Model; startedAt: number; finishedAt?: number; votedFor?: Model; error?: boolean }; +type TaskInfo = { + model: Model; + startedAt: number; + finishedAt?: number; + result?: string; + error?: string; +}; +type VoteInfo = { + voter: Model; + startedAt: number; + finishedAt?: number; + votedFor?: Model; + error?: boolean; +}; type RoundState = { num: number; phase: "prompting" | "answering" | "voting" | "done"; @@ -19,8 +31,18 @@ type RoundState = { scoreA?: number; scoreB?: number; }; -type GameState = { completed: RoundState[]; active: RoundState | null; scores: Record; done: boolean }; -type ServerMessage = { type: "state"; data: GameState; totalRounds: number; viewerCount: number }; +type GameState = { + completed: RoundState[]; + active: RoundState | null; + scores: Record; + done: boolean; +}; +type ServerMessage = { + type: "state"; + data: GameState; + totalRounds: number; + viewerCount: number; +}; // ── Model colors & logos ───────────────────────────────────────────────────── @@ -46,7 +68,8 @@ function getLogo(name: string): string | null { if (name.includes("DeepSeek")) return "/assets/logos/deepseek.svg"; if (name.includes("GLM")) return "/assets/logos/glm.svg"; if (name.includes("GPT")) return "/assets/logos/openai.svg"; - if (name.includes("Opus") || name.includes("Sonnet")) return "/assets/logos/claude.svg"; + if (name.includes("Opus") || name.includes("Sonnet")) + return "/assets/logos/claude.svg"; if (name.includes("Grok")) return "/assets/logos/grok.svg"; if (name.includes("MiniMax")) return "/assets/logos/minimax.svg"; return null; @@ -55,14 +78,23 @@ function getLogo(name: string): string | null { // ── Helpers ────────────────────────────────────────────────────────────────── function Dots() { - return ...; + return ( + + . + . + . + + ); } function ModelTag({ model, small }: { model: Model; small?: boolean }) { const logo = getLogo(model.name); const color = getColor(model.name); return ( - + {logo && } {model.name} @@ -76,9 +108,12 @@ function PromptCard({ round }: { round: RoundState }) { return (
- is writing a prompt + is writing a prompt + +
+
+
-
); } @@ -86,14 +121,18 @@ function PromptCard({ round }: { round: RoundState }) { if (round.promptTask.error) { return (
-
Prompt generation failed
+
+ Prompt generation failed +
); } return (
-
Prompted by
+
+ Prompted by +
{round.prompt}
); @@ -102,7 +141,12 @@ function PromptCard({ round }: { round: RoundState }) { // ── Contestant ─────────────────────────────────────────────────────────────── function ContestantCard({ - task, voteCount, totalVotes, isWinner, showVotes, voters, + task, + voteCount, + totalVotes, + isWinner, + showVotes, + voters, }: { task: TaskInfo; voteCount: number; @@ -126,7 +170,9 @@ function ContestantCard({
{!task.finishedAt ? ( -

+

+ +

) : task.error ? (

{task.error}

) : ( @@ -137,18 +183,36 @@ function ContestantCard({ {showVotes && (
-
+
- {voteCount} - vote{voteCount !== 1 ? "s" : ""} + + {voteCount} + + + vote{voteCount !== 1 ? "s" : ""} + {voters.map((v, i) => { const logo = getLogo(v.voter.name); return logo ? ( - {v.voter.name} + {v.voter.name} ) : ( - + {v.voter.name[0]} ); @@ -168,26 +232,31 @@ function Arena({ round, total }: { round: RoundState; total: number | null }) { const showVotes = round.phase === "voting" || round.phase === "done"; const isDone = round.phase === "done"; - let votesA = 0, votesB = 0; + let votesA = 0, + votesB = 0; for (const v of round.votes) { if (v.votedFor?.name === contA.name) votesA++; else if (v.votedFor?.name === contB.name) votesB++; } const totalVotes = votesA + votesB; - const votersA = round.votes.filter(v => v.votedFor?.name === contA.name); - const votersB = round.votes.filter(v => v.votedFor?.name === contB.name); + const votersA = round.votes.filter((v) => v.votedFor?.name === contA.name); + const votersB = round.votes.filter((v) => v.votedFor?.name === contB.name); const phaseText = - round.phase === "prompting" ? "Writing prompt" : - round.phase === "answering" ? "Answering" : - round.phase === "voting" ? "Judges voting" : - "Complete"; + round.phase === "prompting" + ? "Writing prompt" + : round.phase === "answering" + ? "Answering" + : round.phase === "voting" + ? "Judges voting" + : "Complete"; return (
- Round {round.num}{total ? /{total} : null} + Round {round.num} + {total ? /{total} : null} {phaseText}
@@ -234,7 +303,10 @@ function GameOver({ scores }: { scores: Record }) { {champion && champion[1] > 0 && (
👑 - + {getLogo(champion[0]) && } {champion[0]} @@ -247,19 +319,30 @@ function GameOver({ scores }: { scores: Record }) { // ── Standings ──────────────────────────────────────────────────────────────── -function Standings({ scores, activeRound }: { scores: Record; activeRound: RoundState | null }) { +function Standings({ + scores, + activeRound, +}: { + scores: Record; + activeRound: RoundState | null; +}) { const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]); const maxScore = sorted[0]?.[1] || 1; const competing = activeRound - ? new Set([activeRound.contestants[0].name, activeRound.contestants[1].name]) + ? new Set([ + activeRound.contestants[0].name, + activeRound.contestants[1].name, + ]) : new Set(); return (