Compare commits

...

11 Commits
0.9.4 ... 0.9.7

Author SHA1 Message Date
Vikeo
63aace2b07 fix typo and adjust touch roulette timings 2024-04-07 23:58:39 +02:00
Vikeo
ba9ca354fc fix crown being visible after reset 2024-04-01 18:48:06 +02:00
Viktor Rådberg
e79c728e6a Save game (#35)
* save

* hide scrollbar on desktop

* start menu styling

* bump
2024-04-01 00:28:59 +02:00
Viktor Rådberg
97f9bb75e5 bump 2024-03-31 19:58:00 +02:00
Viktor Rådberg
341cb3cde0 revert new api key 2024-03-31 19:57:16 +02:00
Viktor Rådberg
ce9c9ca997 default api key 2024-03-31 19:31:16 +02:00
Viktor Rådberg
ad485f059d debug release 2024-03-31 19:25:44 +02:00
Viktor Rådberg
92f954130f bump 2024-03-31 19:13:27 +02:00
Viktor Rådberg
112023bdd5 log if it works or not 2024-03-31 19:08:17 +02:00
Viktor Rådberg
4e6dc56d99 add api key back 2024-03-31 19:02:59 +02:00
Viktor Rådberg
e427bfd0cf new analytics api key 2024-03-31 18:52:08 +02:00
14 changed files with 207 additions and 98 deletions

View File

@@ -1,12 +1,12 @@
index.html,1711189442688,fa2549e32940c356ac5cee88c8db61076ad62fb4e599858c8e45cfc68cd901c4 index.html,1711905710499,4b604b23faec8d63a58e07b96d724a1aea56a7c86d57c9af791832ce87a552e7
manifest.json,1711189442512,7ff5111aa04a42adff3b38924ec467b6f345ed0309dba1486dc9b783b60c2a9d manifest.webmanifest,1711905710499,f2bf253209f6e292a6b0dbfa06fb4ac188eb5f2dba568c3ad5511b9ed52c1f51
registerSW.js,1711189442688,5b6445b5215737c53ef0d379c151d57de165a056de2d1c5812ed614f158ebcbd manifest.json,1711905710294,7ff5111aa04a42adff3b38924ec467b6f345ed0309dba1486dc9b783b60c2a9d
sw.js,1711189443521,9c09d33ea573bb818864bfad526fa911839637171773eca8e31905458679846d sw.js,1711905711506,1ef2f4f40ec8dca15cc42d547462ade1e84314ea9722276f5994ccee7bbdf80f
robots.txt,1711189442512,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2 robots.txt,1711905710294,391d14b3c2f8c9143a27a28c7399585142228d4d1bdbe2c87ac946de411fa9a2
manifest.webmanifest,1711189442688,f2bf253209f6e292a6b0dbfa06fb4ac188eb5f2dba568c3ad5511b9ed52c1f51 registerSW.js,1711905710499,5b6445b5215737c53ef0d379c151d57de165a056de2d1c5812ed614f158ebcbd
workbox-3e911b1d.js,1711189443521,d5dbc868a5c07af633d29de7ba3ffe37542aaaabdf33713b4298df31f92f11ff workbox-3e911b1d.js,1711905711507,d5dbc868a5c07af633d29de7ba3ffe37542aaaabdf33713b4298df31f92f11ff
assets/index-WLCHZTqE.css,1711189442688,877e5ea9bfd3a1ca0e6449e8213da8a3c7717e530370f12669bb5c70dd21e700 assets/index-7m_Zw4yH.css,1711905710499,37997d06b32b3d0c724c054913e3c0583b86f786358121cb1615e6646ff46b56
favicon.ico,1711189442511,8cefe5adbf00d337d8633fb744b9f2c4914f769b319be4bb7e184b7a4aa17160 favicon.ico,1711905710294,8cefe5adbf00d337d8633fb744b9f2c4914f769b319be4bb7e184b7a4aa17160
logo192.png,1711189442511,3d1e2e6f064d4fd325828f21bb6493ff0dbf2390b0e7d2aba9f2b6def4829799 logo192.png,1711905710294,3d1e2e6f064d4fd325828f21bb6493ff0dbf2390b0e7d2aba9f2b6def4829799
logo512.png,1711189442511,892a4da1cc5434929a83a71fcbcb0d0d80aa82f44e3c21e9b20ffe9267197133 logo512.png,1711905710294,892a4da1cc5434929a83a71fcbcb0d0d80aa82f44e3c21e9b20ffe9267197133
assets/index-OHs0lOr7.js,1711189442688,aa0dca732cd5b6f621ecb7c6dbcbfdbccde78941cfad954f6626d4ff83040c7f assets/index-CLJVONOc.js,1711905710499,22f3835412f82bb3f8a62e74a7f4602a9c43b447224790365dbcc6cbffb4e665

View File

@@ -8,6 +8,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
VITE_REPO_READ_ACCESS_TOKEN: ${{ secrets.REPO_READ_ACCESS_TOKEN }} VITE_REPO_READ_ACCESS_TOKEN: ${{ secrets.REPO_READ_ACCESS_TOKEN }}
VITE_FIREBASE_ANALYTICS_API_KEY: ${{ secrets.FIREBASE_ANALYTICS_API_KEY }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3

View File

@@ -1,7 +1,7 @@
{ {
"name": "life-trinket", "name": "life-trinket",
"private": true, "private": true,
"version": "0.9.4", "version": "0.9.7",
"type": "commonjs", "type": "commonjs",
"engines": { "engines": {
"node": ">=18", "node": ">=18",

View File

@@ -6,7 +6,7 @@ import { Cross } from '../../Icons/generated';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useAnalytics } from '../../Hooks/useAnalytics'; import { useAnalytics } from '../../Hooks/useAnalytics';
export const ModalWrapper = twc.div`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[85vh] bg-background-default p-4 overflow-scroll rounded-2xl border-none text-text-primary w-[95vw] max-w-[548px]`; export const ModalWrapper = twc.div`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-[47.5%] h-[95%] bg-background-default p-4 overflow-scroll rounded-2xl border-none text-text-primary w-[95vw] max-w-[548px]`;
type InfoModalProps = { type InfoModalProps = {
isOpen: boolean; isOpen: boolean;

View File

@@ -2,6 +2,7 @@ import { Checkbox } from '@mui/material';
import { useRef } from 'react'; import { useRef } from 'react';
import { twc } from 'react-twc'; import { twc } from 'react-twc';
import { theme } from '../../Data/theme'; import { theme } from '../../Data/theme';
import { useAnalytics } from '../../Hooks/useAnalytics';
import { useGlobalSettings } from '../../Hooks/useGlobalSettings'; import { useGlobalSettings } from '../../Hooks/useGlobalSettings';
import { usePlayers } from '../../Hooks/usePlayers'; import { usePlayers } from '../../Hooks/usePlayers';
import { useSafeRotate } from '../../Hooks/useSafeRotate'; import { useSafeRotate } from '../../Hooks/useSafeRotate';
@@ -17,8 +18,8 @@ import {
ResetGame, ResetGame,
} from '../../Icons/generated'; } from '../../Icons/generated';
import { Player, Rotation } from '../../Types/Player'; import { Player, Rotation } from '../../Types/Player';
import { PreStartMode } from '../../Types/Settings';
import { RotationDivProps } from '../Buttons/CommanderDamage'; import { RotationDivProps } from '../Buttons/CommanderDamage';
import { useAnalytics } from '../../Hooks/useAnalytics';
const PlayerMenuWrapper = twc.div` const PlayerMenuWrapper = twc.div`
flex flex
@@ -110,11 +111,14 @@ const PlayerMenu = ({
settings, settings,
setPlaying, setPlaying,
setRandomizingPlayer, setRandomizingPlayer,
saveCurrentGame,
initialGameSettings,
setPreStartCompleted,
} = useGlobalSettings(); } = useGlobalSettings();
const analytics = useAnalytics(); const analytics = useAnalytics();
const { updatePlayer, resetCurrentGame } = usePlayers(); const { updatePlayer, resetCurrentGame, players } = usePlayers();
const handleColorChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleColorChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const updatedPlayer = { ...player, color: event.target.value }; const updatedPlayer = { ...player, color: event.target.value };
@@ -131,12 +135,19 @@ const PlayerMenu = ({
const handleResetGame = () => { const handleResetGame = () => {
resetCurrentGame(); resetCurrentGame();
setShowPlayerMenu(false); setShowPlayerMenu(false);
setPlaying(false); setPlaying(false);
setRandomizingPlayer(true);
if (settings.preStartMode === PreStartMode.RandomKing) {
setRandomizingPlayer(true);
setPreStartCompleted(false);
}
analytics.trackEvent('reset_game'); analytics.trackEvent('reset_game');
}; };
const handleGoToStart = () => { const handleGoToStart = () => {
saveCurrentGame({ players, initialGameSettings });
goToStart(); goToStart();
setRandomizingPlayer(true); setRandomizingPlayer(true);
}; };
@@ -443,8 +454,14 @@ const PlayerMenu = ({
className="text-center text-text-primary" className="text-center text-text-primary"
style={{ fontSize: extraCountersSize }} style={{ fontSize: extraCountersSize }}
> >
End Game? Go to start?
</h1> </h1>
<div
style={{ fontSize: iconSize }}
className="text-center text-text-primary"
>
(Game will be saved)
</div>
<div className="flex justify-evenly gap-2"> <div className="flex justify-evenly gap-2">
<button <button
className="bg-primary-main border border-primary-dark text-text-primary rounded-lg flex-grow" className="bg-primary-main border border-primary-dark text-text-primary rounded-lg flex-grow"

View File

@@ -14,6 +14,10 @@ const getOrientation = () => {
: 'landscape'; : 'landscape';
}; };
const ANIMATION_INTRO_LENGTH = 500;
const BEFORE_INTRO_TIMER_LENGTH = 100;
export const FingerGame = () => { export const FingerGame = () => {
const { players } = usePlayers(); const { players } = usePlayers();
@@ -34,7 +38,7 @@ export const FingerGame = () => {
aboutToStartTimerRef.current = setTimeout(() => { aboutToStartTimerRef.current = setTimeout(() => {
setSelectedTouchPoint(undefined); setSelectedTouchPoint(undefined);
setPlaying(true); setPlaying(true);
}, 500); }, ANIMATION_INTRO_LENGTH);
setTimerStarted(true); setTimerStarted(true);
return; return;
@@ -46,7 +50,7 @@ export const FingerGame = () => {
const randomIndex = Math.floor(Math.random() * touchPoints.length); const randomIndex = Math.floor(Math.random() * touchPoints.length);
const randomTouchPoint = touchPoints[randomIndex]; const randomTouchPoint = touchPoints[randomIndex];
setSelectedTouchPoint(randomTouchPoint); setSelectedTouchPoint(randomTouchPoint);
}, 250); }, BEFORE_INTRO_TIMER_LENGTH);
return; return;
} }
@@ -99,7 +103,7 @@ export const FingerGame = () => {
aboutToStartTimerRef.current = setTimeout(() => { aboutToStartTimerRef.current = setTimeout(() => {
setSelectedTouchPoint(undefined); setSelectedTouchPoint(undefined);
setPlaying(true); setPlaying(true);
}, 500); }, ANIMATION_INTRO_LENGTH);
setTimerStarted(true); setTimerStarted(true);
return; return;
} }
@@ -180,7 +184,7 @@ export const FingerGame = () => {
key={`touch-point-${index}`} key={`touch-point-${index}`}
data-is-selected={selectedTouchPoint?.id === point.id} data-is-selected={selectedTouchPoint?.id === point.id}
data-unloading={timerStarted} data-unloading={timerStarted}
className="absolute rounded-full translate-x-[-50%] translate-y-[-50%] transition-all duration-1000 className="absolute rounded-full translate-x-[-50%] translate-y-[-50%] transition-all duration-500
h-[75px] w-[75px] h-[75px] w-[75px]
data-[unloading=false]:data-[is-selected=true]:h-[250px] data-[unloading=false]:data-[is-selected=true]:w-[250px] data-[unloading=false]:data-[is-selected=true]:h-[250px] data-[unloading=false]:data-[is-selected=true]:w-[250px]
data-[unloading=true]:h-[0px] data-[unloading=true]:w-[0px] data-[unloading=true]:duration-[400ms] data-[unloading=true]:h-[0px] data-[unloading=true]:w-[0px] data-[unloading=true]:duration-[400ms]

View File

@@ -8,8 +8,7 @@ const questions = [
'Who has the most piercings?', 'Who has the most piercings?',
'Who has the most expensive shoes?', 'Who has the most expensive shoes?',
'Who has the most most amount of teeth?', 'Who has the most most amount of teeth?',
'Who has the most least amount of teeth?', 'Who has the least amount of teeth?',
'Who has the most least amount of teeth?',
'Who lives closest to the equator?', 'Who lives closest to the equator?',
'Who is the tallest person in the group?', 'Who is the tallest person in the group?',
'Who is the shortest person in the group?', 'Who is the shortest person in the group?',

View File

@@ -95,6 +95,7 @@ export const Play = () => {
}, []); }, []);
if ( if (
players.length > 1 &&
!preStartCompleted && !preStartCompleted &&
settings.preStartMode !== PreStartMode.None && settings.preStartMode !== PreStartMode.None &&
!playing && !playing &&

View File

@@ -19,9 +19,9 @@ import { SettingsModal } from '../../Misc/SettingsModal';
import { SupportMe } from '../../Misc/SupportMe'; import { SupportMe } from '../../Misc/SupportMe';
import { LayoutOptions } from './LayoutOptions'; import { LayoutOptions } from './LayoutOptions';
const MainWrapper = twc.div`w-[100dvw] h-fit pb-14 overflow-hidden items-center flex flex-col`; const MainWrapper = twc.div`w-[100dvw] h-fit pb-24 overflow-hidden items-center flex flex-col min-[349px]:pb-10`;
const StartButtonFooter = twc.div`w-full max-w-[548px] fixed bottom-4 z-1 items-center flex flex-col px-4 z-10`; const StartButtonFooter = twc.div`w-full max-w-[548px] fixed bottom-4 z-1 items-center flex flex-row flex-wrap px-4 z-10 gap-4`;
const SliderWrapper = twc.div`mx-8`; const SliderWrapper = twc.div`mx-8`;
@@ -92,6 +92,9 @@ const Start = () => {
isPWA, isPWA,
setRandomizingPlayer, setRandomizingPlayer,
version, version,
setPlaying,
savedGame,
saveCurrentGame,
} = useGlobalSettings(); } = useGlobalSettings();
const [openInfoModal, setOpenInfoModal] = useState(false); const [openInfoModal, setOpenInfoModal] = useState(false);
@@ -124,7 +127,7 @@ const Start = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [playerOptions.numberOfPlayers]); }, [playerOptions.numberOfPlayers]);
const doStartGame = () => { const doStartNewGame = () => {
if (!initialGameSettings) { if (!initialGameSettings) {
return; return;
} }
@@ -149,10 +152,40 @@ const Start = () => {
setInitialGameSettings(initialGameSettings); setInitialGameSettings(initialGameSettings);
setPlayers(createInitialPlayers(initialGameSettings)); setPlayers(createInitialPlayers(initialGameSettings));
setShowPlay(true);
setRandomizingPlayer(settings.preStartMode === PreStartMode.RandomKing); setRandomizingPlayer(settings.preStartMode === PreStartMode.RandomKing);
localStorage.setItem('playing', 'false'); setShowPlay(true);
localStorage.setItem('showPlay', 'true'); setPlaying(false);
};
const doResumeGame = () => {
if (!savedGame) {
return;
}
analytics.trackEvent('game_resumed', {
...initialGameSettings,
...settings,
isPWA,
});
try {
if (settings.goFullscreenOnStart) {
fullscreen.enableFullscreen();
}
} catch (error) {
console.error(error);
}
if (settings.keepAwake && !wakeLock.active) {
wakeLock.request();
}
setInitialGameSettings(savedGame.initialGameSettings);
setPlayers(savedGame.players);
saveCurrentGame(null);
setRandomizingPlayer(false);
setShowPlay(true);
setPlaying(true);
}; };
const valueText = (value: number) => { const valueText = (value: number) => {
@@ -196,48 +229,6 @@ const Start = () => {
<div className="overflow-hidden items-center flex flex-col max-w-[548px] w-full mb-8 px-4"> <div className="overflow-hidden items-center flex flex-col max-w-[548px] w-full mb-8 px-4">
<FormControl focused={false} style={{ width: '100%' }}> <FormControl focused={false} style={{ width: '100%' }}>
<FormLabel>Number of Players</FormLabel>
<SliderWrapper>
<Slider
title="Number of Players"
max={6}
min={1}
aria-label="Custom marks"
value={playerOptions?.numberOfPlayers ?? 4}
getAriaValueText={valueText}
step={null}
marks={playerMarks}
onChange={(_e, value) => {
setPlayerOptions({
...playerOptions,
numberOfPlayers: value as number,
orientation: Orientation.Landscape,
});
}}
/>
</SliderWrapper>
<FormLabel className="mt-[0.7rem]">Starting Health</FormLabel>
<SliderWrapper>
<Slider
title="Starting Health"
max={60}
min={20}
aria-label="Custom marks"
value={playerOptions?.startingLifeTotal ?? 40}
getAriaValueText={valueText}
step={10}
marks={healthMarks}
onChange={(_e, value) =>
setPlayerOptions({
...playerOptions,
startingLifeTotal: value as number,
orientation: Orientation.Landscape,
})
}
/>
</SliderWrapper>
<ToggleButtonsWrapper className="mt-4"> <ToggleButtonsWrapper className="mt-4">
<ToggleContainer> <ToggleContainer>
<FormLabel>Commander</FormLabel> <FormLabel>Commander</FormLabel>
@@ -295,6 +286,47 @@ const Start = () => {
</div> </div>
</div> </div>
</ToggleButtonsWrapper> </ToggleButtonsWrapper>
<FormLabel>Number of Players</FormLabel>
<SliderWrapper>
<Slider
title="Number of Players"
max={6}
min={1}
aria-label="Custom marks"
value={playerOptions?.numberOfPlayers ?? 4}
getAriaValueText={valueText}
step={null}
marks={playerMarks}
onChange={(_e, value) => {
setPlayerOptions({
...playerOptions,
numberOfPlayers: value as number,
orientation: Orientation.Landscape,
});
}}
/>
</SliderWrapper>
<FormLabel className="mt-[0.7rem]">Starting Health</FormLabel>
<SliderWrapper>
<Slider
title="Starting Health"
max={60}
min={20}
aria-label="Custom marks"
value={playerOptions?.startingLifeTotal ?? 40}
getAriaValueText={valueText}
step={10}
marks={healthMarks}
onChange={(_e, value) =>
setPlayerOptions({
...playerOptions,
startingLifeTotal: value as number,
orientation: Orientation.Landscape,
})
}
/>
</SliderWrapper>
<FormLabel>Layout</FormLabel> <FormLabel>Layout</FormLabel>
<LayoutOptions <LayoutOptions
@@ -318,14 +350,25 @@ const Start = () => {
</div> </div>
<StartButtonFooter> <StartButtonFooter>
<Button <button
size="large" className="flex flex-grow basis-0 justify-center self-center items-center bg-primary-main px-3 py-2 rounded-md text-text-primary min-w-[150px]"
variant="contained" onClick={doStartNewGame}
onClick={doStartGame}
fullWidth
> >
START GAME NEW GAME
</Button> </button>
{savedGame && (
<button
className="flex flex-grow basis-0 justify-center self-center items-center bg-primary-dark px-3 py-2 rounded-md text-text-primary min-w-[150px]"
onClick={doResumeGame}
>
RESUME&nbsp;
<span className="text-xs">
({savedGame.players.length}&nbsp;
{savedGame.players.length > 1 ? 'players' : 'player'})
</span>
</button>
)}
</StartButtonFooter> </StartButtonFooter>
</MainWrapper> </MainWrapper>
); );

View File

@@ -1,5 +1,6 @@
import { createContext } from 'react'; import { createContext } from 'react';
import { InitialGameSettings, Settings } from '../Types/Settings'; import { InitialGameSettings, Settings } from '../Types/Settings';
import { Player } from '../Types/Player';
type Version = { type Version = {
installedVersion: string; installedVersion: string;
@@ -8,6 +9,11 @@ type Version = {
remoteVersion?: string; remoteVersion?: string;
}; };
export type SavedGame = {
initialGameSettings: InitialGameSettings;
players: Player[];
} | null;
export type GlobalSettingsContextType = { export type GlobalSettingsContextType = {
fullscreen: { fullscreen: {
isFullscreen: boolean; isFullscreen: boolean;
@@ -25,7 +31,7 @@ export type GlobalSettingsContextType = {
goToStart: () => void; goToStart: () => void;
showPlay: boolean; showPlay: boolean;
setShowPlay: (showPlay: boolean) => void; setShowPlay: (showPlay: boolean) => void;
initialGameSettings: InitialGameSettings | null; initialGameSettings: InitialGameSettings;
setInitialGameSettings: (initialGameSettings: InitialGameSettings) => void; setInitialGameSettings: (initialGameSettings: InitialGameSettings) => void;
settings: Settings; settings: Settings;
setSettings: (settings: Settings) => void; setSettings: (settings: Settings) => void;
@@ -36,8 +42,9 @@ export type GlobalSettingsContextType = {
isPWA: boolean; isPWA: boolean;
preStartCompleted: boolean; preStartCompleted: boolean;
setPreStartCompleted: (completed: boolean) => void; setPreStartCompleted: (completed: boolean) => void;
version: Version; version: Version;
savedGame: SavedGame;
saveCurrentGame: (currentGame: SavedGame) => void;
}; };
export const GlobalSettingsContext = export const GlobalSettingsContext =

View File

@@ -3,6 +3,7 @@ import { useWakeLock } from 'react-screen-wake-lock';
import { import {
GlobalSettingsContext, GlobalSettingsContext,
GlobalSettingsContextType, GlobalSettingsContextType,
SavedGame,
} from '../Contexts/GlobalSettingsContext'; } from '../Contexts/GlobalSettingsContext';
import { useAnalytics } from '../Hooks/useAnalytics'; import { useAnalytics } from '../Hooks/useAnalytics';
import { import {
@@ -21,12 +22,21 @@ export const GlobalSettingsProvider = ({
}) => { }) => {
const analytics = useAnalytics(); const analytics = useAnalytics();
const savedShowPlay = localStorage.getItem('showPlay'); const localSavedGame = localStorage.getItem('savedGame');
const savedGameSettings = localStorage.getItem('initialGameSettings'); const [savedGame, setCurrentGame] = useState<SavedGame>(
const savedSettings = localStorage.getItem('settings'); localSavedGame ? JSON.parse(localSavedGame) : null
const savedPlaying = localStorage.getItem('playing'); );
const savedPreStartComplete = localStorage.getItem('preStartComplete'); const setCurrentGameAndLocalStorage = (savedGame: SavedGame) => {
if (!savedGame) {
setCurrentGame(savedGame);
localStorage.removeItem('savedGame');
return;
}
setCurrentGame(savedGame);
localStorage.setItem('savedGame', JSON.stringify(savedGame));
};
const savedPlaying = localStorage.getItem('playing');
const [playing, setPlaying] = useState<boolean>( const [playing, setPlaying] = useState<boolean>(
savedPlaying ? savedPlaying === 'true' : false savedPlaying ? savedPlaying === 'true' : false
); );
@@ -35,23 +45,42 @@ export const GlobalSettingsProvider = ({
localStorage.setItem('playing', String(playing)); localStorage.setItem('playing', String(playing));
}; };
const savedPreStartComplete = localStorage.getItem('preStartComplete');
const [preStartCompleted, setPreStartCompleted] = useState<boolean>( const [preStartCompleted, setPreStartCompleted] = useState<boolean>(
savedPreStartComplete ? savedPreStartComplete === 'true' : false savedPreStartComplete ? savedPreStartComplete === 'true' : false
); );
const savedShowPlay = localStorage.getItem('showPlay');
const [showPlay, setShowPlay] = useState<boolean>( const [showPlay, setShowPlay] = useState<boolean>(
savedShowPlay ? savedShowPlay === 'true' : false savedShowPlay ? savedShowPlay === 'true' : false
); );
const setShowPlayAndLocalStorage = (showPlay: boolean) => {
setShowPlay(showPlay);
localStorage.setItem('showPlay', String(showPlay));
};
const savedSettings = localStorage.getItem('settings');
const [randomizingPlayer, setRandomizingPlayer] = useState<boolean>( const [randomizingPlayer, setRandomizingPlayer] = useState<boolean>(
savedSettings savedSettings
? Boolean(JSON.parse(savedSettings).preStartMode === 'random-king') ? Boolean(JSON.parse(savedSettings).preStartMode === 'random-king')
: true : true
); );
const [settings, setSettings] = useState<Settings>(
savedSettings ? JSON.parse(savedSettings) : defaultSettings
);
const setSettingsAndLocalStorage = (settings: Settings) => {
setSettings(settings);
localStorage.setItem('settings', JSON.stringify(settings));
};
const savedGameSettings = localStorage.getItem('initialGameSettings');
const [initialGameSettings, setInitialGameSettings] = const [initialGameSettings, setInitialGameSettings] =
useState<InitialGameSettings | null>( useState<InitialGameSettings>(
savedGameSettings ? JSON.parse(savedGameSettings) : null savedGameSettings
? JSON.parse(savedGameSettings)
: defaultInitialGameSettings
); );
const setInitialGameSettingsAndLocalStorage = ( const setInitialGameSettingsAndLocalStorage = (
@@ -64,15 +93,6 @@ export const GlobalSettingsProvider = ({
); );
}; };
const [settings, setSettings] = useState<Settings>(
savedSettings ? JSON.parse(savedSettings) : defaultSettings
);
const setSettingsAndLocalStorage = (settings: Settings) => {
setSettings(settings);
localStorage.setItem('settings', JSON.stringify(settings));
};
const removeLocalStorage = async () => { const removeLocalStorage = async () => {
localStorage.removeItem('initialGameSettings'); localStorage.removeItem('initialGameSettings');
localStorage.removeItem('players'); localStorage.removeItem('players');
@@ -252,7 +272,7 @@ export const GlobalSettingsProvider = ({
}, },
goToStart, goToStart,
showPlay, showPlay,
setShowPlay, setShowPlay: setShowPlayAndLocalStorage,
playing, playing,
setPlaying: setPlayingAndLocalStorage, setPlaying: setPlayingAndLocalStorage,
initialGameSettings, initialGameSettings,
@@ -264,6 +284,8 @@ export const GlobalSettingsProvider = ({
isPWA: window?.matchMedia('(display-mode: standalone)').matches, isPWA: window?.matchMedia('(display-mode: standalone)').matches,
preStartCompleted, preStartCompleted,
setPreStartCompleted: setPreStartCompletedAndLocalStorage, setPreStartCompleted: setPreStartCompletedAndLocalStorage,
savedGame,
saveCurrentGame: setCurrentGameAndLocalStorage,
version: { version: {
installedVersion: import.meta.env.VITE_APP_VERSION, installedVersion: import.meta.env.VITE_APP_VERSION,
@@ -285,6 +307,7 @@ export const GlobalSettingsProvider = ({
settings, settings,
randomizingPlayer, randomizingPlayer,
preStartCompleted, preStartCompleted,
savedGame,
remoteVersion, remoteVersion,
isLatestVersion, isLatestVersion,
analytics, analytics,

View File

@@ -31,6 +31,16 @@ code {
monospace; monospace;
} }
// hide scrollbar globally
::-webkit-scrollbar {
display: none;
}
* {
scrollbar-width: none;
-ms-overflow-style: none;
}
@layer utilities { @layer utilities {
.pointer-events-all { .pointer-events-all {
pointer-events: all; pointer-events: all;

1
src/vite-env.d.ts vendored
View File

@@ -3,6 +3,7 @@
interface ImportMetaEnv { interface ImportMetaEnv {
readonly VITE_APP_VERSION: string; readonly VITE_APP_VERSION: string;
readonly VITE_REPO_READ_ACCESS_TOKEN: string; readonly VITE_REPO_READ_ACCESS_TOKEN: string;
readonly VITE_FIREBASE_ANALYTICS_API_KEY: string;
} }
interface ImportMeta { interface ImportMeta {

View File

@@ -27,5 +27,8 @@ export default defineConfig({
VITE_REPO_READ_ACCESS_TOKEN: JSON.stringify( VITE_REPO_READ_ACCESS_TOKEN: JSON.stringify(
process.env.VITE_REPO_READ_ACCESS_TOKEN process.env.VITE_REPO_READ_ACCESS_TOKEN
), ),
VITE_FIREBASE_ANALYTICS_API_KEY: JSON.stringify(
process.env.VITE_FIREBASE_ANALYTICS_API_KEY
),
}, },
}); });