mirror of
https://github.com/Vikeo/LifeTrinket.git
synced 2025-11-20 09:48:00 +00:00
stable state
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
|
||||||
render(<App />);
|
|
||||||
const linkElement = screen.getByText(/learn react/i);
|
|
||||||
expect(linkElement).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
@@ -1,15 +1,70 @@
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
import Counters from './Components/Counters/Counters';
|
import Counters from './Components/Counters/Counters';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Player } from './Types/Player';
|
||||||
|
|
||||||
const MainWrapper = styled.div`
|
const MainWrapper = styled.div`
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const players: Player[] = [
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
color: "grey",
|
||||||
|
settings: {
|
||||||
|
useCommanderDamage: true,
|
||||||
|
usePartner: true,
|
||||||
|
useEnergy: true,
|
||||||
|
useExperience: true,
|
||||||
|
usePoison: true,
|
||||||
|
flipped: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
color: "mintcream",
|
||||||
|
settings: {
|
||||||
|
useCommanderDamage: true,
|
||||||
|
usePartner: false,
|
||||||
|
useEnergy: true,
|
||||||
|
useExperience: true,
|
||||||
|
usePoison: true,
|
||||||
|
flipped: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 3,
|
||||||
|
color: "gold",
|
||||||
|
settings: {
|
||||||
|
useCommanderDamage: true,
|
||||||
|
usePartner: false,
|
||||||
|
useEnergy: true,
|
||||||
|
useExperience: true,
|
||||||
|
usePoison: true,
|
||||||
|
flipped: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 4,
|
||||||
|
color: "aquamarine",
|
||||||
|
settings: {
|
||||||
|
useCommanderDamage: true,
|
||||||
|
usePartner: true,
|
||||||
|
useEnergy: true,
|
||||||
|
useExperience: true,
|
||||||
|
usePoison: true,
|
||||||
|
flipped: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<MainWrapper>
|
<MainWrapper>
|
||||||
<Counters/>
|
<Counters players={players} />
|
||||||
</MainWrapper>
|
</MainWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
61
my-app/src/Components/Buttons/AddLifeButton.tsx
Normal file
61
my-app/src/Components/Buttons/AddLifeButton.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const StyledLifeCounterButton = styled.button<{ align?: string }>`
|
||||||
|
width: 50%;
|
||||||
|
height: auto;
|
||||||
|
color: rgba(0, 0, 0, 0.4);
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 28px;
|
||||||
|
text-align: ${props => props.align || "center"};
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type AddLifeButtonProps = {
|
||||||
|
lifeTotal: number;
|
||||||
|
setLifeTotal: (lifeTotal: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AddLifeButton = ({ lifeTotal, setLifeTotal }: AddLifeButtonProps) => {
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
|
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||||
|
|
||||||
|
const handleLifeChange = (increment: number) => {
|
||||||
|
setLifeTotal(lifeTotal + increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownInput = () => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
handleLifeChange(10);
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpInput = () => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handleLifeChange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledLifeCounterButton
|
||||||
|
onPointerDown={handleDownInput}
|
||||||
|
onPointerUp={handleUpInput}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
align="right"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</StyledLifeCounterButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddLifeButton;
|
||||||
174
my-app/src/Components/Buttons/CommanderDamageBar.tsx
Normal file
174
my-app/src/Components/Buttons/CommanderDamageBar.tsx
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { Player } from "../../Types/Player";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const CommanderDamageGrid = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CommanderDamageContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CommanderDamageButton = styled.button<{ backgroundColor?: string }>`
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
border: none;
|
||||||
|
height: 10vh;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: ${props => props.backgroundColor || "antiquewhite"};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CommanderDamageButtonText = styled.p`
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
text-size-adjust: auto;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
pointer-events: none;
|
||||||
|
width: 2rem;
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const VerticalSeperator = styled.div`
|
||||||
|
width: 1px;
|
||||||
|
background-color: rgba(0, 0, 0, 1);
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type CommanderDamageBarProps = {
|
||||||
|
lifeTotal: number;
|
||||||
|
setLifeTotal: (lifeTotal: number) => void;
|
||||||
|
opponents: Player[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const CommanderDamageBar = ({ opponents, lifeTotal, setLifeTotal }: CommanderDamageBarProps) => {
|
||||||
|
const [commanderDamage, setCommanderDamage] = useState<number[]>(
|
||||||
|
Array(opponents.length).fill(0)
|
||||||
|
);
|
||||||
|
const [partnerCommanderDamage, setPartnerCommanderDamage] = useState<number[]>(
|
||||||
|
Array(opponents.length).fill(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
|
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||||
|
|
||||||
|
const handleCommanderDamageChange = (index: number, increment: number) => {
|
||||||
|
const currentCommanderDamage = commanderDamage[index];
|
||||||
|
if (currentCommanderDamage === 0 && increment === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCommanderDamage === 21 && increment === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedCommanderDamage = [...commanderDamage];
|
||||||
|
updatedCommanderDamage[index] += increment;
|
||||||
|
setCommanderDamage(updatedCommanderDamage);
|
||||||
|
setLifeTotal(lifeTotal - increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePartnerCommanderDamageChange = (index: number, increment: number) => {
|
||||||
|
const currentPartnerCommanderDamage = partnerCommanderDamage[index];
|
||||||
|
if (currentPartnerCommanderDamage === 0 && increment === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedPartnerCommanderDamage = [...partnerCommanderDamage];
|
||||||
|
updatedPartnerCommanderDamage[index] += increment;
|
||||||
|
|
||||||
|
setPartnerCommanderDamage(updatedPartnerCommanderDamage);
|
||||||
|
setLifeTotal(lifeTotal - increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownInput = (index: number) => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
handleCommanderDamageChange(index, -1);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpInput = (index: number) => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handleCommanderDamageChange(index, 1);
|
||||||
|
}
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePartnerDownInput = (index: number) => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
handlePartnerCommanderDamageChange(index, -1);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePartnerUpInput = (index: number) => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handlePartnerCommanderDamageChange(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CommanderDamageGrid>
|
||||||
|
{opponents.map((opponent, index) => {
|
||||||
|
return (
|
||||||
|
<CommanderDamageContainer>
|
||||||
|
<CommanderDamageButton
|
||||||
|
key={index}
|
||||||
|
onPointerDown={() => handleDownInput(index)}
|
||||||
|
onPointerUp={() => handleUpInput(index)}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backgroundColor={opponent.color}
|
||||||
|
>
|
||||||
|
<CommanderDamageButtonText>
|
||||||
|
{commanderDamage[index] > 0 ? commanderDamage[index] : ""}
|
||||||
|
</CommanderDamageButtonText>
|
||||||
|
</CommanderDamageButton>
|
||||||
|
|
||||||
|
{opponent.settings.usePartner && (
|
||||||
|
<>
|
||||||
|
<VerticalSeperator />
|
||||||
|
<CommanderDamageButton
|
||||||
|
key={index}
|
||||||
|
onPointerDown={() => handlePartnerDownInput(index)}
|
||||||
|
onPointerUp={() => handlePartnerUpInput(index)}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backgroundColor={opponent.color}
|
||||||
|
>
|
||||||
|
<CommanderDamageButtonText>
|
||||||
|
{partnerCommanderDamage[index] > 0 ? partnerCommanderDamage[index] : ""}
|
||||||
|
</CommanderDamageButtonText>
|
||||||
|
</CommanderDamageButton>
|
||||||
|
</>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</CommanderDamageContainer>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</CommanderDamageGrid>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CommanderDamageBar;
|
||||||
56
my-app/src/Components/Buttons/CommanderTaxButton.tsx
Normal file
56
my-app/src/Components/Buttons/CommanderTaxButton.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import CommanderTaxIcon from "../../Icons/CommanderTaxIcon";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const StyledCommanderTaxButton = styled.button`
|
||||||
|
flex-grow: 1;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CommanderTaxButton = () => {
|
||||||
|
const [commanderTax, setCommanderTax] = useState(0);
|
||||||
|
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
|
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||||
|
|
||||||
|
const handleCommanderTaxChange = (increment: number) => {
|
||||||
|
setCommanderTax(commanderTax + increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownInput = () => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
handleCommanderTaxChange(-1);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpInput = () => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handleCommanderTaxChange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledCommanderTaxButton
|
||||||
|
onPointerDown={handleDownInput}
|
||||||
|
onPointerUp={handleUpInput}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CommanderTaxIcon
|
||||||
|
size="8vh"
|
||||||
|
text={commanderTax ? commanderTax : undefined}
|
||||||
|
/>
|
||||||
|
</StyledCommanderTaxButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CommanderTaxButton;
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import CommanderTaxIcon from "../../Icons/CommanderTaxIcon";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const StyledCommanderTaxButton = styled.button`
|
||||||
|
flex-grow: 1;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PartnerCommanderTaxButton = () => {
|
||||||
|
const [partnerCommanderTax, setPartnerCommanderTax] = useState(0);
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
|
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||||
|
|
||||||
|
const handlePartnerCommanderTaxChange = (increment: number) => {
|
||||||
|
setPartnerCommanderTax(partnerCommanderTax + increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleDownInput = () => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
handlePartnerCommanderTaxChange(-1);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpInput = () => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handlePartnerCommanderTaxChange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledCommanderTaxButton
|
||||||
|
onPointerDown={handleDownInput}
|
||||||
|
onPointerUp={handleUpInput}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CommanderTaxIcon
|
||||||
|
size="8vh"
|
||||||
|
text={partnerCommanderTax ? partnerCommanderTax : undefined}
|
||||||
|
/> 2
|
||||||
|
</StyledCommanderTaxButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PartnerCommanderTaxButton;
|
||||||
61
my-app/src/Components/Buttons/SubtractLifeButton.tsx
Normal file
61
my-app/src/Components/Buttons/SubtractLifeButton.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const StyledLifeCounterButton = styled.button<{ align?: string }>`
|
||||||
|
width: 50%;
|
||||||
|
height: auto;
|
||||||
|
color: rgba(0, 0, 0, 0.4);
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 28px;
|
||||||
|
text-align: ${props => props.align || "center"};
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type SubtractLifeButtonProps = {
|
||||||
|
lifeTotal: number;
|
||||||
|
setLifeTotal: (lifeTotal: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubtractLifeButton = ({ lifeTotal, setLifeTotal }: SubtractLifeButtonProps) => {
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||||
|
const [timeoutFinished, setTimeoutFinished] = useState(false);
|
||||||
|
|
||||||
|
const handleLifeChange = (increment: number) => {
|
||||||
|
setLifeTotal(lifeTotal + increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownInput = () => {
|
||||||
|
setTimeoutFinished(false);
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
handleLifeChange(-10);
|
||||||
|
setTimeoutFinished(true);
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpInput = () => {
|
||||||
|
if (!timeoutFinished) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
handleLifeChange(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledLifeCounterButton
|
||||||
|
onPointerDown={handleDownInput}
|
||||||
|
onPointerUp={handleUpInput}
|
||||||
|
onContextMenu={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
align="left"
|
||||||
|
>
|
||||||
|
−
|
||||||
|
</StyledLifeCounterButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SubtractLifeButton;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
export const CountersWrapper = styled.div`
|
export const CountersWrapper = styled.div`
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
height: 100vh;
|
max-height: 100%;
|
||||||
background-color: #4f4f4f;
|
background-color: black;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CountersGrid = styled.div`
|
export const CountersGrid = styled.div`
|
||||||
@@ -11,16 +11,27 @@ export const CountersGrid = styled.div`
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 10px;
|
|
||||||
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
|
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
|
||||||
-moz-box-sizing: border-box; /* Firefox, other Gecko */
|
-moz-box-sizing: border-box; /* Firefox, other Gecko */
|
||||||
box-sizing: border-box; /* Opera/IE 8+ */
|
box-sizing: border-box; /* Opera/IE 8+ */
|
||||||
|
row-gap: 4px;
|
||||||
|
column-gap: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GridItemContainer = styled.div`
|
export const GridItemContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 50%;
|
width: calc(50vw - 2px);
|
||||||
height: 50vh;
|
height: calc(50vh - 2px);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const GridItemContainerFlipped = styled.div`
|
||||||
|
display: flex;
|
||||||
|
width: calc(50vw - 2px);
|
||||||
|
height: calc(50vh - 2px);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,36 @@
|
|||||||
import * as S from "./Counters.style";
|
import * as S from "./Counters.style";
|
||||||
import LifeCounter from "../LifeCounter/LifeCounter";
|
import LifeCounter from "../LifeCounter/LifeCounter";
|
||||||
|
import { Player } from "../../Types/Player";
|
||||||
|
|
||||||
|
type CountersProps = {
|
||||||
|
players: Player[];
|
||||||
|
};
|
||||||
|
|
||||||
const Counters = () => {
|
const Counters = ({ players }: CountersProps) => {
|
||||||
return (
|
return (
|
||||||
<S.CountersWrapper>
|
<S.CountersWrapper>
|
||||||
<S.CountersGrid>
|
<S.CountersGrid>
|
||||||
<S.GridItemContainer>
|
{players.map((player) => {
|
||||||
<LifeCounter backgroundColor="grey"/>
|
if (player.settings.flipped) {
|
||||||
</S.GridItemContainer>
|
return (
|
||||||
<S.GridItemContainer>
|
<S.GridItemContainerFlipped>
|
||||||
<LifeCounter backgroundColor="pink"/>
|
<LifeCounter backgroundColor={player.color} player={player} opponents={
|
||||||
</S.GridItemContainer>
|
players.filter((opponent) => opponent.key !== player.key)
|
||||||
<S.GridItemContainer>
|
} />
|
||||||
<LifeCounter backgroundColor="white"/>
|
</S.GridItemContainerFlipped>
|
||||||
</S.GridItemContainer>
|
)
|
||||||
<S.GridItemContainer>
|
}
|
||||||
<LifeCounter backgroundColor="lightblue"/>
|
return (
|
||||||
</S.GridItemContainer>
|
<S.GridItemContainer>
|
||||||
</S.CountersGrid>
|
<LifeCounter backgroundColor={player.color} player={player} opponents={
|
||||||
</S.CountersWrapper>
|
players.filter((opponent) => opponent.key !== player.key)
|
||||||
);
|
} />
|
||||||
|
</S.GridItemContainer>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</S.CountersGrid>
|
||||||
|
</S.CountersWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Counters;
|
export default Counters;
|
||||||
|
|||||||
@@ -1,36 +1,44 @@
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
|
||||||
//LifeCounterWrapper with a background color variable:
|
|
||||||
export const LifeCounterWrapper = styled.div<{ backgroundColor?: string }>`
|
export const LifeCounterWrapper = styled.div<{ backgroundColor?: string }>`
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: ${props => props.backgroundColor || "antiquewhite"};
|
background-color: ${props => props.backgroundColor || "antiquewhite"};
|
||||||
border-radius: 10px;
|
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const LifeCounterButton = styled.button`
|
export const LifeCountainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 5rem;
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const LifeCounterText = styled.p`
|
export const LifeCounterText = styled.p`
|
||||||
font-size: 5rem;
|
position: absolute;
|
||||||
font-weight: bold;
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 30vh;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
text-size-adjust: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ExtraCountersGrid = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import * as S from "./LifeCounter.style";
|
import * as S from "./LifeCounter.style";
|
||||||
|
import { Player } from "../../Types/Player";
|
||||||
|
import CommanderTaxButton from "../Buttons/CommanderTaxButton";
|
||||||
|
import PartnerCommanderTaxButton from "../Buttons/PartnerCommanderTaxButton copy";
|
||||||
|
import AddLifeButton from "../Buttons/AddLifeButton";
|
||||||
|
import SubtractLifeButton from "../Buttons/SubtractLifeButton";
|
||||||
|
import CommanderDamageBar from "../Buttons/CommanderDamageBar";
|
||||||
|
|
||||||
type LifeCounterProps = {
|
type LifeCounterProps = {
|
||||||
|
player: Player;
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
}
|
opponents: Player[];
|
||||||
|
};
|
||||||
|
|
||||||
const LifeCounter = ({backgroundColor}: LifeCounterProps) => {
|
const LifeCounter = ({ backgroundColor, player, opponents }: LifeCounterProps) => {
|
||||||
const [life, setLife] = useState(40);
|
const [lifeTotal, setLifeTotal] = useState(40);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<S.LifeCounterWrapper backgroundColor={backgroundColor}>
|
<S.LifeCounterWrapper backgroundColor={backgroundColor}>
|
||||||
<S.LifeCounterButton onClick={() => setLife(life - 1)}>-</S.LifeCounterButton>
|
<CommanderDamageBar lifeTotal={lifeTotal} setLifeTotal={setLifeTotal} opponents={opponents} />
|
||||||
<S.LifeCounterText>{life}</S.LifeCounterText>
|
<S.LifeCountainer>
|
||||||
<S.LifeCounterButton onClick={() => setLife(life + 1)}>+</S.LifeCounterButton>
|
<SubtractLifeButton lifeTotal={lifeTotal} setLifeTotal={setLifeTotal}/>
|
||||||
|
<S.LifeCounterText>{lifeTotal}</S.LifeCounterText>
|
||||||
|
<AddLifeButton lifeTotal={lifeTotal} setLifeTotal={setLifeTotal} />
|
||||||
|
</S.LifeCountainer>
|
||||||
|
<S.ExtraCountersGrid>
|
||||||
|
<CommanderTaxButton/>
|
||||||
|
{player.settings.usePartner && <PartnerCommanderTaxButton/>}
|
||||||
|
</S.ExtraCountersGrid>
|
||||||
</S.LifeCounterWrapper>
|
</S.LifeCounterWrapper>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default LifeCounter;
|
export default LifeCounter;
|
||||||
|
|||||||
39
my-app/src/Icons/CommanderTaxIcon.tsx
Normal file
39
my-app/src/Icons/CommanderTaxIcon.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
type CommanderTaxIconProps = {
|
||||||
|
size?: string;
|
||||||
|
text?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CommanderTaxIcon = ({ size, text }: CommanderTaxIconProps) => {
|
||||||
|
return (
|
||||||
|
<div style={{ position: 'relative', display: 'inline-block'}}>
|
||||||
|
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 325 325" width={size || 'auto'} height={size || 'auto'}>
|
||||||
|
<title>CommanderTaxIcon</title>
|
||||||
|
<style>{`.s0 { fill: #000000; fill-opacity: 0.5}`}</style>
|
||||||
|
<path
|
||||||
|
id="Lager 1"
|
||||||
|
className="s0"
|
||||||
|
d="m162 168c-40.9 0-74-33.1-74-74 0-40.9 33.1-74 74-74 40.9 0 74 33.1 74 74 0 40.9-33.1 74-74 74z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="Form 1"
|
||||||
|
className="s0"
|
||||||
|
d="m159.9 351.8c-11.4 0.3-22.5 0.7-33.2 1.2-10.6 0.6-20.8 1.3-30.5 1.8-9.6 0.5-18.8 0.6-27.2 0.5-8.4-0.6-16.1-1.6-23-3.4-6.9-2.3-12.9-5.5-18.1-9.5-5-4.7-9.1-10.4-12.2-16.9-3.1-7.1-5.2-15-6.3-23.4-1.1-8.8-1.2-17.9-0.4-27.1 0.8-9.2 2.4-17.7 4.7-25.3 2.2-7.4 5.2-13.9 8.8-19.5 3.6-5.3 7.8-9.9 12.8-13.6 4.8-3.7 10.5-6.9 16.8-9.5 6.4-2.9 13.6-5.4 21.5-7.6 7.9-2.4 16.6-4.6 26-6.5 9.4-2.1 19.4-3.8 29.9-5 10.6-1.3 21.7-2 33-2 11.3 0 22.4 0.7 33 2 10.5 1.2 20.6 2.9 30 5 9.4 1.9 18.2 4.1 26.2 6.5 7.9 2.3 15.2 4.8 21.7 7.6 6.4 2.7 12.2 5.8 17.1 9.5 5.1 3.8 9.4 8.3 12.9 13.7 3.7 5.5 6.7 12.1 8.9 19.5 2.3 7.7 3.8 16.2 4.5 25.3 0.7 9.2 0.4 18.3-0.9 27.1-1.3 8.4-3.6 16.2-6.8 23.3-3.4 6.4-7.8 11.9-13.1 16.4-5.5 3.9-11.8 6.9-19 9.1-7.3 1.6-15.4 2.6-24.1 3-8.8 0.1-18.3-0.1-28.2-0.5-10-0.4-20.5-0.9-31.4-1.3-10.8-0.3-22-0.5-33.4-0.4z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
fontSize: '8vh',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CommanderTaxIcon;
|
||||||
15
my-app/src/Types/Player.ts
Normal file
15
my-app/src/Types/Player.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export type Player = {
|
||||||
|
key: number;
|
||||||
|
color: string;
|
||||||
|
settings: PlayerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlayerSettings = {
|
||||||
|
useCommanderDamage: boolean;
|
||||||
|
flipped?: boolean;
|
||||||
|
usePartner?: boolean;
|
||||||
|
usePoison?: boolean;
|
||||||
|
useEnergy?: boolean;
|
||||||
|
useExperience?: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user