diff --git a/src/pages/lotto/Evolver.css b/src/pages/lotto/Evolver.css new file mode 100644 index 0000000..f370eee --- /dev/null +++ b/src/pages/lotto/Evolver.css @@ -0,0 +1,51 @@ +.evolver { max-width: 1100px; margin: 0 auto; padding: 24px 16px; } +.evolver-header { display: flex; justify-content: space-between; align-items: start; margin-bottom: 24px; gap: 16px; } +.evolver-kicker { letter-spacing: 0.12em; color: #6b7280; font-size: 0.75rem; margin: 0 0 4px; } +.evolver-header h1 { margin: 0 0 8px; font-size: 2rem; } +.evolver-sub { color: #6b7280; margin: 0; } +.refresh-btn { padding: 8px 14px; background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 6px; cursor: pointer; } + +.evolver-card { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 20px; margin-bottom: 16px; } +.evolver-card.empty .muted { color: #9ca3af; } +.evolver-card h2 { margin: 0 0 12px; font-size: 1.1rem; display: flex; justify-content: space-between; align-items: center; gap: 8px; } +.evolver-card .badge { background: #ecfdf5; color: #065f46; padding: 2px 8px; border-radius: 4px; font-size: 0.7rem; font-weight: normal; } + +.winner-card .winner-meta { display: flex; gap: 16px; flex-wrap: wrap; color: #6b7280; font-size: 0.9rem; margin-bottom: 12px; } +.winner-card .winner-meta strong { color: #111827; } + +.trials-grid .grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; height: 140px; align-items: end; } +.trial-cell { border: none; background: #f9fafb; border-radius: 6px; padding: 8px 4px; display: flex; flex-direction: column; align-items: center; justify-content: end; cursor: pointer; height: 100%; } +.trial-cell.winner { background: #ecfdf5; } +.trial-cell .bar { width: 80%; background: #34d399; border-radius: 3px 3px 0 0; min-height: 4px; } +.trial-cell.winner .bar { background: #059669; } +.trial-cell .label { font-size: 0.85rem; margin-top: 6px; } +.trial-cell .max-correct { font-size: 0.7rem; color: #6b7280; } +.trial-detail { margin-top: 16px; padding: 12px; background: #f9fafb; border-radius: 6px; } +.trial-detail ul { margin: 8px 0 0; padding-left: 18px; } + +.base-diff .diff-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; } +.metric-card { padding: 12px; background: #f9fafb; border-radius: 8px; text-align: center; } +.metric-card .metric-name { color: #6b7280; font-size: 0.75rem; text-transform: uppercase; } +.metric-card .metric-values { margin: 6px 0; font-size: 0.85rem; } +.metric-card .metric-diff { font-weight: bold; } +.metric-card.up .metric-diff, .metric-card.up-big .metric-diff { color: #059669; } +.metric-card.down .metric-diff, .metric-card.down-big .metric-diff { color: #dc2626; } +.metric-card.eq .metric-diff { color: #9ca3af; } + +.activity-card .activity-list { list-style: none; padding: 0; margin: 0; } +.activity-item { display: grid; grid-template-columns: 24px 1fr auto; gap: 8px; padding: 8px 0; border-bottom: 1px solid #f3f4f6; } +.activity-item .ts { color: #9ca3af; font-size: 0.75rem; white-space: nowrap; } +.activity-item .status.ok { color: #059669; } +.activity-item .status.err { color: #dc2626; } +.activity-item .detail { color: #6b7280; font-size: 0.85rem; } + +.actions-card .action-buttons { display: flex; gap: 8px; flex-wrap: wrap; } +.actions-card button { padding: 8px 14px; background: #1f2937; color: #fff; border: none; border-radius: 6px; cursor: pointer; } +.actions-card button:disabled { opacity: 0.5; cursor: wait; } +.action-output { background: #1f2937; color: #d1d5db; padding: 12px; border-radius: 6px; margin-top: 12px; max-height: 200px; overflow: auto; font-size: 0.8rem; } + +@media (max-width: 640px) { + .trials-grid .grid { grid-template-columns: repeat(3, 1fr); height: auto; } + .base-diff .diff-grid { grid-template-columns: repeat(2, 1fr); } + .evolver-header { flex-direction: column; } +} diff --git a/src/pages/lotto/Evolver.jsx b/src/pages/lotto/Evolver.jsx new file mode 100644 index 0000000..47ca8ba --- /dev/null +++ b/src/pages/lotto/Evolver.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import './Evolver.css'; +import { useEvolverApi } from './evolver/useEvolverApi'; +import WinnerCard from './evolver/WinnerCard'; +import TrialsGrid from './evolver/TrialsGrid'; +import BaseDiff from './evolver/BaseDiff'; +import BaseHistory from './evolver/BaseHistory'; +import LottoActivityTimeline from './evolver/LottoActivityTimeline'; +import EvolverActions from './evolver/EvolverActions'; + +export default function Evolver() { + const { status, history, activity, loading, error, refetch } = useEvolverApi({ days: 7, weeks: 12 }); + + if (loading) return
로딩 중...
에러: {String(error)}
Lotto · Weight Evolver
++ 매주 6가지 가중치를 시도해서 best 조합을 다음주 base로 학습합니다. + {status?.latest_draw && ` 마지막 회차: ${status.latest_draw}회.`} +
+다음 월요일 09:00에 자동 시작 또는 수동 트리거 사용.
+{JSON.stringify(out, null, 2)}}
+ 지난 {days}일 활동 없음.
+