"use client"; import * as React from "react"; import { Plus, Trophy, X } from "lucide-react"; import { PromptDialog } from "@/components/common/prompt-dialog"; import { Tooltip } from "@/components/ui/tooltip"; import { useLocalStorage } from "@/lib/client/hooks"; import { BUILTIN_CRITERIA, customCriterion, type Criterion } from "@/lib/arena/scoring"; import { cn } from "@/lib/utils"; export const CRITERIA_STORAGE_KEY = "polyllm:arena-criteria"; /** Custom criteria persisted in localStorage (`polyllm:arena-criteria`). */ export function useCustomCriteria() { const [stored, setStored] = useLocalStorage<{ id: string; label: string }[]>(CRITERIA_STORAGE_KEY, []); const custom = React.useMemo(() => stored.map((c) => customCriterion(c.label) ?? { id: c.id, label: c.label, short: c.label, ratingKey: "bestCustom", custom: true }).filter((c) => c.id), [stored]); const add = React.useCallback( (label: string): Criterion | null => { const c = customCriterion(label); if (!c) return null; setStored((prev) => (prev.some((p) => p.id === c.id) ? prev : [...prev, { id: c.id, label: c.label }].slice(0, 12))); return c; }, [setStored], ); const remove = React.useCallback((id: string) => setStored((prev) => prev.filter((p) => p.id !== id)), [setStored]); const all = React.useMemo(() => [...BUILTIN_CRITERIA, ...custom], [custom]); return { custom, all, add, remove }; } interface Props { criteria: Criterion[]; /** Criterion ids won by this response. */ won: ReadonlySet; onToggle: (criterionId: string, on: boolean) => void; onAddCriterion?: (label: string) => void; onRemoveCriterion?: (id: string) => void; busy?: boolean; disabled?: boolean; className?: string; } /** Criteria chips under a response. One vote per criterion per session — voting here moves the vote. */ export function VotePanel({ criteria, won, onToggle, onAddCriterion, onRemoveCriterion, busy, disabled, className }: Props) { const [adding, setAdding] = React.useState(false); return (
{criteria.map((c) => { const on = won.has(c.id); return ( {c.custom && onRemoveCriterion ? ( ) : null} ); })} {onAddCriterion ? ( <> { onAddCriterion(v); }} /> ) : null}
); }