forked from external-repos/LifeTrinket
Compare commits
4 Commits
bugfix/chr
...
feature/ti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4130e069bb | ||
|
|
e7e5882859 | ||
|
|
c6039c2a53 | ||
|
|
6d6da2ad79 |
51
package.json
51
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "life-trinket",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"type": "commonjs",
|
||||
"engines": {
|
||||
"node": ">=20",
|
||||
@@ -17,39 +17,42 @@
|
||||
"deploy": "bun run build && firebase deploy --only hosting"
|
||||
},
|
||||
"dependencies": {
|
||||
"firebase": "^10.3.0",
|
||||
"@mui/icons-material": "^6.4.5",
|
||||
"@mui/material": "^6.4.5",
|
||||
"firebase": "^10.14.1",
|
||||
"ga-4-react": "^0.1.281",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-screen-wake-lock": "^3.0.2",
|
||||
"react-swipeable": "^7.0.1",
|
||||
"react-twc": "^1.3.0",
|
||||
"semver": "^7.6.2",
|
||||
"zod": "^3.22.4"
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-timer-hook": "^3.0.8",
|
||||
"react-twc": "^1.4.2",
|
||||
"semver": "^7.7.1",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@savvywombat/tailwindcss-grid-areas": "^4.0.0",
|
||||
"@svgr/cli": "^8.1.0",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"@typescript-eslint/parser": "^7.8.0",
|
||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"firebase-tools": "^13.7.5",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"firebase-tools": "^13.31.2",
|
||||
"install": "^0.13.0",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "2.8.8",
|
||||
"prop-types": "^15.8.1",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.10",
|
||||
"vite-plugin-pwa": "^0.20.0"
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^5.4.14",
|
||||
"vite-plugin-pwa": "^0.20.5"
|
||||
}
|
||||
}
|
||||
|
||||
7619
pnpm-lock.yaml
generated
7619
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ const CommanderDamageButton = twc.button<RotationButtonProps>((props) => [
|
||||
]);
|
||||
|
||||
const CommanderDamageTextContainer = twc.div<RotationDivProps>((props) => [
|
||||
'relative top-1/2 left-1/2 tabular-nums pointer-events-none select-none webkit-user-select-none',
|
||||
'relative -translate-y-1/2 top-1/2 left-1/2 tabular-nums pointer-events-none select-none webkit-user-select-none',
|
||||
props.$rotation === Rotation.SideFlipped || props.$rotation === Rotation.Side
|
||||
? 'rotate-[270deg]'
|
||||
: '',
|
||||
|
||||
@@ -2,5 +2,4 @@ import { twc } from 'react-twc';
|
||||
|
||||
export const Paragraph = twc.p`text-text-primary`;
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export const H1 = twc.h1`text-text-primary;`;
|
||||
|
||||
37
src/Components/Misc/Timer/NegativeStopWatch.tsx
Normal file
37
src/Components/Misc/Timer/NegativeStopWatch.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useStopwatch } from 'react-timer-hook';
|
||||
import { TimerStyle, TimerWrapper } from './Timer';
|
||||
import { Time } from './Time';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
import PauseIcon from '@mui/icons-material/Pause';
|
||||
|
||||
export const NegativeStopWatch = ({
|
||||
autoStart = false,
|
||||
}: {
|
||||
autoStart?: boolean;
|
||||
}) => {
|
||||
// Initialize the timer using the useTimer hook.
|
||||
const { seconds, minutes, hours, isRunning, start, pause } = useStopwatch({
|
||||
autoStart,
|
||||
});
|
||||
|
||||
return (
|
||||
<TimerWrapper>
|
||||
<TimerStyle>
|
||||
{'-'}
|
||||
<Time time={{ hours, minutes, seconds }} />
|
||||
<div>
|
||||
{!isRunning && (
|
||||
<button onClick={start}>
|
||||
<PlayArrowIcon />
|
||||
</button>
|
||||
)}
|
||||
{isRunning && (
|
||||
<button onClick={pause}>
|
||||
<PauseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</TimerStyle>
|
||||
</TimerWrapper>
|
||||
);
|
||||
};
|
||||
9
src/Components/Misc/Timer/Time.tsx
Normal file
9
src/Components/Misc/Timer/Time.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { formatTime } from '../../../Utils/formatTime';
|
||||
|
||||
export const Time = ({
|
||||
time,
|
||||
}: {
|
||||
time: { hours: number; minutes: number; seconds: number };
|
||||
}) => {
|
||||
return <div className="tabular-nums">{formatTime({ time })}</div>;
|
||||
};
|
||||
84
src/Components/Misc/Timer/Timer.tsx
Normal file
84
src/Components/Misc/Timer/Timer.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { useState } from 'react';
|
||||
import { useTimer } from 'react-timer-hook';
|
||||
import { NegativeStopWatch } from './NegativeStopWatch';
|
||||
import { twc } from 'react-twc';
|
||||
import PauseIcon from '@mui/icons-material/Pause';
|
||||
import RestartAltIcon from '@mui/icons-material/RestartAlt';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
import { Time } from './Time';
|
||||
|
||||
export const TimerWrapper = twc.div`
|
||||
absolute z-50 top-0 w-screen flex items-center flex-col
|
||||
`;
|
||||
|
||||
export const TimerStyle = twc.div`
|
||||
flex gap-2 bg-interface-recentDifference-background py-1 px-4 rounded-full
|
||||
`;
|
||||
|
||||
const TIMER_MINUTES = 50;
|
||||
|
||||
export const Timer = () => {
|
||||
// Set the default expiry time to 50 minutes from now.
|
||||
const defaultExpiry = new Date();
|
||||
defaultExpiry.setMinutes(defaultExpiry.getMinutes() + TIMER_MINUTES);
|
||||
|
||||
const [hasStarted, setHasStarted] = useState(false);
|
||||
|
||||
// Initialize the timer using the useTimer hook.
|
||||
const { seconds, minutes, hours, isRunning, start, pause, restart } =
|
||||
useTimer({
|
||||
expiryTimestamp: defaultExpiry,
|
||||
onExpire: () => console.warn('Timer expired'),
|
||||
autoStart: false,
|
||||
});
|
||||
|
||||
// Function to restart the timer for 50 minutes.
|
||||
const handleRestart = () => {
|
||||
const time = new Date();
|
||||
time.setMinutes(time.getMinutes() + TIMER_MINUTES);
|
||||
restart(time);
|
||||
};
|
||||
|
||||
const handleStart = () => {
|
||||
setHasStarted(true);
|
||||
start();
|
||||
};
|
||||
|
||||
const handlePause = () => {
|
||||
setHasStarted(false);
|
||||
pause();
|
||||
};
|
||||
|
||||
if (hasStarted && !isRunning) {
|
||||
return <NegativeStopWatch autoStart />;
|
||||
}
|
||||
|
||||
return (
|
||||
<TimerWrapper>
|
||||
<TimerStyle>
|
||||
<Time
|
||||
time={{
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
{!isRunning && (
|
||||
<button onClick={handleStart}>
|
||||
<PlayArrowIcon />
|
||||
</button>
|
||||
)}
|
||||
{isRunning && (
|
||||
<button onClick={handlePause}>
|
||||
<PauseIcon />
|
||||
</button>
|
||||
)}
|
||||
<button onClick={handleRestart}>
|
||||
<RestartAltIcon />
|
||||
</button>
|
||||
</div>
|
||||
</TimerStyle>
|
||||
</TimerWrapper>
|
||||
);
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import { PreStartMode } from '../../Types/Settings';
|
||||
import LifeCounter from '../LifeCounter/LifeCounter';
|
||||
import { RoulettePlayerCard } from '../PreStartGame/Games/RandomKing/RoulettePlayerCard';
|
||||
import { GridLayout } from '../Views/Play';
|
||||
import { Timer } from '../Misc/Timer/Timer';
|
||||
|
||||
const getGridArea = (player: PlayerType) => {
|
||||
switch (player.index) {
|
||||
@@ -36,6 +37,7 @@ export const Players = ({ gridLayout }: { gridLayout: GridLayout }) => {
|
||||
return (
|
||||
<PlayersWrapper>
|
||||
<div className={`grid w-full h-full gap-1 box-border ${gridLayout} `}>
|
||||
<Timer />
|
||||
{players.map((player) => {
|
||||
const gridArea = getGridArea(player);
|
||||
return (
|
||||
|
||||
@@ -19,6 +19,7 @@ export const Play = () => {
|
||||
useGlobalSettings();
|
||||
|
||||
let gridLayout: GridLayout;
|
||||
|
||||
switch (players.length) {
|
||||
case 1:
|
||||
if (initialGameSettings?.orientation === Orientation.Portrait) {
|
||||
@@ -101,7 +102,6 @@ export const Play = () => {
|
||||
settings.preStartMode !== PreStartMode.None &&
|
||||
!playing &&
|
||||
settings.showStartingPlayer && <PreStart />}
|
||||
|
||||
<Players gridLayout={gridLayout} />
|
||||
</MainWrapper>
|
||||
);
|
||||
|
||||
17
src/Utils/formatTime.ts
Normal file
17
src/Utils/formatTime.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const formatTime = ({
|
||||
time,
|
||||
}: {
|
||||
time: { hours: number; minutes: number; seconds: number };
|
||||
}) => {
|
||||
const h = time.hours.toString().padStart(2, '0');
|
||||
const m = time.minutes.toString().padStart(2, '0');
|
||||
const s = time.seconds.toString().padStart(2, '0');
|
||||
|
||||
if (time.hours > 0) {
|
||||
return `${h}:${m}:${s}`;
|
||||
} else if (time.minutes > 0) {
|
||||
return `${m}:${s}`;
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user