일정 카드 AI 픽을 팀 아래 모델 아이콘으로 표시
기존 "AI 픽 삼성 3" 텍스트 줄 대신 GPT/Claude/Gemini 아이콘을 각자 픽한 팀 쪽 아래에 배치 (무승부 픽은 가운데). 참여수는 우측 유지. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
d6b3ddeee0
commit
8da8b7e7bd
@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
|
||||
import { timeOnly, dateKey } from "@/lib/format";
|
||||
import { getLive, type LiveData } from "@/lib/api";
|
||||
import { type Lang, dict, teamShort, roundLabel as tRound, dayName, monthEn } from "@/lib/i18n";
|
||||
import type { League, Match, MatchPhase } from "@/lib/types";
|
||||
import type { League, Match, MatchPhase, ModelName, Outcome } from "@/lib/types";
|
||||
import TeamFlag from "./TeamFlag";
|
||||
import StandingsTable from "./StandingsTable";
|
||||
|
||||
@ -435,6 +435,29 @@ function RankBadge({ rank, lang = "ko" }: { rank?: number | null; lang?: Lang })
|
||||
);
|
||||
}
|
||||
|
||||
// AI 픽 아이콘 (일정 카드용 — Arena 와 동일 공식 로고)
|
||||
const MODEL_ICON: Record<ModelName, string> = {
|
||||
GPT: "/icons/gpt.png",
|
||||
Claude: "/icons/claude.jpg",
|
||||
Gemini: "/icons/gemini.jpeg",
|
||||
};
|
||||
|
||||
function AiPickIcons({ models }: { models: ModelName[] }) {
|
||||
return (
|
||||
<>
|
||||
{models.map((m) => (
|
||||
<img
|
||||
key={m}
|
||||
src={MODEL_ICON[m]}
|
||||
alt={m}
|
||||
title={m}
|
||||
className="h-[18px] w-[18px] shrink-0 rounded-full border border-white/25 object-cover"
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function MatchCard({
|
||||
match,
|
||||
lang,
|
||||
@ -490,6 +513,15 @@ function MatchCard({
|
||||
const rightSt = flip ? match.extras?.standings?.a : match.extras?.standings?.b;
|
||||
const flagCls = isClub ? "h-7 w-7 shrink-0" : "h-6 w-9 shrink-0";
|
||||
|
||||
// AI 픽: 픽한 팀 아래에 모델 아이콘 배치 (무승부 픽은 가운데)
|
||||
const picksFor = (o: Outcome) =>
|
||||
match.predictions.filter((p) => p.outcome === o).map((p) => p.model);
|
||||
const leftPicks = picksFor(flip ? "TEAM_B_WIN" : "TEAM_A_WIN");
|
||||
const rightPicks = picksFor(flip ? "TEAM_A_WIN" : "TEAM_B_WIN");
|
||||
const drawPicks = picksFor("DRAW");
|
||||
const showAiRow =
|
||||
match.votable && phase !== "cancelled" && match.predictions.length > 0;
|
||||
|
||||
// 비투표(타 조)는 클릭 비활성, 투표 가능 조(A)는 상세로 이동
|
||||
const inner = (
|
||||
<>
|
||||
@ -558,6 +590,24 @@ function MatchCard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI 픽: 각 모델 아이콘을 픽한 팀 아래에 표시 (무승부 픽은 가운데) */}
|
||||
{showAiRow && (
|
||||
<div
|
||||
className="mt-1.5 grid grid-cols-[1fr_auto_1fr] items-center gap-2"
|
||||
aria-label={`${t.aiPicks}: ${aiSplit(match, lang).join(", ")}`}
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<AiPickIcons models={leftPicks} />
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<AiPickIcons models={drawPicks} />
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<AiPickIcons models={rightPicks} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 야구: 선발 매치업 (프리뷰 캐시 있을 때만) */}
|
||||
{isBaseball && !match.result && (match.extras?.starterA || match.extras?.starterB) && (
|
||||
<div className="mt-2 text-center text-[12px] font-semibold text-white/65">
|
||||
@ -578,13 +628,9 @@ function MatchCard({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 투표 가능 조만: AI 픽 갈림 + 참여수 + 이동 화살표 (취소 경기는 숨김) */}
|
||||
{/* 투표 가능 조만: 참여수 + 이동 화살표 (AI 픽은 위의 아이콘 행이 담당, 취소 경기는 숨김) */}
|
||||
{match.votable && phase !== "cancelled" && (
|
||||
<div className="mt-3 flex items-center justify-between text-[12px] font-bold text-[#F4F3FE]">
|
||||
<span>
|
||||
<span className="font-semibold text-white/65">{t.aiPicks}</span>{" "}
|
||||
{aiSplit(match, lang).join(" · ")}
|
||||
</span>
|
||||
<div className="mt-3 flex items-center justify-end text-[12px] font-bold text-[#F4F3FE]">
|
||||
<span className="flex items-center gap-2">
|
||||
<span>{t.joined((match.crowd?.total ?? 0).toLocaleString())}</span>
|
||||
<span className="text-[#94FBE0]">→</span>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user