일정 카드 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 { timeOnly, dateKey } from "@/lib/format";
|
||||||
import { getLive, type LiveData } from "@/lib/api";
|
import { getLive, type LiveData } from "@/lib/api";
|
||||||
import { type Lang, dict, teamShort, roundLabel as tRound, dayName, monthEn } from "@/lib/i18n";
|
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 TeamFlag from "./TeamFlag";
|
||||||
import StandingsTable from "./StandingsTable";
|
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({
|
function MatchCard({
|
||||||
match,
|
match,
|
||||||
lang,
|
lang,
|
||||||
@ -490,6 +513,15 @@ function MatchCard({
|
|||||||
const rightSt = flip ? match.extras?.standings?.a : match.extras?.standings?.b;
|
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";
|
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)는 상세로 이동
|
// 비투표(타 조)는 클릭 비활성, 투표 가능 조(A)는 상세로 이동
|
||||||
const inner = (
|
const inner = (
|
||||||
<>
|
<>
|
||||||
@ -558,6 +590,24 @@ function MatchCard({
|
|||||||
</div>
|
</div>
|
||||||
</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) && (
|
{isBaseball && !match.result && (match.extras?.starterA || match.extras?.starterB) && (
|
||||||
<div className="mt-2 text-center text-[12px] font-semibold text-white/65">
|
<div className="mt-2 text-center text-[12px] font-semibold text-white/65">
|
||||||
@ -578,13 +628,9 @@ function MatchCard({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 투표 가능 조만: AI 픽 갈림 + 참여수 + 이동 화살표 (취소 경기는 숨김) */}
|
{/* 투표 가능 조만: 참여수 + 이동 화살표 (AI 픽은 위의 아이콘 행이 담당, 취소 경기는 숨김) */}
|
||||||
{match.votable && phase !== "cancelled" && (
|
{match.votable && phase !== "cancelled" && (
|
||||||
<div className="mt-3 flex items-center justify-between text-[12px] font-bold text-[#F4F3FE]">
|
<div className="mt-3 flex items-center justify-end text-[12px] font-bold text-[#F4F3FE]">
|
||||||
<span>
|
|
||||||
<span className="font-semibold text-white/65">{t.aiPicks}</span>{" "}
|
|
||||||
{aiSplit(match, lang).join(" · ")}
|
|
||||||
</span>
|
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
<span>{t.joined((match.crowd?.total ?? 0).toLocaleString())}</span>
|
<span>{t.joined((match.crowd?.total ?? 0).toLocaleString())}</span>
|
||||||
<span className="text-[#94FBE0]">→</span>
|
<span className="text-[#94FBE0]">→</span>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user