TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1"use client";2import * as React from "react";3import { BLIND_LETTERS } from "@/lib/arena/scoring";4import { cn } from "@/lib/utils";56/** Neutral letter avatar used while identities are hidden in Blind Arena. */7export function BlindAvatar({ index, size = 20, className }: { index: number; size?: number; className?: string }) {8 const letter = BLIND_LETTERS[index] ?? String(index + 1);9 return (10 <span className={cn("inline-flex shrink-0 items-center justify-center rounded-full bg-fg font-mono font-semibold text-bg", className)} style={{ width: size, height: size, fontSize: Math.max(9, Math.round(size * 0.55)) }} aria-label={`Model ${letter}`}>11 {letter}12 </span>13 );14}1516/**17 * Card-flip reveal: rotates the children 90° around Y, swaps content at the midpoint, rotates back.18 * `flipping` is driven by the parent; the content already reflects the new state when it flips back.19 */20export function Flip({ flipping, children, className }: { flipping: boolean; children: React.ReactNode; className?: string }) {21 return (22 <span className={cn("inline-flex min-w-0 items-center transition-transform duration-150 ease-out [backface-visibility:hidden] [transform-style:preserve-3d] motion-reduce:transition-none", flipping ? "[transform:rotateY(90deg)]" : "[transform:rotateY(0deg)]", className)}>23 {children}24 </span>25 );26}2728/** Drives a two-phase flip: returns `[flipping, trigger]`; `onMidpoint` fires when the card is edge-on. */29export function useFlip(durationMs = 150): [boolean, (onMidpoint: () => void) => void] {30 const [flipping, setFlipping] = React.useState(false);31 const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);32 React.useEffect(33 () => () => {34 if (timer.current) clearTimeout(timer.current);35 },36 [],37 );38 const trigger = React.useCallback(39 (onMidpoint: () => void) => {40 setFlipping(true);41 timer.current = setTimeout(() => {42 onMidpoint();43 setFlipping(false);44 }, durationMs);45 },46 [durationMs],47 );48 return [flipping, trigger];49}50