forked from external-repos/LifeTrinket
fix text styling
This commit is contained in:
@@ -54,7 +54,7 @@ const App = () => {
|
||||
|
||||
const handlePlayerChange = (updatedPlayer: Player) => {
|
||||
const updatedPlayers = players.map((player) =>
|
||||
player.key === updatedPlayer.key ? updatedPlayer : player
|
||||
player.index === updatedPlayer.index ? updatedPlayer : player
|
||||
);
|
||||
setPlayers(updatedPlayers);
|
||||
};
|
||||
|
||||
273
my-app/src/Components/Buttons/CommanderDamage.tsx
Normal file
273
my-app/src/Components/Buttons/CommanderDamage.tsx
Normal file
@@ -0,0 +1,273 @@
|
||||
import styled, { css } from 'styled-components';
|
||||
import { Player, Rotation } from '../../Types/Player';
|
||||
import { useRef, useState } from 'react';
|
||||
import { OutlinedText } from '../Text/OutlinedText';
|
||||
|
||||
const CommanderDamageContainer = styled.div<{
|
||||
rotation: number;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
flex-direction: column;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const CommanderDamageButton = styled.button<{
|
||||
backgroundColor?: string;
|
||||
rotation: number;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
height: 10vmin;
|
||||
width: 50%;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
background-color: ${(props) => props.backgroundColor || 'antiquewhite'};
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
padding: 0;
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
width: 10vmin;
|
||||
height: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const CommanderDamageTextContainer = styled.p<{
|
||||
rotation: number;
|
||||
}>`
|
||||
position: relative;
|
||||
top: 25%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-variant-numeric: tabular-nums;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
rotate: 180deg;
|
||||
text-orientation: sideways;
|
||||
writing-mode: vertical-lr;
|
||||
height: 1rem;
|
||||
width: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const LmaoContainer = styled.div`
|
||||
/* top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100px;
|
||||
height: 100px; */
|
||||
`;
|
||||
|
||||
const PartnerDamageSeperator = styled.div<{
|
||||
rotation: number;
|
||||
}>`
|
||||
width: 1px;
|
||||
background-color: rgba(0, 0, 0, 1);
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
width: auto;
|
||||
height: 1px;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
type CommanderDamageButtonComponentProps = {
|
||||
player: Player;
|
||||
opponent: Player;
|
||||
onPlayerChange: (updatedPlayer: Player) => void;
|
||||
setLifeTotal: (lifeTotal: number) => void;
|
||||
};
|
||||
|
||||
type InputProps = {
|
||||
opponentIndex: number;
|
||||
isPartner: boolean;
|
||||
};
|
||||
|
||||
export const CommanderDamage = ({
|
||||
player,
|
||||
opponent,
|
||||
onPlayerChange,
|
||||
setLifeTotal,
|
||||
}: CommanderDamageButtonComponentProps) => {
|
||||
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||
const [hasPressedDown, setHasPressedDown] = useState(false);
|
||||
|
||||
const handleCommanderDamageChange = (
|
||||
index: number,
|
||||
increment: number,
|
||||
isPartner: boolean
|
||||
) => {
|
||||
const currentCommanderDamage = player.commanderDamage[index];
|
||||
if (isPartner) {
|
||||
if (currentCommanderDamage.partnerDamageTotal === 0 && increment === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedCommanderDamage = [...player.commanderDamage];
|
||||
updatedCommanderDamage[index].partnerDamageTotal += increment;
|
||||
|
||||
const updatedPlayer = {
|
||||
...player,
|
||||
commanderDamage: updatedCommanderDamage,
|
||||
};
|
||||
onPlayerChange(updatedPlayer);
|
||||
setLifeTotal(player.lifeTotal - increment);
|
||||
return;
|
||||
}
|
||||
if (currentCommanderDamage.damageTotal === 0 && increment === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedCommanderDamage = [...player.commanderDamage];
|
||||
updatedCommanderDamage[index].damageTotal += increment;
|
||||
|
||||
const updatedPlayer = {
|
||||
...player,
|
||||
commanderDamage: updatedCommanderDamage,
|
||||
};
|
||||
onPlayerChange(updatedPlayer);
|
||||
setLifeTotal(player.lifeTotal - increment);
|
||||
};
|
||||
|
||||
const handleDownInput = ({ opponentIndex, isPartner }: InputProps) => {
|
||||
setTimeoutFinished(false);
|
||||
setHasPressedDown(true);
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setTimeoutFinished(true);
|
||||
handleCommanderDamageChange(opponentIndex, -1, isPartner);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleUpInput = ({ opponentIndex, isPartner }: InputProps) => {
|
||||
if (!(hasPressedDown && !timeoutFinished)) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeoutRef.current);
|
||||
handleCommanderDamageChange(opponentIndex, 1, isPartner);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
const handleLeaveInput = () => {
|
||||
setTimeoutFinished(true);
|
||||
clearTimeout(timeoutRef.current);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
const opponentIndex = opponent.index;
|
||||
const fontSize = '5vmin';
|
||||
const fontWeight = 'bold';
|
||||
const strokeWidth = '0.5vmin';
|
||||
|
||||
return (
|
||||
<CommanderDamageContainer
|
||||
key={opponentIndex}
|
||||
rotation={player.settings.rotation}
|
||||
>
|
||||
<CommanderDamageButton
|
||||
key={opponentIndex}
|
||||
rotation={player.settings.rotation}
|
||||
onPointerDown={() =>
|
||||
handleDownInput({ opponentIndex, isPartner: false })
|
||||
}
|
||||
onPointerUp={() => handleUpInput({ opponentIndex, isPartner: false })}
|
||||
onPointerLeave={handleLeaveInput}
|
||||
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
backgroundColor={opponent.color}
|
||||
>
|
||||
<CommanderDamageTextContainer rotation={player.settings.rotation}>
|
||||
<OutlinedText
|
||||
fontSize={fontSize}
|
||||
fontWeight={fontWeight}
|
||||
strokeWidth={strokeWidth}
|
||||
>
|
||||
{player.commanderDamage[opponentIndex].damageTotal > 0
|
||||
? player.commanderDamage[opponentIndex].damageTotal
|
||||
: ''}
|
||||
</OutlinedText>
|
||||
</CommanderDamageTextContainer>
|
||||
</CommanderDamageButton>
|
||||
|
||||
{opponent.settings.usePartner && (
|
||||
<>
|
||||
<PartnerDamageSeperator rotation={player.settings.rotation} />
|
||||
<CommanderDamageButton
|
||||
key={opponentIndex}
|
||||
rotation={player.settings.rotation}
|
||||
onPointerDown={() =>
|
||||
handleDownInput({ opponentIndex, isPartner: true })
|
||||
}
|
||||
onPointerUp={() =>
|
||||
handleUpInput({ opponentIndex, isPartner: true })
|
||||
}
|
||||
onPointerLeave={handleLeaveInput}
|
||||
onContextMenu={(
|
||||
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||
) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
backgroundColor={opponent.color}
|
||||
>
|
||||
<CommanderDamageTextContainer rotation={player.settings.rotation}>
|
||||
<OutlinedText
|
||||
fontSize={fontSize}
|
||||
fontWeight={fontWeight}
|
||||
strokeWidth={strokeWidth}
|
||||
>
|
||||
{player.commanderDamage[opponentIndex].partnerDamageTotal > 0
|
||||
? player.commanderDamage[opponentIndex].partnerDamageTotal
|
||||
: ''}
|
||||
</OutlinedText>
|
||||
</CommanderDamageTextContainer>
|
||||
</CommanderDamageButton>
|
||||
</>
|
||||
)}
|
||||
</CommanderDamageContainer>
|
||||
);
|
||||
};
|
||||
@@ -1,299 +0,0 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { Player, Rotation } from '../../Types/Player';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
const CommanderDamageGrid = styled.div<{ rotation: number }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const CommanderDamageContainer = styled.div<{
|
||||
rotation: number;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
flex-direction: column;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const CommanderDamageButton = styled.button<{
|
||||
backgroundColor?: string;
|
||||
rotation: number;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
height: 10vmin;
|
||||
width: 50%;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
background-color: ${(props) => props.backgroundColor || 'antiquewhite'};
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
padding: 0;
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
width: 10vmin;
|
||||
height: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const CommanderDamageButtonText = styled.p<{
|
||||
rotation: number;
|
||||
}>`
|
||||
margin: auto;
|
||||
font-size: 5vmin;
|
||||
text-size-adjust: auto;
|
||||
font-variant-numeric: tabular-nums;
|
||||
pointer-events: none;
|
||||
text-shadow: -1px -1px 0 #ffffff, 1px -1px 0 #ffffff, -1px 1px 0 #ffffff,
|
||||
1px 1px 0 #ffffff;
|
||||
color: #000000;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
rotate: 180deg;
|
||||
text-orientation: sideways;
|
||||
writing-mode: vertical-lr;
|
||||
height: 1rem;
|
||||
width: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
const PartnerDamageSeperator = styled.div<{
|
||||
rotation: number;
|
||||
}>`
|
||||
width: 1px;
|
||||
background-color: rgba(0, 0, 0, 1);
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
width: auto;
|
||||
height: 1px;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
type CommanderDamageBarProps = {
|
||||
lifeTotal: number;
|
||||
opponents: Player[];
|
||||
player: Player;
|
||||
onPlayerChange: (updatedPlayer: Player) => void;
|
||||
setLifeTotal: (lifeTotal: number) => void;
|
||||
};
|
||||
|
||||
const CommanderDamageBar = ({
|
||||
opponents,
|
||||
lifeTotal,
|
||||
player,
|
||||
onPlayerChange,
|
||||
setLifeTotal,
|
||||
}: CommanderDamageBarProps) => {
|
||||
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||
const [hasPressedDown, setHasPressedDown] = useState(false);
|
||||
|
||||
const handleCommanderDamageChange = (
|
||||
index: number,
|
||||
increment: number,
|
||||
isPartner: boolean
|
||||
) => {
|
||||
const currentCommanderDamage = player.commanderDamage[index];
|
||||
if (isPartner) {
|
||||
if (currentCommanderDamage.partnerDamageTotal === 0 && increment === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedCommanderDamage = [...player.commanderDamage];
|
||||
updatedCommanderDamage[index].partnerDamageTotal += increment;
|
||||
|
||||
const updatedPlayer = {
|
||||
...player,
|
||||
commanderDamage: updatedCommanderDamage,
|
||||
};
|
||||
onPlayerChange(updatedPlayer);
|
||||
setLifeTotal(lifeTotal - increment);
|
||||
return;
|
||||
}
|
||||
if (currentCommanderDamage.damageTotal === 0 && increment === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedCommanderDamage = [...player.commanderDamage];
|
||||
updatedCommanderDamage[index].damageTotal += increment;
|
||||
|
||||
const updatedPlayer = {
|
||||
...player,
|
||||
commanderDamage: updatedCommanderDamage,
|
||||
};
|
||||
onPlayerChange(updatedPlayer);
|
||||
setLifeTotal(lifeTotal - increment);
|
||||
};
|
||||
|
||||
const handleDownInput = (index: number) => {
|
||||
setTimeoutFinished(false);
|
||||
setHasPressedDown(true);
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setTimeoutFinished(true);
|
||||
handleCommanderDamageChange(index, -1, false);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleUpInput = (index: number) => {
|
||||
if (!(hasPressedDown && !timeoutFinished)) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeoutRef.current);
|
||||
handleCommanderDamageChange(index, 1, false);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
const handleLeaveInput = () => {
|
||||
setTimeoutFinished(true);
|
||||
clearTimeout(timeoutRef.current);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
const handlePartnerDownInput = (index: number) => {
|
||||
setTimeoutFinished(false);
|
||||
setHasPressedDown(true);
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setTimeoutFinished(true);
|
||||
handleCommanderDamageChange(index, -1, true);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handlePartnerUpInput = (index: number) => {
|
||||
if (!(hasPressedDown && !timeoutFinished)) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeoutRef.current);
|
||||
handleCommanderDamageChange(index, 1, true);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
const handlePartnerLeaveInput = () => {
|
||||
setTimeoutFinished(true);
|
||||
clearTimeout(timeoutRef.current);
|
||||
setHasPressedDown(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<CommanderDamageGrid rotation={player.settings.rotation}>
|
||||
{opponents.map((opponent, index) => {
|
||||
if (!opponent.settings.useCommanderDamage) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<CommanderDamageContainer
|
||||
key={index}
|
||||
rotation={player.settings.rotation}
|
||||
>
|
||||
<CommanderDamageButton
|
||||
key={index}
|
||||
rotation={player.settings.rotation}
|
||||
onPointerDown={() => handleDownInput(index)}
|
||||
onPointerUp={() => handleUpInput(index)}
|
||||
onPointerLeave={handleLeaveInput}
|
||||
onContextMenu={(
|
||||
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||
) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
backgroundColor={opponent.color}
|
||||
>
|
||||
<CommanderDamageButtonText rotation={player.settings.rotation}>
|
||||
{player.commanderDamage[index].damageTotal > 0
|
||||
? player.commanderDamage[index].damageTotal
|
||||
: ''}
|
||||
</CommanderDamageButtonText>
|
||||
</CommanderDamageButton>
|
||||
|
||||
{opponent.settings.usePartner && (
|
||||
<>
|
||||
<PartnerDamageSeperator rotation={player.settings.rotation} />
|
||||
<CommanderDamageButton
|
||||
key={index}
|
||||
rotation={player.settings.rotation}
|
||||
onPointerDown={() => handlePartnerDownInput(index)}
|
||||
onPointerUp={() => handlePartnerUpInput(index)}
|
||||
onPointerLeave={handlePartnerLeaveInput}
|
||||
onContextMenu={(
|
||||
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||
) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
backgroundColor={opponent.color}
|
||||
>
|
||||
<CommanderDamageButtonText
|
||||
rotation={player.settings.rotation}
|
||||
>
|
||||
{player.commanderDamage[index].partnerDamageTotal > 0
|
||||
? player.commanderDamage[index].partnerDamageTotal
|
||||
: ''}
|
||||
</CommanderDamageButtonText>
|
||||
</CommanderDamageButton>
|
||||
</>
|
||||
)}
|
||||
</CommanderDamageContainer>
|
||||
);
|
||||
})}
|
||||
</CommanderDamageGrid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommanderDamageBar;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ReactNode, useRef, useState } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { CounterType, Rotation } from '../../Types/Player';
|
||||
import { OutlinedText } from '../Text/OutlinedText';
|
||||
|
||||
const ExtraCounterContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -29,11 +30,11 @@ export const CenteredText = styled.div`
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 7vmin;
|
||||
font-size: 6vmin;
|
||||
font-weight: bold;
|
||||
-webkit-text-stroke: 0.3vmin #ffffff; /* Add a 2-pixel black stroke */
|
||||
-webkit-text-stroke: 0.4vmin #ffffff;
|
||||
-webkit-text-fill-color: #000000;
|
||||
color: #000000;
|
||||
color: #b5b2b2;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
@@ -42,6 +43,13 @@ export const CenteredText = styled.div`
|
||||
-ms-user-select: none;
|
||||
`;
|
||||
|
||||
const CenteredTextOutline = styled.span`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
-webkit-text-stroke: 0;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
const IconContainer = styled.div<{
|
||||
rotation: number;
|
||||
}>`
|
||||
@@ -122,7 +130,13 @@ const ExtraCounter = ({
|
||||
>
|
||||
<IconContainer rotation={rotation}>
|
||||
{Icon}
|
||||
<CenteredText>{counterTotal ? counterTotal : undefined}</CenteredText>
|
||||
<OutlinedText
|
||||
fontSize="6vmin"
|
||||
fontWeight="bold"
|
||||
strokeWidth="0.6vmin"
|
||||
>
|
||||
{counterTotal ? counterTotal : undefined}
|
||||
</OutlinedText>
|
||||
</IconContainer>
|
||||
</StyledExtraCounterButton>
|
||||
</ExtraCounterContainer>
|
||||
|
||||
57
my-app/src/Components/Counters/CommanderDamageBar.tsx
Normal file
57
my-app/src/Components/Counters/CommanderDamageBar.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Player, Rotation } from '../../Types/Player';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { CommanderDamage } from '../Buttons/CommanderDamage';
|
||||
|
||||
const CommanderDamageGrid = styled.div<{ rotation: number }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
|
||||
${(props) => {
|
||||
if (
|
||||
props.rotation === Rotation.SideFlipped ||
|
||||
props.rotation === Rotation.Side
|
||||
) {
|
||||
return css`
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
||||
type CommanderDamageBarProps = {
|
||||
opponents: Player[];
|
||||
player: Player;
|
||||
onPlayerChange: (updatedPlayer: Player) => void;
|
||||
setLifeTotal: (lifeTotal: number) => void;
|
||||
};
|
||||
|
||||
const CommanderDamageBar = ({
|
||||
opponents,
|
||||
player,
|
||||
onPlayerChange,
|
||||
setLifeTotal,
|
||||
}: CommanderDamageBarProps) => {
|
||||
return (
|
||||
<CommanderDamageGrid rotation={player.settings.rotation}>
|
||||
{opponents.map((opponent) => {
|
||||
if (!opponent.settings.useCommanderDamage) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<CommanderDamage
|
||||
player={player}
|
||||
opponent={opponent}
|
||||
setLifeTotal={setLifeTotal}
|
||||
onPlayerChange={onPlayerChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</CommanderDamageGrid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommanderDamageBar;
|
||||
@@ -58,14 +58,14 @@ const Counters = ({
|
||||
) {
|
||||
return (
|
||||
<GridItemContainer
|
||||
key={player.key}
|
||||
gridArea={`player${player.key}`}
|
||||
key={player.index}
|
||||
gridArea={`player${player.index}`}
|
||||
>
|
||||
<LifeCounter
|
||||
backgroundColor={player.color}
|
||||
player={player}
|
||||
opponents={players.filter(
|
||||
(opponent) => opponent.key !== player.key
|
||||
(opponent) => opponent.index !== player.index
|
||||
)}
|
||||
onPlayerChange={onPlayerChange}
|
||||
resetCurrentGame={resetCurrentGame}
|
||||
@@ -75,14 +75,14 @@ const Counters = ({
|
||||
}
|
||||
return (
|
||||
<GridItemContainer
|
||||
key={player.key}
|
||||
gridArea={`player${player.key}`}
|
||||
key={player.index}
|
||||
gridArea={`player${player.index}`}
|
||||
>
|
||||
<LifeCounter
|
||||
backgroundColor={player.color}
|
||||
player={player}
|
||||
opponents={players.filter(
|
||||
(opponent) => opponent.key !== player.key
|
||||
(opponent) => opponent.index !== player.index
|
||||
)}
|
||||
onPlayerChange={onPlayerChange}
|
||||
resetCurrentGame={resetCurrentGame}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Player } from '../../Types/Player';
|
||||
import { useSwipeable } from 'react-swipeable';
|
||||
import CommanderDamageBar from '../Buttons/CommanderDamageBar';
|
||||
import PlayerMenu from '../PlayerMenu/PlayerMenu';
|
||||
import SettingsButton from '../Buttons/SettingsButton';
|
||||
import ExtraCountersBar from '../Counters/ExtraCountersBar';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled, { css, keyframes } from 'styled-components';
|
||||
import { Rotation } from '../../Types/Player';
|
||||
import { Player, Rotation } from '../../Types/Player';
|
||||
import LifeCounterButton from '../Buttons/LifeCounterButton';
|
||||
import SettingsButton from '../Buttons/SettingsButton';
|
||||
import CommanderDamageBar from '../Counters/CommanderDamageBar';
|
||||
import ExtraCountersBar from '../Counters/ExtraCountersBar';
|
||||
import PlayerMenu from '../PlayerMenu/PlayerMenu';
|
||||
import { OutlinedText } from '../Text/OutlinedText';
|
||||
|
||||
export const LifeCounterWrapper = styled.div<{
|
||||
backgroundColor: string;
|
||||
@@ -79,24 +78,16 @@ export const LifeCountainer = styled.div<{
|
||||
}}
|
||||
`;
|
||||
|
||||
export const LifeCounterText = styled.p<{
|
||||
export const LifeCounterTextContainer = styled.p<{
|
||||
rotation: Rotation;
|
||||
}>`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
translate: -50% -50%;
|
||||
font-size: 30vmin;
|
||||
text-align: center;
|
||||
text-size-adjust: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-variant-numeric: tabular-nums;
|
||||
pointer-events: none;
|
||||
text-shadow: -1px -1px 0 #ffffff, 1px -1px 0 #ffffff, -1px 1px 0 #ffffff,
|
||||
1px 1px 0 #ffffff;
|
||||
color: #000000;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
@@ -133,6 +124,7 @@ export const RecentDifference = styled.span`
|
||||
transform: translate(-50%, -50%);
|
||||
text-shadow: none;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
font-variant-numeric: tabular-nums;
|
||||
border-radius: 50%;
|
||||
padding: 5px 10px;
|
||||
font-size: 8vmin;
|
||||
@@ -175,23 +167,10 @@ const LifeCounter = ({
|
||||
return () => clearTimeout(timer);
|
||||
}, [recentDifference]);
|
||||
|
||||
const swipeHandlers = useSwipeable({
|
||||
onSwipedUp: () => {
|
||||
// player.settings.flipped ? setShowPlayerMenu(true) : null;
|
||||
},
|
||||
onSwipedDown: () => {
|
||||
// player.settings.flipped ? null : setShowPlayerMenu(true);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<LifeCounterWrapper backgroundColor={backgroundColor}>
|
||||
<LifeCounterContentContainer
|
||||
{...swipeHandlers}
|
||||
rotation={player.settings.rotation}
|
||||
>
|
||||
<LifeCounterContentContainer rotation={player.settings.rotation}>
|
||||
<CommanderDamageBar
|
||||
lifeTotal={player.lifeTotal}
|
||||
opponents={opponents}
|
||||
player={player}
|
||||
onPlayerChange={onPlayerChange}
|
||||
@@ -211,15 +190,17 @@ const LifeCounter = ({
|
||||
operation="subtract"
|
||||
increment={-1}
|
||||
/>
|
||||
<LifeCounterText rotation={player.settings.rotation}>
|
||||
<LifeCounterTextContainer rotation={player.settings.rotation}>
|
||||
<OutlinedText fontSize="30vmin" strokeWidth="1.5vmin">
|
||||
{player.lifeTotal}
|
||||
</OutlinedText>
|
||||
{recentDifference !== 0 && (
|
||||
<RecentDifference key={key}>
|
||||
{recentDifference > 0 ? '+' : ''}
|
||||
{recentDifference}
|
||||
</RecentDifference>
|
||||
)}
|
||||
</LifeCounterText>
|
||||
</LifeCounterTextContainer>
|
||||
<LifeCounterButton
|
||||
lifeTotal={player.lifeTotal}
|
||||
setLifeTotal={handleLifeChange}
|
||||
|
||||
68
my-app/src/Components/Text/OutlinedText.tsx
Normal file
68
my-app/src/Components/Text/OutlinedText.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import styled from 'styled-components';
|
||||
import { theme } from '../../Data/theme';
|
||||
|
||||
export const CenteredText = styled.div<{
|
||||
strokeWidth?: string;
|
||||
strokeColor?: string;
|
||||
fillColor?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: string;
|
||||
}>`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-weight: ${(props) => props.fontWeight || ''};
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: #b5b2b2;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-moz-user-select: -moz-none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
|
||||
font-size: ${(props) => props.fontSize || '6vmin'};
|
||||
-webkit-text-stroke: ${(props) => props.strokeWidth || '1vmin'}
|
||||
${(props) => props.strokeColor || theme.palette.common.white};
|
||||
-webkit-text-fill-color: ${(props) =>
|
||||
props.fillColor || theme.palette.common.black};
|
||||
`;
|
||||
|
||||
const CenteredTextOutline = styled.span`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
-webkit-text-stroke: 0;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
type OutlinedTextProps = {
|
||||
children?: React.ReactNode;
|
||||
fontSize?: string;
|
||||
fontWeight?: string;
|
||||
strokeWidth?: string;
|
||||
strokeColor?: string;
|
||||
fillColor?: string;
|
||||
};
|
||||
|
||||
export const OutlinedText: React.FC<OutlinedTextProps> = ({
|
||||
children,
|
||||
fontSize,
|
||||
fontWeight,
|
||||
strokeWidth,
|
||||
strokeColor,
|
||||
fillColor,
|
||||
}) => {
|
||||
return (
|
||||
<CenteredText
|
||||
fontSize={fontSize}
|
||||
fontWeight={fontWeight}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeColor={strokeColor}
|
||||
fillColor={fillColor}
|
||||
>
|
||||
{children}
|
||||
<CenteredTextOutline aria-hidden>{children}</CenteredTextOutline>
|
||||
</CenteredText>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { GridTemplateAreas } from '../../../Data/getGridTemplateAreas';
|
||||
import { GridTemplateAreas } from '../../../Data/GridTemplateAreas';
|
||||
import { FormControlLabel, Radio, RadioGroup } from '@mui/material';
|
||||
import OnePlayerLandscape from '../../../Icons/Layouts/OnePlayerLandscape';
|
||||
import OnePlayerPortrait from '../../../Icons/Layouts/OnePlayerPortrait';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Button, FormControl, FormLabel, Switch } from '@mui/material';
|
||||
import Slider from '@mui/material/Slider';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { GridTemplateAreas } from '../../../Data/getGridTemplateAreas';
|
||||
import { GridTemplateAreas } from '../../../Data/GridTemplateAreas';
|
||||
import {
|
||||
InitialSettings,
|
||||
createInitialPlayers,
|
||||
@@ -196,7 +196,7 @@ const Start = ({
|
||||
/>
|
||||
|
||||
<FormLabel>Layout</FormLabel>
|
||||
{/* Use the new LayoutOptions component */}
|
||||
|
||||
<LayoutOptions
|
||||
numberOfPlayers={playerOptions.numberOfPlayers}
|
||||
gridAreas={playerOptions.gridAreas}
|
||||
|
||||
15
my-app/src/Data/GridTemplateAreas.ts
Normal file
15
my-app/src/Data/GridTemplateAreas.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export enum GridTemplateAreas {
|
||||
OnePlayerLandscape = '"player0 player0"',
|
||||
OnePlayerPortrait = '"player0" "player0"',
|
||||
TwoPlayersOppositeLandscape = '"player0" "player1"',
|
||||
TwoPlayersOppositePortrait = '"player0 player1" "player0 player1"',
|
||||
TwoPlayersSameSide = '"player0 player1"',
|
||||
ThreePlayers = '"player0 player0" "player1 player2"',
|
||||
ThreePlayersSide = '"player0 player0 player0 player2" "player1 player1 player1 player2"',
|
||||
FourPlayers = '"player0 player1" "player2 player3"',
|
||||
FourPlayersSide = '"player0 player1 player1 player1 player3" "player0 player2 player2 player2 player3"',
|
||||
FivePlayers = '"player0 player0 player0 player1 player1 player1" "player2 player2 player3 player3 player4 player4"',
|
||||
FivePlayersSide = '"player0 player0 player0 player0 player0 player1 player1 player1 player1 player1 player2" "player3 player3 player3 player3 player3 player4 player4 player4 player4 player4 player2"',
|
||||
SixPlayers = '"player0 player1 player2" "player3 player4 player5"',
|
||||
SixPlayersSide = '"player0 player1 player1 player1 player1 player2 player2 player2 player2 player3" "player0 player4 player4 player4 player4 player5 player5 player5 player5 player3"',
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
export enum GridTemplateAreas {
|
||||
OnePlayerLandscape = '"player1 player1"',
|
||||
OnePlayerPortrait = '"player1" "player1"',
|
||||
TwoPlayersOppositeLandscape = '"player1" "player2"',
|
||||
TwoPlayersOppositePortrait = '"player1 player2" "player1 player2"',
|
||||
TwoPlayersSameSide = '"player1 player2"',
|
||||
ThreePlayers = '"player1 player1" "player2 player3"',
|
||||
ThreePlayersSide = '"player1 player1 player1 player3" "player2 player2 player2 player3"',
|
||||
FourPlayers = '"player1 player2" "player3 player4"',
|
||||
FourPlayersSide = '"player1 player2 player2 player2 player4" "player1 player3 player3 player3 player4"',
|
||||
FivePlayers = '"player1 player1 player1 player2 player2 player2" "player3 player3 player4 player4 player5 player5"',
|
||||
FivePlayersSide = '"player1 player1 player1 player1 player1 player2 player2 player2 player2 player2 player3" "player4 player4 player4 player4 player4 player5 player5 player5 player5 player5 player3"',
|
||||
SixPlayers = '"player1 player2 player3" "player4 player5 player6"',
|
||||
SixPlayersSide = '"player1 player2 player2 player2 player2 player3 player3 player3 player3 player4" "player1 player5 player5 player5 player5 player6 player6 player6 player6 player4"',
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Player, Rotation } from '../Types/Player';
|
||||
import { GridTemplateAreas } from './getGridTemplateAreas';
|
||||
import { GridTemplateAreas } from './GridTemplateAreas';
|
||||
|
||||
export type InitialSettings = {
|
||||
startingLifeTotal: number;
|
||||
@@ -30,9 +30,9 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.TwoPlayersOppositePortrait) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.SideFlipped;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Side;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -41,9 +41,9 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.TwoPlayersOppositeLandscape) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -52,9 +52,9 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.TwoPlayersSameSide) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.Normal;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -63,11 +63,11 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.ThreePlayers) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Normal;
|
||||
case 3:
|
||||
case 2:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -76,11 +76,11 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.ThreePlayersSide) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Normal;
|
||||
case 3:
|
||||
case 2:
|
||||
return Rotation.Side;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -89,13 +89,13 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.FourPlayers) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
return Rotation.Flipped;
|
||||
case 3:
|
||||
return Rotation.Normal;
|
||||
case 4:
|
||||
case 3:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -104,13 +104,13 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.FourPlayersSide) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.SideFlipped;
|
||||
case 2:
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 3:
|
||||
case 2:
|
||||
return Rotation.Normal;
|
||||
case 4:
|
||||
case 3:
|
||||
return Rotation.Side;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -119,16 +119,16 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.FivePlayers) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
return Rotation.Flipped;
|
||||
return Rotation.Normal;
|
||||
case 3:
|
||||
return Rotation.Normal;
|
||||
case 4:
|
||||
return Rotation.Normal;
|
||||
case 5:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
}
|
||||
@@ -136,15 +136,15 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.FivePlayersSide) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
return Rotation.Flipped;
|
||||
case 3:
|
||||
return Rotation.Side;
|
||||
case 4:
|
||||
case 3:
|
||||
return Rotation.Normal;
|
||||
case 5:
|
||||
case 4:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -153,18 +153,18 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.SixPlayers) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return Rotation.Flipped;
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
return Rotation.Flipped;
|
||||
case 3:
|
||||
return Rotation.Flipped;
|
||||
return Rotation.Normal;
|
||||
case 4:
|
||||
return Rotation.Normal;
|
||||
case 5:
|
||||
return Rotation.Normal;
|
||||
case 6:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
}
|
||||
@@ -172,17 +172,17 @@ const getRotation = (index: number, gridAreas: GridTemplateAreas): Rotation => {
|
||||
|
||||
if (gridAreas === GridTemplateAreas.SixPlayersSide) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
case 0:
|
||||
return Rotation.SideFlipped;
|
||||
case 1:
|
||||
return Rotation.Flipped;
|
||||
case 2:
|
||||
return Rotation.Flipped;
|
||||
case 3:
|
||||
return Rotation.Flipped;
|
||||
case 4:
|
||||
return Rotation.Side;
|
||||
case 5:
|
||||
case 4:
|
||||
return Rotation.Normal;
|
||||
case 6:
|
||||
case 5:
|
||||
return Rotation.Normal;
|
||||
default:
|
||||
return Rotation.Normal;
|
||||
@@ -201,7 +201,7 @@ export const createInitialPlayers = ({
|
||||
const players: Player[] = [];
|
||||
const availableColors = [...presetColors]; // Create a copy of the colors array
|
||||
|
||||
for (let i = 1; i <= numberOfPlayers; i++) {
|
||||
for (let i = 0; i <= numberOfPlayers - 1; i++) {
|
||||
const colorIndex = Math.floor(Math.random() * availableColors.length);
|
||||
const color = availableColors[colorIndex];
|
||||
|
||||
@@ -209,19 +209,19 @@ export const createInitialPlayers = ({
|
||||
availableColors.splice(colorIndex, 1);
|
||||
|
||||
const commanderDamage = [];
|
||||
for (let j = 1; j <= numberOfPlayers; j++) {
|
||||
for (let j = 0; j <= numberOfPlayers - 1; j++) {
|
||||
commanderDamage.push({
|
||||
source: j,
|
||||
damageTotal: 0,
|
||||
partnerDamageTotal: 0,
|
||||
});
|
||||
}
|
||||
|
||||
const rotation = getRotation(i, gridAreas);
|
||||
console.log(rotation);
|
||||
|
||||
const player: Player = {
|
||||
lifeTotal: startingLifeTotal,
|
||||
key: i,
|
||||
index: i,
|
||||
color,
|
||||
settings: {
|
||||
useCommanderDamage,
|
||||
|
||||
@@ -19,7 +19,7 @@ export const theme = createTheme({
|
||||
disabled: '#5E714C',
|
||||
},
|
||||
common: {
|
||||
white: '#ffffff',
|
||||
white: '#F9FFE3',
|
||||
black: '#000000',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export type Player = {
|
||||
lifeTotal: number;
|
||||
key: number;
|
||||
index: number;
|
||||
color: string;
|
||||
settings: PlayerSettings;
|
||||
commanderDamage: CommanderDamage[];
|
||||
|
||||
Reference in New Issue
Block a user