added blackout timer
|
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 930 B After Width: | Height: | Size: 930 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,46 @@
|
|||||||
|
.timer {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 6px;
|
||||||
|
border: 3px solid;
|
||||||
|
background: #000;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
gap: 3px;
|
||||||
|
padding: 2px 3px;
|
||||||
|
border-width: 2px;
|
||||||
|
font-size: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .icon {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blink during the last second so the return of the board isn't a surprise. */
|
||||||
|
.ending {
|
||||||
|
animation: blink 0.25s steps(2) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { itemVisual } from '../theme/assets';
|
||||||
|
import styles from './BlackoutTimer.module.css';
|
||||||
|
|
||||||
|
/** Seconds left on a player's blackout, in the corner of their board. */
|
||||||
|
export function BlackoutTimer({ remaining, small = false }: { remaining: number; small?: boolean }) {
|
||||||
|
if (remaining <= 0) return null;
|
||||||
|
const visual = itemVisual('blind');
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={[styles.timer, small ? styles.small : '', remaining < 1 ? styles.ending : ''].join(' ')}
|
||||||
|
style={{ color: visual.color, borderColor: visual.color }}
|
||||||
|
title={visual.name}
|
||||||
|
>
|
||||||
|
<img className={styles.icon} src={visual.icon} alt="" />
|
||||||
|
{remaining.toFixed(1)}s
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import type { PlayerState } from '../net/types';
|
import type { PlayerState } from '../net/types';
|
||||||
import type { ItemFlash } from '../net/useGameConnection';
|
import type { ItemFlash } from '../net/useGameConnection';
|
||||||
|
import { BlackoutTimer } from './BlackoutTimer';
|
||||||
import { BoardCanvas } from './BoardCanvas';
|
import { BoardCanvas } from './BoardCanvas';
|
||||||
import { ItemBar } from './ItemBar';
|
import { ItemBar } from './ItemBar';
|
||||||
import { ItemFlashOverlay } from './ItemFlashOverlay';
|
import { ItemFlashOverlay } from './ItemFlashOverlay';
|
||||||
@@ -29,6 +30,7 @@ export const MiniBoard = memo(function MiniBoard({ state, width, height, slot, s
|
|||||||
</div>
|
</div>
|
||||||
<BoardCanvas state={state} width={width} height={height} cell={cell} highlighted={selected}>
|
<BoardCanvas state={state} width={width} height={height} cell={cell} highlighted={selected}>
|
||||||
<ItemFlashOverlay flashes={flashes} small />
|
<ItemFlashOverlay flashes={flashes} small />
|
||||||
|
<BlackoutTimer remaining={state.alive ? state.invisibleRemaining : 0} small />
|
||||||
</BoardCanvas>
|
</BoardCanvas>
|
||||||
<div className={styles.items} style={{ width: width * cell + 6 }}>
|
<div className={styles.items} style={{ width: width * cell + 6 }}>
|
||||||
<ItemBar items={state.inventory} size={Math.max(10, cell)} />
|
<ItemBar items={state.inventory} size={Math.max(10, cell)} />
|
||||||
|
|||||||