|
|
@@ -1,4 +1,5 @@
|
|
|
import type { GameStats, SolverReplay } from '@wordle/shared';
|
|
|
+import { en } from '../messages/en.js';
|
|
|
|
|
|
interface Screen3ResultsProps {
|
|
|
won: boolean;
|
|
|
@@ -9,28 +10,6 @@ interface Screen3ResultsProps {
|
|
|
onPlayAgain?: () => void;
|
|
|
}
|
|
|
|
|
|
-function Histogram({ stats }: { stats: GameStats }) {
|
|
|
- if (stats.gamesPlayed === 0) return <p style={{ color: '#787c7e' }}>No games yet.</p>;
|
|
|
-
|
|
|
- const maxCount = Math.max(...stats.histogram, 1);
|
|
|
-
|
|
|
- return (
|
|
|
- <div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
|
- {stats.histogram.map((count, idx) => {
|
|
|
- const label = idx < 6 ? `${idx + 1}` : 'X';
|
|
|
- const pct = (count / maxCount) * 100;
|
|
|
- return (
|
|
|
- <div key={idx} style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
|
|
- <span style={{ width: '20px', textAlign: 'right', fontWeight: 'bold', color: '#555' }}>{label}</span>
|
|
|
- <div style={{ flex: 1, height: '20px', backgroundColor: count > 0 ? '#6aaa64' : '#d3d6da', width: `${Math.max(pct, count > 0 ? 5 : 0)}%`, minWidth: count > 0 ? '12px' : '4px', borderRadius: '2px' }} />
|
|
|
- <span style={{ width: '24px', fontSize: '0.8rem', color: '#555' }}>{count}</span>
|
|
|
- </div>
|
|
|
- );
|
|
|
- })}
|
|
|
- </div>
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
const MINI_COLORS: Record<string, string> = { g: '#6aaa64', y: '#c9b458', x: '#787c7e' };
|
|
|
|
|
|
function MiniBoard({ replay }: { replay: SolverReplay }) {
|
|
|
@@ -43,12 +22,11 @@ function MiniBoard({ replay }: { replay: SolverReplay }) {
|
|
|
<div key={rowIdx} style={{ display: 'flex', gap: '2px', justifyContent: 'center', marginBottom: '2px' }}>
|
|
|
{step.guess.split('').map((letter, colIdx) => {
|
|
|
const c = step.colors[colIdx];
|
|
|
- const bg = MINI_COLORS[c] ?? '#d3d6da';
|
|
|
return (
|
|
|
<div key={colIdx} style={{
|
|
|
width: '20px', height: '20px',
|
|
|
- backgroundColor: bg,
|
|
|
- color: c === 'x' || !c ? '#fff' : '#fff',
|
|
|
+ backgroundColor: MINI_COLORS[c] ?? '#d3d6da',
|
|
|
+ color: '#fff',
|
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
|
fontSize: '0.55rem', fontWeight: 'bold',
|
|
|
textTransform: 'uppercase', fontFamily: 'monospace',
|
|
|
@@ -64,24 +42,50 @@ function MiniBoard({ replay }: { replay: SolverReplay }) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+function Histogram({ stats }: { stats: GameStats }) {
|
|
|
+ if (stats.gamesPlayed === 0) return <p style={{ color: '#787c7e' }}>{en.results.noGames}</p>;
|
|
|
+
|
|
|
+ const maxCount = Math.max(...stats.histogram, 1);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
|
+ {stats.histogram.map((count, idx) => {
|
|
|
+ const label = idx < 6 ? `${idx + 1}` : 'X';
|
|
|
+ const pct = (count / maxCount) * 100;
|
|
|
+ return (
|
|
|
+ <div key={idx} style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
|
|
+ <span style={{ width: '20px', textAlign: 'right', fontWeight: 'bold', color: '#555' }}>{label}</span>
|
|
|
+ <div style={{ flex: 1, height: '20px', backgroundColor: count > 0 ? '#6aaa64' : '#d3d6da', width: `${Math.max(pct, count > 0 ? 5 : 0)}%`, minWidth: count > 0 ? '12px' : '4px', borderRadius: '2px' }} />
|
|
|
+ <span style={{ width: '24px', fontSize: '0.8rem', color: '#555' }}>{count}</span>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
export function Screen3Results({ won, attemptCount, revealedWord, stats, replays, onPlayAgain }: Screen3ResultsProps) {
|
|
|
+ const r = en.results;
|
|
|
+
|
|
|
return (
|
|
|
<div style={{ maxWidth: '400px', margin: '24px auto', padding: '16px', fontFamily: 'sans-serif', textAlign: 'center' }}>
|
|
|
- <h1 style={{ fontSize: '1.6rem', marginBottom: '12px' }}>{won ? '🎉 Congratulations!' : 'Better luck next time'}</h1>
|
|
|
+ <h1 style={{ fontSize: '1.6rem', marginBottom: '12px' }}>
|
|
|
+ {won ? r.congratulations : r.betterLuck}
|
|
|
+ </h1>
|
|
|
|
|
|
{won ? (
|
|
|
- <p style={{ fontSize: '1.1rem', marginBottom: '8px' }}>Solved in {attemptCount} {attemptCount === 1 ? 'attempt' : 'attempts'}</p>
|
|
|
+ <p style={{ fontSize: '1.1rem', marginBottom: '8px' }}>{r.solvedIn(attemptCount)}</p>
|
|
|
) : (
|
|
|
- revealedWord && <p style={{ fontSize: '1.1rem', marginBottom: '8px' }}>The word was: <strong>{revealedWord.toUpperCase()}</strong></p>
|
|
|
+ revealedWord && <p style={{ fontSize: '1.1rem', marginBottom: '8px' }}>{r.theWordWas(revealedWord)}</p>
|
|
|
)}
|
|
|
|
|
|
<div style={{ margin: '24px 0' }}>
|
|
|
- <h2 style={{ fontSize: '1.1rem', marginBottom: '12px' }}>Statistics</h2>
|
|
|
+ <h2 style={{ fontSize: '1.1rem', marginBottom: '12px' }}>{r.statistics}</h2>
|
|
|
<div style={{ display: 'flex', justifyContent: 'center', gap: '24px', marginBottom: '16px' }}>
|
|
|
- <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.gamesPlayed}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>Played</div></div>
|
|
|
- <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.gamesPlayed > 0 ? Math.round((stats.wins / stats.gamesPlayed) * 100) : 0}%</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>Win Rate</div></div>
|
|
|
- <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.currentStreak}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>Streak</div></div>
|
|
|
- <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.maxStreak}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>Max Streak</div></div>
|
|
|
+ <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.gamesPlayed}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>{r.played}</div></div>
|
|
|
+ <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.gamesPlayed > 0 ? Math.round((stats.wins / stats.gamesPlayed) * 100) : 0}%</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>{r.winRate}</div></div>
|
|
|
+ <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.currentStreak}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>{r.streak}</div></div>
|
|
|
+ <div><div style={{ fontSize: '1.4rem', fontWeight: 'bold' }}>{stats.maxStreak}</div><div style={{ fontSize: '0.75rem', color: '#787c7e' }}>{r.maxStreak}</div></div>
|
|
|
</div>
|
|
|
<Histogram stats={stats} />
|
|
|
</div>
|
|
|
@@ -89,11 +93,11 @@ export function Screen3Results({ won, attemptCount, revealedWord, stats, replays
|
|
|
{replays && replays.length > 0 && (
|
|
|
<div style={{ margin: '24px 0' }}>
|
|
|
<p style={{ fontSize: '0.85rem', color: '#787c7e', marginBottom: '12px' }}>
|
|
|
- How the solvers cracked this word:
|
|
|
+ {r.solverCaption}
|
|
|
</p>
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', maxWidth: '320px', margin: '0 auto' }}>
|
|
|
- {replays.map((r) => (
|
|
|
- <MiniBoard key={r.solver} replay={r} />
|
|
|
+ {replays.map((rp) => (
|
|
|
+ <MiniBoard key={rp.solver} replay={rp} />
|
|
|
))}
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -113,7 +117,7 @@ export function Screen3Results({ won, attemptCount, revealedWord, stats, replays
|
|
|
cursor: 'pointer',
|
|
|
}}
|
|
|
>
|
|
|
- Play Again
|
|
|
+ {r.playAgain}
|
|
|
</button>
|
|
|
)}
|
|
|
</div>
|