hud and timer bar

This commit is contained in:
2025-12-16 22:05:26 +02:00
parent 36a35bbbbf
commit a905e575f4
+125
View File
@@ -0,0 +1,125 @@
import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { IconClockFilled, IconCircleCheckFilled, IconEyeFilled, IconBookmarkFilled, IconChecks,
IconBoltFilled, IconPlayerTrackNextFilled, IconArrowBackUp, IconArrowForwardUp,
IconPencil, IconBallpenFilled, IconShieldCheckFilled } from '@tabler/icons-react'
import { useStore } from '../store'
import Tooltip from './ui/Tooltip'
export default function InfoBar() {
const elapsed = useStore((s) => s.elapsed)
const startTime = useStore((s) => s.startTime)
const paused = useStore((s) => s.paused)
const tick = useStore((s) => s.tick)
const selectedCell = useStore((s) => s.selectedCell)
const checkCell = useStore((s) => s.checkCell)
const revealLetter = useStore((s) => s.revealLetter)
const revealWord = useStore((s) => s.revealWord)
const validateSolution = useStore((s) => s.validateSolution)
const gameMode = useStore((s) => s.gameMode)
const timeLimit = useStore((s) => s.timeLimit)
const marathonCount = useStore((s) => s.marathonCount)
const hintsUsed = useStore((s) => s.hintsUsed)
const solved = useStore((s) => s.solved)
const undo = useStore((s) => s.undo)
const redo = useStore((s) => s.redo)
const undoStack = useStore((s) => s.undoStack)
const redoStack = useStore((s) => s.redoStack)
const pencilMode = useStore((s) => s.pencilMode)
const togglePencilMode = useStore((s) => s.togglePencilMode)
const autoCheck = useStore((s) => s.autoCheck)
const toggleAutoCheck = useStore((s) => s.toggleAutoCheck)
const { t } = useTranslation()
useEffect(() => {
if (!startTime || paused) return
const id = setInterval(tick, 1000)
return () => clearInterval(id)
}, [startTime, paused, tick])
const isSpeedRun = gameMode === 'speedrun'
const isMarathon = gameMode === 'marathon'
const displayTime = isSpeedRun && timeLimit > 0
? Math.max(0, timeLimit - elapsed)
: elapsed
const mins = Math.floor(displayTime / 60)
const secs = displayTime % 60
const timeWarning = isSpeedRun && timeLimit > 0 && (timeLimit - elapsed) <= 30
return (
<div className="info-bar">
<span className={`timer ${timeWarning ? 'timer-warning' : ''}`}>
{isSpeedRun && <IconBoltFilled size={11} style={{ color: '#fbbf24', marginRight: 2 }} aria-hidden="true" />}
{isMarathon && <IconPlayerTrackNextFilled size={11} style={{ color: '#60a5fa', marginRight: 2 }} aria-hidden="true" />}
<IconClockFilled size={12} style={{ opacity: 0.4, marginRight: 3 }} aria-hidden="true" />
{mins}:{secs.toString().padStart(2, '0')}
{isMarathon && <span className="marathon-count">#{marathonCount + 1}</span>}
</span>
{hintsUsed > 0 && (
<span className="hints-used">{hintsUsed === 1 ? t('game.hintsUsed', { count: hintsUsed }) : t('game.hintsUsed_plural', { count: hintsUsed })}</span>
)}
{!solved && (
<>
<span className="info-bar-sep" />
<Tooltip text={t('game.undoTooltip')}>
<button className="btn btn-sm btn-icon" onClick={undo} disabled={undoStack.length === 0} aria-label={t('game.undo')}>
<IconArrowBackUp size={14} aria-hidden="true" />
</button>
</Tooltip>
<Tooltip text={t('game.redoTooltip')}>
<button className="btn btn-sm btn-icon" onClick={redo} disabled={redoStack.length === 0} aria-label={t('game.redo')}>
<IconArrowForwardUp size={14} aria-hidden="true" />
</button>
</Tooltip>
<Tooltip text={t('game.pencilTooltip')}>
<button className={`btn btn-sm btn-icon${pencilMode ? ' btn-active' : ''}`} onClick={togglePencilMode} aria-label={t('game.pencilToggle')} aria-pressed={pencilMode}>
{pencilMode
? <IconPencil size={14} aria-hidden="true" />
: <IconBallpenFilled size={14} aria-hidden="true" />
}
</button>
</Tooltip>
{!isSpeedRun && !isMarathon && (
<>
<Tooltip text={t('game.autoCheckTooltip')}>
<button className={`btn btn-sm btn-icon${autoCheck ? ' btn-active' : ''}`} onClick={toggleAutoCheck} aria-label={t('game.autoCheckToggle')} aria-pressed={autoCheck}>
<IconShieldCheckFilled size={14} aria-hidden="true" />
</button>
</Tooltip>
<span className="info-bar-sep" />
<Tooltip text={t('game.checkTooltip')}>
<button className="btn btn-sm btn-icon" onClick={checkCell} disabled={!selectedCell} aria-label={t('game.check')}>
<IconCircleCheckFilled size={14} aria-hidden="true" />
</button>
</Tooltip>
<Tooltip text={t('game.revealTooltip')}>
<button className="btn btn-sm btn-icon" onClick={revealLetter} disabled={!selectedCell} aria-label={t('game.reveal')}>
<IconEyeFilled size={14} aria-hidden="true" />
</button>
</Tooltip>
<Tooltip text={t('game.wordTooltip')}>
<button className="btn btn-sm btn-icon" onClick={revealWord} disabled={!selectedCell} aria-label={t('game.word')}>
<IconBookmarkFilled size={14} aria-hidden="true" />
</button>
</Tooltip>
</>
)}
<span className="info-bar-sep" />
<Tooltip text={t('game.validateTooltip')}>
<button className="btn btn-sm" onClick={validateSolution}>
<IconChecks size={13} style={{ verticalAlign: -2, marginRight: 3 }} aria-hidden="true" /> {t('game.validate')}
</button>
</Tooltip>
</>
)}
</div>
)
}