/* ─── Dualbat home-sections.jsx — 홈 리디자인 전용 컴포넌트 ──────────────
원본: design_handoff_landing_redesign/components.jsx
IIFE 래퍼로 기존 sections.jsx의 Header·Hero·등과 이름 충돌 차단.
`window.KBHome*` prefix로 export — app.jsx에서 명시적으로 호출.
*/
(function(){
const { useState, useEffect, useMemo, useRef } = React;
const D = window.KB_HOME_DATA;
const TEAM_COLORS = window.KB_TEAM_COLORS || {};
function relDate(s){
const m = (s||"").match(/^(\d{4})-(\d{2})-(\d{2})$/); if(!m) return s;
const pub = new Date(+m[1], +m[2]-1, +m[3]);
const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const days = Math.round((today-pub)/86400000);
if (days<=0) return "오늘"; if (days===1) return "어제"; if (days<=7) return `${days}일 전`;
return `${+m[2]}/${+m[3]}`;
}
/* ─── Icons ─────────────────────────────────────────────────────────── */
const I = {
search:(p)=>,
moon:(p)=>,
sun:(p)=>,
star:(p)=>,
arrow:(p)=>,
home:(p)=>,
user:(p)=>,
vs:(p)=>,
pin:(p)=>,
menu:(p)=>,
};
/* ─── Header ─────────────────────────────────────────────────────────── */
function Header(){
const [isDark, setIsDark] = useState(()=>localStorage.getItem("dualbat_theme")==="dark");
useEffect(()=>{
// .home2026 스코프 내 토글 (글 페이지의 :root 토큰 영향 X)
const root = document.querySelector(".home2026") || document.documentElement;
root.setAttribute("data-theme", isDark?"dark":"light");
localStorage.setItem("dualbat_theme", isDark?"dark":"light");
},[isDark]);
const items = [
{id:"home",label:"홈",active:true},{id:"today",label:"오늘 경기"},{id:"mlb",label:"MLB"},
{id:"kbo",label:"KBO"},{id:"players",label:"선수"},{id:"rank",label:"랭킹"},{id:"guide",label:"가이드"},
];
return (
);
}
/* ─── Hero — single clear spotlight ──────────────────────────────────── */
function Hero(){
const h = D.hero;
return (
한국인 MLB
오늘의 메이저리거
갱신 {h.updated} · MLB Stats API
{h.ko[0]}
{h.ko}
{h.today.vs} · {h.today.date}
{h.today.line}
{h.role}
{h.stats.map((s,i)=>(
))}
📅 오늘 KBO 5경기 매치업 분석
최근 4경기 폼
{h.form.map((g,i)=>(
{g.date}
{g.line}
))}
다른 한국인 선수
{h.others.map((p,i)=>(
{p.team}
{p.ko}
{p.line}
))}
✦ 선수 1대1 비교 도구
);
}
/* ─── Today's KBO games ──────────────────────────────────────────────── */
function Games(){
return (
2026-06-07 · 5경기
오늘 KBO 경기
전체 일정
);
}
/* ─── Analysis — lead + compact rows ─────────────────────────────────── */
function Analysis(){
const lead = D.lead;
return (
);
}
/* ─── Player carousel ────────────────────────────────────────────────── */
function Carousel(){
return (
);
}
/* ─── Career chart ───────────────────────────────────────────────────── */
function CareerChart(){
const c = D.career, S = c.seasons;
const W=760, H=300, padL=44, padR=20, padT=24, padB=40;
const xs = (i)=> padL + i*((W-padL-padR)/(S.length-1));
const lo=.60, hi=1.05;
const ys = (v)=> padT + (1-(v-lo)/(hi-lo))*(H-padT-padB);
const kIdx = S.map((s,i)=>({s,i})).filter(o=>o.s.lg==="kbo");
const mIdx = S.map((s,i)=>({s,i})).filter(o=>o.s.lg==="mlb");
const line = (arr)=> arr.map((o,j)=> `${j===0?"M":"L"} ${xs(o.i).toFixed(1)} ${ys(o.s.ops).toFixed(1)}`).join(" ");
const area = (arr)=>{
const d = arr.map((o,j)=>`${j===0?"M":"L"} ${xs(o.i).toFixed(1)} ${ys(o.s.ops).toFixed(1)}`).join(" ");
return `${d} L ${xs(arr[arr.length-1].i).toFixed(1)} ${H-padB} L ${xs(arr[0].i).toFixed(1)} ${H-padB} Z`;
};
const grid = [.6,.7,.8,.9,1.0];
return (
KBO 2017–2022
MLB 2024–현재
KBO 통산 OPS .896 · 2022 정점 .996 → MLB 적응기 거쳐 2026 .808 회복 중 · 출처 KBO 공식 · MLB Stats API
);
}
/* ─── Leaderboard ────────────────────────────────────────────────────── */
function Sparkbars({ data, color }){
const max = 4;
return (
{data.map((v,i)=>(
=3?color:(v>=1?`color-mix(in srgb, ${color} 55%, transparent)`:"var(--hairline-strong)")}}/>
))}
);
}
function Leaderboard(){
const [tab, setTab] = useState("kbo");
const lb = D.leaderboards[tab];
const max = Math.max(...lb.rows.map(r=>r.ops), 0.5);
const LINKS = window.KB_HOME_PLAYER_LINKS || {};
return (
2026 리더보드
OPS 기준 탑 플레이어
자동 갱신 · {tab==="kbo"?"KBO 공식":"MLB Stats API"}
| # |
선수 |
OPS |
시즌 OPS 비교 |
최근 5경기 |
경기 |
홈런 |
타점 |
타율 |
{lb.rows.map((r,i)=>{
const tc = TEAM_COLORS[r.sub.split(" ")[0]] || "var(--card-2)";
const accent = tab==="mlb" ? "var(--mlb)" : "var(--kbo)";
const href = LINKS[r.name];
const trProps = href ? {
onClick: () => { window.location.href = href; },
onKeyDown: (e) => { if (e.key==="Enter") window.location.href = href; },
role: "link",
tabIndex: 0,
title: `${r.name} 페이지로 이동`,
style: { cursor: "pointer" },
} : { style: { cursor: "default" } };
return (
| {i+1} |
=3?9:11,fontWeight:800,color:"#fff"}}>{r.sub.split(" ")[0]}
|
{r.ops?r.ops.toFixed(3).replace(/^0/,""):"—"} |
{r.ops?`${Math.round((r.ops/max)*100)}%`:"—"}
|
|
{r.g||"—"} |
{r.hr} |
{r.rbi||"—"} |
{r.avg?r.avg.toFixed(3).replace(/^0/,""):"—"} |
);})}
);
}
/* ─── Guides ─────────────────────────────────────────────────────────── */
function Guides(){
return (
입문자 가이드
처음 보는 야구 데이터, 5분이면 이해
전체 24편
);
}
/* ─── Footer ─────────────────────────────────────────────────────────── */
function Footer(){
const cols = [
{ h:"선수", items:[["이정후 — SF","/players/이정후.html"],["김혜성 — LAD","/players/김혜성.html"],["김하성 — ATL","/players/김하성.html"],["오늘 KBO 경기 ✦","/today.html"]] },
{ h:"레전드", items:[["박찬호 124승","/players/박찬호.html"],["류현진 78승","/players/류현진.html"],["추신수 218HR","/players/추신수.html"],["한국인 MLB 순위","/players/korean-mlb-ranking.html"]] },
{ h:"도구", items:[["선수 1대1 비교 ✦","/tools/compare.html"],["드림팀 빌더","/tools/dreamteam.html"],["히트존 매핑","/tools/heatzone.html"],["KBO 10팀 시즌","/teams/"]] },
{ h:"가이드", items:[["가이드 전체 24편","/guides/"],["wRC+가 뭐야?","/guides/wrc-plus.html"],["WAR 5분","/guides/war.html"],["Statcast 풀이","/guides/statcast.html"]] },
];
return (
);
}
/* ─── Mobile tab bar ─────────────────────────────────────────────────── */
function MobileTabBar(){
const tabs = [
{id:"home",label:"홈",icon:I.home,href:"#"},{id:"today",label:"오늘",icon:I.vs,href:"/today.html"},
{id:"players",label:"선수",icon:I.user,href:"#players"},{id:"rank",label:"랭킹",icon:I.pin,href:"#rank"},
{id:"guide",label:"가이드",icon:I.menu,href:"#guide"},
];
return (
);
}
/* IIFE export — 명시적 prefix로 기존 sections.jsx와 분리 */
Object.assign(window, {
KBHomeHeader: Header,
KBHomeHero: Hero,
KBHomeGames: Games,
KBHomeAnalysis: Analysis,
KBHomeCarousel: Carousel,
KBHomeCareerChart: CareerChart,
KBHomeLeaderboard: Leaderboard,
KBHomeGuides: Guides,
KBHomeFooter: Footer,
KBHomeMobileTabBar: MobileTabBar,
});
})();