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