Add info modal (#14)

* add border radius

* fix settings styling a little

* move hook

* get default values from localstorage

* replace svgs with own svg

* update favicon

* add logo

* update meta

* adjust scaling

* fix some scaling

* add infomodal
This commit is contained in:
Viktor Rådberg
2023-09-01 19:40:21 +02:00
committed by GitHub
parent b36addc743
commit f626799a26
11 changed files with 216 additions and 19 deletions

View File

@@ -51,7 +51,7 @@ const CommanderDamageButton = styled.button<{
props.rotation === Rotation.Side props.rotation === Rotation.Side
) { ) {
return css` return css`
width: 10vmin; width: 6vmax;
height: auto; height: auto;
`; `;
} }

View File

@@ -9,7 +9,6 @@ export const StyledLifeCounterButton = styled.button`
width: 100%; width: 100%;
height: 100%; height: 100%;
color: rgba(0, 0, 0, 0.4); color: rgba(0, 0, 0, 0.4);
font-size: 4rem;
font-weight: 600; font-weight: 600;
background-color: transparent; background-color: transparent;
border: none; border: none;
@@ -35,6 +34,7 @@ const TextContainer = styled.div<{
rotation: number; rotation: number;
}>` }>`
position: relative; position: relative;
top: -10%;
${(props) => { ${(props) => {
if ( if (
@@ -45,10 +45,13 @@ const TextContainer = styled.div<{
return css` return css`
rotate: -90deg; rotate: -90deg;
bottom: 25%; bottom: 25%;
left: -10%;
top: auto;
`; `;
} }
return css` return css`
rotate: -90deg; rotate: -90deg;
left: -10%;
top: 25%; top: 25%;
`; `;
} }
@@ -111,6 +114,11 @@ const LifeCounterButton = ({
setHasPressedDown(false); setHasPressedDown(false);
}; };
const fontSize =
rotation === Rotation.SideFlipped || rotation === Rotation.Side
? '10vmax'
: '20vmin';
return ( return (
<StyledLifeCounterButton <StyledLifeCounterButton
onPointerDown={handleDownInput} onPointerDown={handleDownInput}
@@ -119,6 +127,7 @@ const LifeCounterButton = ({
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault(); e.preventDefault();
}} }}
style={{ fontSize }}
> >
<TextContainer <TextContainer
rotation={rotation} rotation={rotation}

View File

@@ -9,7 +9,7 @@ export const StyledSettingsButton = styled.button<{ rotation: number }>`
border: none; border: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
top: 12vmin; top: 25%;
right: 1vmax; right: 1vmax;
background-color: transparent; background-color: transparent;
user-select: none; user-select: none;
@@ -26,7 +26,7 @@ export const StyledSettingsButton = styled.button<{ rotation: number }>`
return css` return css`
right: auto; right: auto;
top: 1vmax; top: 1vmax;
left: 12vmin; left: 27%;
`; `;
} }
}} }}

View File

@@ -187,8 +187,8 @@ export const LoseGameButton = styled.button<{ rotation: Rotation }>`
border: none; border: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
top: 12vmin; top: 25%;
right: 6vmax; right: 15%;
background-color: #43434380; background-color: #43434380;
border-radius: 8px; border-radius: 8px;
-webkit-touch-callout: none; -webkit-touch-callout: none;
@@ -202,15 +202,15 @@ export const LoseGameButton = styled.button<{ rotation: Rotation }>`
if (props.rotation === Rotation.SideFlipped) { if (props.rotation === Rotation.SideFlipped) {
return css` return css`
right: auto; right: auto;
top: 6vmax; top: 15%;
left: 12vmin; left: 27%;
rotate: ${props.rotation}deg; rotate: ${props.rotation}deg;
`; `;
} else if (props.rotation === Rotation.Side) { } else if (props.rotation === Rotation.Side) {
return css` return css`
right: auto; right: auto;
top: 6vmax; top: 15%;
left: 12vmin; left: 27%;
rotate: ${props.rotation - 180}deg; rotate: ${props.rotation - 180}deg;
`; `;
} }
@@ -311,14 +311,14 @@ const LifeCounter = ({
const fontSize = const fontSize =
player.settings.rotation === Rotation.SideFlipped || player.settings.rotation === Rotation.SideFlipped ||
player.settings.rotation === Rotation.Side player.settings.rotation === Rotation.Side
? `clamp(6rem, ${size}vmax, 10rem)` ? `${size}vmax`
: `clamp(6rem, ${size}vmin, 10rem)`; : `${size}vmin`;
const strokeWidth = const strokeWidth =
player.settings.rotation === Rotation.SideFlipped || player.settings.rotation === Rotation.SideFlipped ||
player.settings.rotation === Rotation.Side player.settings.rotation === Rotation.Side
? `clamp(0.4rem, ${size / 20}vmax, 12rem)` ? `${size / 20}vmax`
: `clamp(0.4rem, ${size / 20}vmin, 12rem)`; : `${size / 20}vmin`;
return ( return (
<LifeCounterContentWrapper backgroundColor={backgroundColor}> <LifeCounterContentWrapper backgroundColor={backgroundColor}>

View File

@@ -0,0 +1,95 @@
import { Modal } from '@mui/material';
import { theme } from '../../Data/theme';
type InfoModalProps = {
isOpen: boolean;
closeModal: () => void;
};
export const InfoModal = ({ isOpen, closeModal }: InfoModalProps) => {
return (
<Modal open={isOpen} onClose={closeModal}>
<div
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '80vw',
height: '80vh',
backgroundColor: theme.palette.background.default,
padding: '1rem',
overflow: 'scroll',
borderRadius: '1rem',
color: theme.palette.text.primary,
border: 'none',
}}
>
<div>
<h2 style={{ textAlign: 'center' }}>📋 Usage Guide</h2>
<p>
There are some controls that you might not know about, so here's a
short list of them.
</p>
<h3>Life counter</h3>
<ul>
<li>
<strong>Tap</strong> on a player's + or - button to add or
subtract <strong>1 life</strong>.
</li>
<li>
<strong>Long press</strong> on a player's + or - button to add or
subtract <strong>10 life</strong>.
</li>
</ul>
<h3>Commander damage and other counters</h3>
<ul>
<li>
<strong>Tap</strong> on the counter to add{' '}
<strong>1 counter</strong>.
</li>
<li>
<strong>Long press</strong> on the counter to subtract{' '}
<strong>1 counter</strong>.
</li>
</ul>
<h3>Other</h3>
<p>
When a player is <strong>at or below 0 life</strong>, has taken{' '}
<strong>21 or more Commander Damage</strong> or has{' '}
<strong>10 or more poison counters</strong>, a button with a skull
will appear on that player's card.
</p>
<p>
Tap on the button to mark that player as lost, dimming their player
card.
</p>
</div>
<br />
<div
style={{
textAlign: 'center',
marginTop: '1rem',
}}
>
Visit my
<a
href="https://github.com/Vikeo/LifeTrinket"
target="_blank"
style={{
textDecoration: 'none',
color: theme.palette.primary.light,
}}
>
{' '}
GitHub{' '}
</a>
for more info about this web app.
</div>
</div>
</Modal>
);
};

View File

@@ -34,8 +34,9 @@ const CloseButton = styled.div<{
rotation: Rotation; rotation: Rotation;
}>` }>`
position: absolute; position: absolute;
top: 5%; top: 15%;
right: 5%; right: 5%;
z-index: 9999;
border: none; border: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
@@ -77,6 +78,7 @@ const PlayerMenu = ({
resetCurrentGame, resetCurrentGame,
}: PlayerMenuProps) => { }: PlayerMenuProps) => {
const handleOnClick = () => { const handleOnClick = () => {
console.log('hej');
setShowPlayerMenu(false); setShowPlayerMenu(false);
}; };

View File

@@ -156,6 +156,12 @@ const Settings = ({ player, onChange, resetCurrentGame }: SettingsProps) => {
} }
}; };
const buttonFontSize =
player.settings.rotation === Rotation.SideFlipped ||
player.settings.rotation === Rotation.Side
? '1.3vmax'
: '2.5vmin';
return ( return (
<SettingsContainer rotation={player.settings.rotation}> <SettingsContainer rotation={player.settings.rotation}>
<ColorPicker <ColorPicker
@@ -269,7 +275,7 @@ const Settings = ({ player, onChange, resetCurrentGame }: SettingsProps) => {
style={{ style={{
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',
fontSize: '0.6rem', fontSize: buttonFontSize,
padding: '0 4px 0 4px', padding: '0 4px 0 4px',
}} }}
onClick={handleNewGame} onClick={handleNewGame}
@@ -281,7 +287,7 @@ const Settings = ({ player, onChange, resetCurrentGame }: SettingsProps) => {
style={{ style={{
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',
fontSize: '0.6rem', fontSize: buttonFontSize,
padding: '0 4px 0 4px', padding: '0 4px 0 4px',
}} }}
onClick={toggleFullscreen} onClick={toggleFullscreen}
@@ -293,7 +299,7 @@ const Settings = ({ player, onChange, resetCurrentGame }: SettingsProps) => {
style={{ style={{
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',
fontSize: '0.6rem', fontSize: buttonFontSize,
padding: '0 4px 0 4px', padding: '0 4px 0 4px',
}} }}
onClick={handleWakeLock} onClick={handleWakeLock}

View File

@@ -7,11 +7,14 @@ import {
InitialSettings, InitialSettings,
createInitialPlayers, createInitialPlayers,
} from '../../../Data/getInitialPlayers'; } from '../../../Data/getInitialPlayers';
import { theme } from '../../../Data/theme';
import { useAnalytics } from '../../../Hooks/useAnalytics';
import { Info } from '../../../Icons/generated';
import { Player } from '../../../Types/Player'; import { Player } from '../../../Types/Player';
import { InfoModal } from '../../Misc/InfoModal';
import { SupportMe } from '../../Misc/SupportMe'; import { SupportMe } from '../../Misc/SupportMe';
import { H2, Paragraph } from '../../Misc/TextComponents'; import { H2, Paragraph } from '../../Misc/TextComponents';
import LayoutOptions from './LayoutOptions'; import LayoutOptions from './LayoutOptions';
import { useAnalytics } from '../../../Hooks/useAnalytics';
const MainWrapper = styled.div` const MainWrapper = styled.div`
width: 100vw; width: 100vw;
@@ -93,6 +96,7 @@ const Start = ({
setInitialGameSettings, setInitialGameSettings,
}: StartProps) => { }: StartProps) => {
const analytics = useAnalytics(); const analytics = useAnalytics();
const [openModal, setOpenModal] = useState(false);
const [playerOptions, setPlayerOptions] = useState<InitialSettings>( const [playerOptions, setPlayerOptions] = useState<InitialSettings>(
initialGameSettings || { initialGameSettings || {
numberOfPlayers: 4, numberOfPlayers: 4,
@@ -157,6 +161,23 @@ const Start = ({
return ( return (
<MainWrapper> <MainWrapper>
<Info
color={theme.palette.primary.light}
size="2rem"
style={{ position: 'absolute', top: '1rem', left: '1rem' }}
onClick={() => {
console.log('lmao');
setOpenModal(!openModal);
}}
/>
<InfoModal
closeModal={() => {
setOpenModal(false);
}}
isOpen={openModal}
/>
<SupportMe /> <SupportMe />
<H2>Life Trinket</H2> <H2>Life Trinket</H2>

View File

@@ -0,0 +1,33 @@
import PropTypes from 'prop-types';
import { SVGProps } from 'react';
interface SVGRProps {
title?: string;
titleId?: string;
size?: string;
}
const Info = ({
title,
titleId,
...props
}: SVGProps<SVGSVGElement> & SVGRProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={props.size || 16}
height={props.size || 16}
viewBox="0 0 524 524"
aria-labelledby={titleId}
{...props}
>
{title ? <title id={titleId}>{title}</title> : null}
<g fill="currentColor">
<path d="M236.7 33.5c-28.8 3.6-51.4 10.2-75.4 22C92.7 89.2 46.2 152.7 34.4 229c-2.5 16-2.5 50 0 66C46 370 91.6 433.3 158.5 467.2c32.9 16.7 65.2 24.3 103.5 24.3 22.1 0 34.2-1.4 54.5-6.2 31.1-7.3 65.4-24.3 90.8-45.2 9.1-7.4 27-25.5 34.3-34.6 25-31.3 41.8-70.1 48-111 2.5-16.4 2.5-48.3 0-65-11.4-76.2-58.6-140.8-126.9-174-23.2-11.2-42.1-17.1-67.7-21-14.5-2.2-44.7-2.8-58.3-1zM294 78.9c74.6 13.2 133.6 70.2 149.6 144.4 8.6 40.3 3.5 82-14.6 119.3C390.5 422 302.6 463 216.5 441.9c-88.7-21.8-148.8-107.6-139.4-199 7.3-71.5 56.7-133.8 124.4-156.8 12.2-4.1 27.1-7.4 40.5-9.1 11.8-1.4 38.8-.4 52 1.9z" />
<path d="M246.5 112c-20.8 2-36.2 8.6-48.5 21.1-11.5 11.6-19.3 26.4-27.5 52-3.4 10.6-3.6 11.9-2.4 14.4 2 4.1 5.8 6.5 11.4 7.1 7.4.9 9.2-1 17.8-19 14.9-30.8 25.7-41.9 46-47.3 8.4-2.3 29.8-2.2 38.6.1 21.2 5.5 34.6 19.5 35.9 37.6.8 11.1-2.3 16.4-20.5 35.2-26 26.8-38 45.6-44.2 69.2-3 11.3-4.6 31.6-3.6 46 .7 11.3.9 12.1 3.5 14.8 2.6 2.5 3.5 2.8 9.5 2.8 5.7 0 6.9-.3 9-2.5 1.4-1.3 2.5-3.2 2.6-4.2.1-1 .2-9.9.3-19.8.2-20.3 1.6-28.1 7.1-40.2 7.6-16.6 23.7-36 42.5-51.3 22.4-18.2 28.1-27.9 28-47.8-.1-19.8-6.1-35.4-17.9-46.5-8.6-8.1-14.8-11.8-26.6-15.7-16.5-5.4-41.3-7.8-61-6zM252.4 372.9c-4.2 1.8-5.4 5-5.4 13.9 0 4.6.5 9.2 1 10.3 1.8 3.3 6.4 4.9 14 4.9 12.6 0 15.5-3.3 14.9-16.9-.6-11.3-1.9-12.5-13.7-12.8-4.8-.2-9.7.1-10.8.6z" />
</g>
</svg>
);
};
Info.propTypes = {
title: PropTypes.string,
};
export default Info;

View File

@@ -2,6 +2,7 @@ export { default as Cog } from './Cog';
export { default as CommanderTax } from './CommanderTax'; export { default as CommanderTax } from './CommanderTax';
export { default as Energy } from './Energy'; export { default as Energy } from './Energy';
export { default as Experience } from './Experience'; export { default as Experience } from './Experience';
export { default as Info } from './Info';
export { default as LittleGuy } from './LittleGuy'; export { default as LittleGuy } from './LittleGuy';
export { default as Logo } from './Logo'; export { default as Logo } from './Logo';
export { default as PartnerTax } from './PartnerTax'; export { default as PartnerTax } from './PartnerTax';

30
src/Icons/svgs/Info.svg Normal file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="524.000000pt" height="524.000000pt" viewBox="0 0 524.000000 524.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,524.000000) scale(0.100000,-0.100000)"
fill="currentColor" stroke="none">
<path d="M2367 4905 c-288 -36 -514 -102 -754 -220 -686 -337 -1151 -972
-1269 -1735 -25 -160 -25 -500 0 -660 116 -750 572 -1383 1241 -1722 329 -167
652 -243 1035 -243 221 0 342 14 545 62 311 73 654 243 908 452 91 74 270 255
343 346 250 313 418 701 480 1110 25 164 25 483 0 650 -114 762 -586 1408
-1269 1740 -232 112 -421 171 -677 210 -145 22 -447 28 -583 10z m573 -454
c746 -132 1336 -702 1496 -1444 86 -403 35 -820 -146 -1193 -385 -794 -1264
-1204 -2125 -993 -887 218 -1488 1076 -1394 1990 73 715 567 1338 1244 1568
122 41 271 74 405 91 118 14 388 4 520 -19z"/>
<path d="M2465 4120 c-208 -20 -362 -86 -485 -211 -115 -116 -193 -264 -275
-520 -34 -106 -36 -119 -24 -144 20 -41 58 -65 114 -71 74 -9 92 10 178 190
149 308 257 419 460 473 84 23 298 22 386 -1 212 -55 346 -195 359 -376 8
-111 -23 -164 -205 -352 -260 -268 -380 -456 -442 -692 -30 -113 -46 -316 -36
-460 7 -113 9 -121 35 -148 26 -25 35 -28 95 -28 57 0 69 3 90 25 14 13 25 32
26 42 1 10 2 99 3 198 2 203 16 281 71 402 76 166 237 360 425 513 224 182
281 279 280 478 -1 198 -61 354 -179 465 -86 81 -148 118 -266 157 -165 54
-413 78 -610 60z"/>
<path d="M2524 1511 c-42 -18 -54 -50 -54 -139 0 -46 5 -92 10 -103 18 -33 64
-49 140 -49 126 0 155 33 149 169 -6 113 -19 125 -137 128 -48 2 -97 -1 -108
-6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB