hud and timer bar
This commit is contained in:
@@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user