feat: Add statistics tracking and fix clipboard API

- Add personal statistics with badges for each attempt count
- Track solved puzzles per attempt (1-6) and failed attempts
- Display statistics after game completion
- Fix clipboard API issue with fallback method
- Add footer with attribution
This commit is contained in:
Hördle Bot
2025-11-21 13:20:45 +01:00
parent ed87bd8c97
commit ea26649558
5 changed files with 252 additions and 22 deletions

View File

@@ -3,6 +3,7 @@
import { useEffect, useState } from 'react';
import AudioPlayer from './AudioPlayer';
import GuessInput from './GuessInput';
import Statistics from './Statistics';
import { useGameState } from '../lib/gameState';
interface GameProps {
@@ -16,7 +17,7 @@ interface GameProps {
const UNLOCK_STEPS = [2, 4, 7, 11, 16, 30];
export default function Game({ dailyPuzzle }: GameProps) {
const { gameState, addGuess } = useGameState();
const { gameState, statistics, addGuess } = useGameState();
const [hasWon, setHasWon] = useState(false);
const [hasLost, setHasLost] = useState(false);
const [shareText, setShareText] = useState('Share Result');
@@ -68,10 +69,25 @@ export default function Game({ dailyPuzzle }: GameProps) {
const speaker = hasWon ? '🔉' : '🔇';
const text = `Hördle #${dailyPuzzle.id}\n\n${speaker}${emojiGrid}\n\n#Hördle #Music\n\nhttps://hoerdle.elpatron.me`;
navigator.clipboard.writeText(text).then(() => {
// Fallback method for copying to clipboard
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
setShareText('Copied!');
setTimeout(() => setShareText('Share Result'), 2000);
});
} catch (err) {
console.error('Failed to copy:', err);
setShareText('Copy failed');
setTimeout(() => setShareText('Share Result'), 2000);
} finally {
document.body.removeChild(textarea);
}
};
return (
@@ -123,6 +139,7 @@ export default function Game({ dailyPuzzle }: GameProps) {
<div className="message-box success">
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', marginBottom: '0.5rem' }}>You won!</h2>
<p>Come back tomorrow for a new song.</p>
{statistics && <Statistics statistics={statistics} />}
<button onClick={handleShare} className="btn-primary" style={{ marginTop: '1rem' }}>
{shareText}
</button>
@@ -133,6 +150,7 @@ export default function Game({ dailyPuzzle }: GameProps) {
<div className="message-box failure">
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', marginBottom: '0.5rem' }}>Game Over</h2>
<p>The song was hidden.</p>
{statistics && <Statistics statistics={statistics} />}
<button onClick={handleShare} className="btn-primary" style={{ marginTop: '1rem' }}>
{shareText}
</button>