From c571b189c5e99a9d56b372fc0b7e61e29bfe9d94 Mon Sep 17 00:00:00 2001 From: Anna Branco Date: Mon, 5 Apr 2021 12:14:22 +0200 Subject: [PATCH] feat: [#304] Refactored XpBar component --- .../PlayersSection/CharacterSheet/index.js | 0 .../Sections/PlayersSection/index.js | 78 +++------ .../Sections/PlayersSection/styles.js | 149 ------------------ .../elements/AbilitiesArea/index.js | 16 ++ src/components/elements/ActionsArea/index.js | 16 ++ src/components/elements/CharId/index.js | 16 ++ src/components/elements/CharItems/index.js | 16 ++ src/components/elements/Indicators/index.js | 16 ++ .../elements/Items/ItemsArea/index.js | 4 +- src/components/elements/MovementsBar/index.js | 41 +++++ .../elements/MovementsBar/styles.js | 45 ++++++ src/components/elements/NavIcons/index.js | 16 ++ src/components/elements/SheetsModal/index.js | 16 ++ src/components/elements/XpBar/index.js | 77 +++++++++ src/components/elements/XpBar/styles.js | 111 +++++++++++++ src/interfaces/types.js | 5 + 16 files changed, 415 insertions(+), 207 deletions(-) create mode 100644 src/components/Sections/PlayersSection/CharacterSheet/index.js create mode 100644 src/components/elements/AbilitiesArea/index.js create mode 100644 src/components/elements/ActionsArea/index.js create mode 100644 src/components/elements/CharId/index.js create mode 100644 src/components/elements/CharItems/index.js create mode 100644 src/components/elements/Indicators/index.js create mode 100644 src/components/elements/MovementsBar/index.js create mode 100644 src/components/elements/MovementsBar/styles.js create mode 100644 src/components/elements/NavIcons/index.js create mode 100644 src/components/elements/SheetsModal/index.js create mode 100644 src/components/elements/XpBar/index.js create mode 100644 src/components/elements/XpBar/styles.js diff --git a/src/components/Sections/PlayersSection/CharacterSheet/index.js b/src/components/Sections/PlayersSection/CharacterSheet/index.js new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Sections/PlayersSection/index.js b/src/components/Sections/PlayersSection/index.js index 762f2e8..145f69e 100644 --- a/src/components/Sections/PlayersSection/index.js +++ b/src/components/Sections/PlayersSection/index.js @@ -201,7 +201,6 @@ import { ExtraActivationImage, FirstPlayerToken, FirstPlayerWrapper, - HighestXpTag, IndicatorsWrapper, LevelIndicator, MainButton, @@ -219,9 +218,10 @@ import { SelectButton, TopActionsLabelWrapper, WoundedSign, - WoundedWrapper, - XpIcon + WoundedWrapper } from './styles'; +import XpBar from '../../elements/XpBar'; +import MovementsBar from '../../elements/MovementsBar'; const PlayersSection = ({ damageMode, @@ -1811,61 +1811,27 @@ const PlayersSection = ({ {character.name && ( <> {/* ----- XP BAR ----- */} - {!trade && character.wounded !== KILLED && !objectivesAchieved && ( - - {xpCounter && - xpCounter.map((level, index) => ( - - setCustomXp( - level, - xpCounter[index - 1], - xpCounter[index + 1] - ) - : () => null - } - setupMode={setupMode} - size={xpCounter.length} - type={level} - > - {level} - {highestXp.xp === level && - highestXp.name !== character.name && ( - - {highestXp.name} - - )} - - ))} - - )} + {/* ----- MOVEMENTS BAR ----- */} - {!trade && character.wounded !== KILLED && !objectivesAchieved && ( - - {actionsCount.map((action, index) => ( - - {action} - - ))} - - )} + {/* ----- MAIN SECTION ----- */} {trade ? ( diff --git a/src/components/Sections/PlayersSection/styles.js b/src/components/Sections/PlayersSection/styles.js index 9eca21c..9fcba13 100644 --- a/src/components/Sections/PlayersSection/styles.js +++ b/src/components/Sections/PlayersSection/styles.js @@ -1126,35 +1126,6 @@ export const FirstPlayerWrapper = styled.div` `; FirstPlayerWrapper.displayName = 'FirstPlayerWrapper'; -export const HighestXpTag = styled.span` - label: HighestXpTag; - z-index: 15; - position: absolute; - top: 10px; - left: 50%; - transform: translate(-50%, 0); - font-family: ${TEXT_FONT}; - text-transform: uppercase; - font-size: 0.5rem; - color: black; - font-weight: 900; - user-select: none; - - @media all and (min-width: 701px) { - top: 20px; - font-size: 0.7rem; - color: white; - - ${({ xp }) => - xp <= 4 && - css` - font-size: 0.5rem; - top: -8px; - `} - } -`; -HighestXpTag.displayName = 'HighestXpTag'; - export const IndicatorsWrapper = styled.div` label: IndicatorsWrapper; z-index: 10; @@ -1372,49 +1343,6 @@ export const ModalSignText = styled.p` `; ModalSignText.displayName = 'ModalSignText'; -export const MovementIcon = styled.div` - label: MovementIcon; - position: relative; - left: 0.75em; - width: ${({ type }) => (typeof type === 'number' ? '20px' : '70px')}; - height: 14px; - text-align: center; - background: ${({ color }) => color}; - color: ${({ type }) => (typeof type === 'number' ? 'white' : 'black')}; - font-weight: 700; - line-height: 1.3; - letter-spacing: 0.001rem; - font-size: 0.8rem; - font-family: ${TITLE_FONT}; - text-transform: uppercase; - - &:not(:first-of-type) { - margin-left: 15px; - } - - &:after { - content: ''; - position: absolute; - left: 100%; - width: 10px; - height: 14px; - clip-path: polygon(50% 50%, -50% -50%, 0 100%); - background: ${({ color }) => color}; - } - &:before { - content: ''; - position: absolute; - left: 1px; - top: 0; - width: 10px; - height: 14px; - clip-path: polygon(100% 0, 100% 100%, 0% 100%, 50% 50%, 0% 0%); - transform: translateX(-100%); - background: ${({ color }) => color}; - } -`; -MovementIcon.displayName = 'MovementIcon'; - export const NavIcons = styled.img` label: NavIcons; z-index: 15; @@ -1772,80 +1700,3 @@ export const WoundedWrapper = styled.div` overflow: hidden; `; WoundedWrapper.displayName = 'WoundedWrapper'; - -export const XpIcon = styled(MovementIcon)` - label: XpIcon; - width: 25px; - left: 0; - user-select: none; - /* color: black; */ - color: black; - font-size: ${({ currentXp, device, highestXp }) => { - if (device === MOBILE) { - if (currentXp) { - return '1.1rem'; - } - if (highestXp) { - return '0.6rem'; - } - } else if (currentXp || highestXp) { - return '1.1rem'; - } - return null; - }}; - line-height: ${({ currentXp, highestXp }) => - currentXp || highestXp ? '1' : '1.2'}; - - background: ${({ activeColor }) => activeColor && activeColor}; - opacity: ${({ activeColor }) => activeColor && 1}; - height: ${({ currentXp, highestXp }) => - currentXp || highestXp ? '18px' : '14px'}; - width: ${({ currentXp, highestXp, size }) => - currentXp || highestXp - ? `calc(100% / ${size} + 10px) ` - : `calc(100% / ${size} )`}; - - &:not(:first-of-type) { - margin-left: 8px; - } - - &:after { - content: ''; - position: absolute; - left: 100%; - width: 6px; - height: ${({ currentXp, highestXp }) => - currentXp || highestXp ? '18px' : '14px'}; - clip-path: polygon(50% 50%, -50% -50%, 0 100%); - background: ${({ activeColor }) => activeColor && activeColor}; - } - &:before { - content: ''; - position: absolute; - /* left: 10px; */ - top: 0; - width: 6px; - height: ${({ currentXp, highestXp }) => - currentXp || highestXp ? '18px' : '14px'}; - clip-path: polygon(100% 0, 100% 100%, 0% 100%, 50% 50%, 0% 0%); - transform: translateX(-100%); - background: ${({ activeColor }) => activeColor && activeColor}; - } - - &:first-of-type:before { - clip-path: none; - } - &:last-of-type:after { - clip-path: none; - } - - ${({ setupMode }) => - setupMode && - css` - cursor: pointer; - `} - - @media all and (min-width: 701px) { - } -`; -XpIcon.displayName = 'XPIcon'; diff --git a/src/components/elements/AbilitiesArea/index.js b/src/components/elements/AbilitiesArea/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/AbilitiesArea/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/ActionsArea/index.js b/src/components/elements/ActionsArea/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/ActionsArea/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/CharId/index.js b/src/components/elements/CharId/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/CharId/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/CharItems/index.js b/src/components/elements/CharItems/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/CharItems/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/Indicators/index.js b/src/components/elements/Indicators/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/Indicators/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/Items/ItemsArea/index.js b/src/components/elements/Items/ItemsArea/index.js index af84cde..04c6bcf 100644 --- a/src/components/elements/Items/ItemsArea/index.js +++ b/src/components/elements/Items/ItemsArea/index.js @@ -7,8 +7,8 @@ import { logger, useStateWithLabel } from '../../../../utils'; -import ActionButton from '../../../elements/ActionButton'; -import SoundBlock from '../../../elements/SoundBlock'; +import ActionButton from '../../ActionButton'; +import SoundBlock from '../../SoundBlock'; import ZombieFace from '../../../../assets/images/zombieFace.png'; import { DROP, diff --git a/src/components/elements/MovementsBar/index.js b/src/components/elements/MovementsBar/index.js new file mode 100644 index 0000000..f9ba417 --- /dev/null +++ b/src/components/elements/MovementsBar/index.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { string, bool, number, arrayOf } from 'prop-types'; +import { getActionColor } from '../../../utils'; +import { IndicatorsWrapper } from '../../sections/PlayersSection/styles'; +import { MovementIcon } from './styles'; + +const MovementsBar = ({ + actionsCount, + charIsAlive, + gameHasEnded, + setupMode, + tradeModeActive +}) => { + return ( + <> + {charIsAlive && !gameHasEnded && !setupMode && !tradeModeActive && ( + + {actionsCount.map((action, index) => ( + + {action} + + ))} + + )} + + ); +}; + +MovementsBar.propTypes = { + actionsCount: arrayOf([string, number]).isRequired, + charIsAlive: bool.isRequired, + gameHasEnded: bool.isRequired, + setupMode: bool.isRequired, + tradeModeActive: bool.isRequired +}; + +export default MovementsBar; diff --git a/src/components/elements/MovementsBar/styles.js b/src/components/elements/MovementsBar/styles.js new file mode 100644 index 0000000..20a650a --- /dev/null +++ b/src/components/elements/MovementsBar/styles.js @@ -0,0 +1,45 @@ +import styled from '@emotion/styled'; +import { TITLE_FONT } from '../../../styles'; + +export const MovementIcon = styled.div` + label: MovementIcon; + position: relative; + left: 0.75em; + width: ${({ type }) => (typeof type === 'number' ? '20px' : '70px')}; + height: 14px; + text-align: center; + background: ${({ color }) => color}; + color: ${({ type }) => (typeof type === 'number' ? 'white' : 'black')}; + font-weight: 700; + line-height: 1.3; + letter-spacing: 0.001rem; + font-size: 0.8rem; + font-family: ${TITLE_FONT}; + text-transform: uppercase; + + &:not(:first-of-type) { + margin-left: 15px; + } + + &:after { + content: ''; + position: absolute; + left: 100%; + width: 10px; + height: 14px; + clip-path: polygon(50% 50%, -50% -50%, 0 100%); + background: ${({ color }) => color}; + } + &:before { + content: ''; + position: absolute; + left: 1px; + top: 0; + width: 10px; + height: 14px; + clip-path: polygon(100% 0, 100% 100%, 0% 100%, 50% 50%, 0% 0%); + transform: translateX(-100%); + background: ${({ color }) => color}; + } +`; +MovementIcon.displayName = 'MovementIcon'; diff --git a/src/components/elements/NavIcons/index.js b/src/components/elements/NavIcons/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/NavIcons/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/SheetsModal/index.js b/src/components/elements/SheetsModal/index.js new file mode 100644 index 0000000..d775bf5 --- /dev/null +++ b/src/components/elements/SheetsModal/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { string, func, bool, oneOfType } from 'prop-types'; + +const CharacterFace = ({ big }) => { + return ...; +}; + +CharacterFace.propTypes = { + big: bool +}; + +CharacterFace.defaultProps = { + big: false +}; + +export default CharacterFace; diff --git a/src/components/elements/XpBar/index.js b/src/components/elements/XpBar/index.js new file mode 100644 index 0000000..89f609f --- /dev/null +++ b/src/components/elements/XpBar/index.js @@ -0,0 +1,77 @@ +import React from 'react'; +import { string, func, bool, oneOfType, number, arrayOf } from 'prop-types'; +import { getXpColor } from '../../../utils'; +import { HighestXpType } from '../../../interfaces/types'; +import { IndicatorsWrapper } from '../../sections/PlayersSection/styles'; +import { HighestXpTag, XpIcon } from './styles'; + +const XpBar = ({ + currentXp, + charIsAlive, + device, + gameHasEnded, + setupMode, + xpCounter, + tradeModeActive, + setCustomXp, + highestXp, + characterName +}) => { + return ( + <> + {charIsAlive && !gameHasEnded && !tradeModeActive && ( + + {xpCounter && + xpCounter.map((level, index) => ( + + setCustomXp( + level, + xpCounter[index - 1], + xpCounter[index + 1] + ) + : () => null + } + setupMode={setupMode} + size={xpCounter.length} + type={level} + > + {level} + {highestXp.xp === level && highestXp.name !== characterName && ( + + {highestXp.name} + + )} + + ))} + + )} + + ); +}; + +XpBar.propTypes = { + characterName: string.isRequired, + currentXp: number.isRequired, + charIsAlive: bool.isRequired, + device: string.isRequired, + gameHasEnded: bool.isRequired, + setupMode: bool.isRequired, + xpCounter: arrayOf(oneOfType([number, string])).isRequired, + tradeModeActive: bool.isRequired, + setCustomXp: func.isRequired, + highestXp: HighestXpType.isRequired +}; + +export default XpBar; diff --git a/src/components/elements/XpBar/styles.js b/src/components/elements/XpBar/styles.js new file mode 100644 index 0000000..c78e89f --- /dev/null +++ b/src/components/elements/XpBar/styles.js @@ -0,0 +1,111 @@ +import styled from '@emotion/styled'; +import { css } from '@emotion/core'; +import { MOBILE } from '../../../constants'; +import { TEXT_FONT } from '../../../styles'; +import { MovementIcon } from '../MovementsBar/styles'; + +export const HighestXpTag = styled.span` + label: HighestXpTag; + z-index: 15; + position: absolute; + top: 10px; + left: 50%; + transform: translate(-50%, 0); + font-family: ${TEXT_FONT}; + text-transform: uppercase; + font-size: 0.5rem; + color: black; + font-weight: 900; + user-select: none; + + @media all and (min-width: 701px) { + top: 20px; + font-size: 0.7rem; + color: white; + + ${({ xp }) => + xp <= 4 && + css` + font-size: 0.5rem; + top: -8px; + `} + } +`; +HighestXpTag.displayName = 'HighestXpTag'; + +export const XpIcon = styled(MovementIcon)` + label: XpIcon; + width: 25px; + left: 0; + user-select: none; + /* color: black; */ + color: black; + font-size: ${({ currentXp, device, highestXp }) => { + if (device === MOBILE) { + if (currentXp) { + return '1.1rem'; + } + if (highestXp) { + return '0.6rem'; + } + } else if (currentXp || highestXp) { + return '1.1rem'; + } + return null; + }}; + line-height: ${({ currentXp, highestXp }) => + currentXp || highestXp ? '1' : '1.2'}; + + background: ${({ activeColor }) => activeColor && activeColor}; + opacity: ${({ activeColor }) => activeColor && 1}; + height: ${({ currentXp, highestXp }) => + currentXp || highestXp ? '18px' : '14px'}; + width: ${({ currentXp, highestXp, size }) => + currentXp || highestXp + ? `calc(100% / ${size} + 10px) ` + : `calc(100% / ${size} )`}; + + &:not(:first-of-type) { + margin-left: 8px; + } + + &:after { + content: ''; + position: absolute; + left: 100%; + width: 6px; + height: ${({ currentXp, highestXp }) => + currentXp || highestXp ? '18px' : '14px'}; + clip-path: polygon(50% 50%, -50% -50%, 0 100%); + background: ${({ activeColor }) => activeColor && activeColor}; + } + &:before { + content: ''; + position: absolute; + /* left: 10px; */ + top: 0; + width: 6px; + height: ${({ currentXp, highestXp }) => + currentXp || highestXp ? '18px' : '14px'}; + clip-path: polygon(100% 0, 100% 100%, 0% 100%, 50% 50%, 0% 0%); + transform: translateX(-100%); + background: ${({ activeColor }) => activeColor && activeColor}; + } + + &:first-of-type:before { + clip-path: none; + } + &:last-of-type:after { + clip-path: none; + } + + ${({ setupMode }) => + setupMode && + css` + cursor: pointer; + `} + + @media all and (min-width: 701px) { + } +`; +XpIcon.displayName = 'XPIcon'; diff --git a/src/interfaces/types.js b/src/interfaces/types.js index 02c75c6..6bc8257 100644 --- a/src/interfaces/types.js +++ b/src/interfaces/types.js @@ -37,3 +37,8 @@ export const BonusDiceType = shape({ melee: number.isRequired, ranged: number.isRequired }); + +export const HighestXpType = shape({ + name: string.isRequired, + xp: number.isRequired +});