Refactor selected items and add items

This commit is contained in:
Jeremie Pardou-Piquemal 2020-10-17 22:23:43 +02:00 committed by Jérémie Pardou-Piquemal
parent bdbba57b9f
commit f7bfee8018
11 changed files with 171 additions and 74 deletions

View file

@ -0,0 +1,88 @@
import React from "react";
import { useRecoilValue } from "recoil";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import AvailableItems from "./AvailableItems";
import NewItems from "./NewItems";
import { AvailableItemListAtom } from "./Board/";
const StyledButton = styled.div.attrs(() => ({
className: "button clear icon-only primary",
}))`
position: fixed;
bottom: 4px;
right: 4px;
`;
const AddItemPane = styled.div`
position: absolute;
right: 0.5em;
top: 7em;
bottom: 4em;
background-color: var(--bg-secondary-color);
width: 20%;
padding: 0.5em;
text-align: center;
overflow-y: scroll;
& .tabs a {
cursor: pointer;
}
`;
const AvailableItemList = styled.div`
margin-top: 2em;
background-color: black;
color: white;
list-type: none;
`;
const Title = styled.h3``;
const AddItemButton = () => {
const { t } = useTranslation();
const availableItemList = useRecoilValue(AvailableItemListAtom);
const [showAddPanel, setShowAddPanel] = React.useState(false);
const [tab, setTab] = React.useState("standard");
return (
<>
<StyledButton onClick={() => setShowAddPanel((prev) => !prev)}>
<img src="https://icongr.am/feather/plus-circle.svg?size=46&color=db5034" />
</StyledButton>
{showAddPanel && (
<AddItemPane>
<nav className="tabs">
<a
onClick={() => setTab("standard")}
className={tab === "standard" ? "active" : ""}
>
Standard
</a>
{availableItemList && availableItemList.length > 0 && (
<a
onClick={() => setTab("other")}
className={tab === "other" ? "active" : ""}
>
Other
</a>
)}
</nav>
<section className="content">
{tab === "standard" && <NewItems />}
{tab === "other" && (
<AvailableItemList>
<Title>{t("Box Content")}</Title>
<AvailableItems />
</AvailableItemList>
)}
</section>
</AddItemPane>
)}
</>
);
};
export default AddItemButton;

View file

@ -45,7 +45,6 @@ const AvailableItems = () => {
.filter((item) => item.groupId === groupId)
.map((item) => (
<li key={item.id}>
{item.id}
<AvailableItem data={item} />
</li>
))}

View file

@ -14,7 +14,7 @@ const LeftPane = styled.div`
left: 0.5em;
top: 4em;
bottom: 0.5em;
background-color: #ffffff10;
background-color: var(--bg-secondary-color);
width: 20%;
padding: 0.5em;
text-align: center;

View file

@ -21,38 +21,55 @@ import "react-confirm-alert/src/react-confirm-alert.css";
import { useTranslation } from "react-i18next";
const SelectedPane = styled.div.attrs(() => ({ className: "card" }))`
const SelectedPane = styled.div`
position: absolute;
right: 0.5em;
left: 0.5em;
bottom: 0.5em;
background-color: #ffffffe0;
padding: 0.5em;
max-height: 66%;
top: 4.5em;
background-color: transparent;
overflow-y: scroll;
transform: scaleX(-1);
& > div {
transform: scaleX(-1);
}
`;
const ActionPane = styled.div.attrs(({ top, left }) => ({
style: {
top: `${top - 50}px`,
top: `${top - 55}px`,
left: `${left}px`,
},
}))`
position: absolute;
display: flex;
background-color: transparent;
background-color: #333333ff;
justify-content: center;
//z-index: 1;
border-radius: 4px;
padding: 0.5em;
box-shadow: rgba(0, 0, 0, 0.15) 0px 3px 3px 0px;
& button{
margin 0 6px;
padding: 0.4em;
height: 40px
}
& .count{
color: var(--color-secondary);
display: flex;
flex-direction: column;
align-items: center;
line-height: 0.8em;
}
& .number{
font-size: 1.5em;
line-height: 1em;
}
`;
const CardContent = styled.div.attrs(() => ({ className: "content" }))`
display: flex;
flex-direction: column;
padding: 0.5em;
background-color: var(--bg-secondary-color);
`;
const BoundingBoxZone = styled.div.attrs(({ top, left, height, width }) => ({
@ -71,11 +88,12 @@ const BoundingBoxZone = styled.div.attrs(({ top, left, height, width }) => ({
pointer-events: none;
`;
export const SelectedItems = ({ edit }) => {
export const SelectedItems = () => {
const { updateItem } = useItems();
const { availableActions, actionMap } = useItemActions();
const [showAction, setShowAction] = React.useState(false);
const [showEdit, setShowEdit] = React.useState(false);
const { t } = useTranslation();
@ -100,6 +118,8 @@ export const SelectedItems = ({ edit }) => {
selectedItems.forEach((itemId) => {
const elem = document.getElementById(itemId);
if (!elem) return;
const {
right: x2,
bottom: y2,
@ -159,6 +179,7 @@ export const SelectedItems = ({ edit }) => {
React.useEffect(() => {
// Show on selection
showActionDelay(true);
setShowEdit(false);
}, [selectedItems, showActionDelay]);
React.useEffect(() => {
@ -173,7 +194,7 @@ export const SelectedItems = ({ edit }) => {
if (["INPUT", "TEXTAREA"].includes(e.target.tagName)) return;
Object.values(actionMap).forEach(
({ shortcut, action, edit: whileEdit }) => {
if (e.key === shortcut && edit === !!whileEdit) {
if (e.key === shortcut && showEdit === !!whileEdit) {
action();
}
}
@ -183,7 +204,7 @@ export const SelectedItems = ({ edit }) => {
return () => {
document.removeEventListener("keyup", onKeyUp);
};
}, [actionMap, edit]);
}, [actionMap, showEdit]);
const onSubmitHandler = React.useCallback(
(formValues) => {
@ -246,7 +267,7 @@ export const SelectedItems = ({ edit }) => {
});
};*/
const showEditPane = selectedItems.length === 1 && edit;
const showEditPane = selectedItems.length === 1 && showEdit;
return (
<>
@ -269,7 +290,12 @@ export const SelectedItems = ({ edit }) => {
)}
{showAction && (
<ActionPane {...boundingBoxLast}>
<h3>#{selectedItems.length}</h3>
{selectedItems.length > 1 && (
<div className="count">
<span className="number">{selectedItems.length}</span>
<span>Items</span>
</div>
)}
{availableActions.map((action) => {
const {
label,
@ -279,9 +305,14 @@ export const SelectedItems = ({ edit }) => {
icon,
} = actionMap[action];
if (multiple && selectedItems.length < 2) return null;
if (onlyEdit && !edit) return null;
if (onlyEdit && !showEdit) return null;
return (
<button key={action} onClick={handler} title={label}>
<button
className="icon-only"
key={action}
onClick={handler}
title={label}
>
<img
src={icon}
style={{ width: "25px", height: "24px" }}
@ -290,6 +321,17 @@ export const SelectedItems = ({ edit }) => {
</button>
);
})}
<button
className="icon-only"
onClick={() => setShowEdit((prev) => !prev)}
title="Edit"
>
<img
src="https://icongr.am/feather/edit.svg?size=25&color=000000"
alt="Edit"
/>
</button>
</ActionPane>
)}
{boundingBoxLast && <BoundingBoxZone {...boundingBoxLast} />}

View file

@ -319,7 +319,7 @@ export const useItemActions = () => {
remove: {
action: removeSelectedItems,
label: t("Remove all"),
shortcut: "r",
shortcut: "Delete",
edit: true,
disableDblclick: true,
icon: deleteIcon,

View file

@ -5,11 +5,12 @@ body {
:root {
--bg-color: #2a2a2aff;
--bg-secondary-color: #00a698ff;
--bg-secondary-color: #404040ff;
--font-color: #f9fbfaff;
--color-grey: #404040ff;
--color-darkGrey: #777;
--color-primary: #db5034ff;
--color-secondary: #00a698ff;
--color-lightGrey: #9a9a9aff;
--color-error: #d43939;
--color-success: #28bd14;

View file

@ -12,6 +12,7 @@ const StyledModal = styled.div`
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
border-radius: 5px;
.modal-content {
max-width: 50%;
position: relative;
@ -19,6 +20,8 @@ const StyledModal = styled.div`
padding: 8px 8px 8px 8px;
border-radius: 2px;
background: var(--bg-secondary-color);
box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px,
rgba(0, 0, 0, 0.23) 0px 6px 6px;
}
.close {
position: absolute;

View file

@ -8,7 +8,7 @@ const Overlay = styled.div`
height: 100vh;
top: 0;
left: 0;
background-color: hsla(227, 20%, 20%, 0.9);
background-color: var(--bg-color);
color: #606984;
display: flex;
justify-content: center;

View file

@ -2,21 +2,17 @@ import React from "react";
import styled from "styled-components";
import { SHOW_WELCOME } from "../utils/settings";
import BoardMenu from "../components/BoardMenu";
import BoardMenuEdit from "../components/BoardMenuEdit";
import GameController from "../components/GameController";
import { Board } from "../components/Board";
import SelectedItemsPane from "../components/SelectedItemsPane";
import { useUsers, SubscribeUserEvents, UserList } from "../components/users";
import LoadGameModal from "../components/LoadGameModal";
import HelpModal from "./HelpModal";
import WelcomeModal from "./WelcomeModal";
import InfoModal from "./InfoModal";
import NavBar from "./NavBar";
import AutoSave from "../components/AutoSave";
import ImageDropNPaste from "../components/ImageDropNPaste";
import { getComponent } from "../components/boardComponents";
import { useGame } from "../hooks/useGame";
import AddItemButton from "../components/AddItemButton";
const StyledBoardView = styled.div`
width: 100vw;
@ -29,55 +25,22 @@ const BoardContainer = styled.div`
height: 100%;
overflow: hidden;
box-sizing: border-box;
background-color: #202b38;
background-color: var(--bg-color);
`;
export const BoardView = ({ namespace, edit: editMode = false }) => {
const { currentUser, users } = useUsers();
const [showLoadGameModal, setShowLoadGameModal] = React.useState(false);
const [showHelpModal, setShowHelpModal] = React.useState(false);
const [showInfoModal, setShowInfoModal] = React.useState(false);
const [showWelcomeModal, setShowWelcomeModal] = React.useState(
SHOW_WELCOME && !editMode
);
const [menuOpen, setMenuOpen] = React.useState(false);
const [edit, setEdit] = React.useState(editMode);
const { gameLoaded } = useGame();
return (
<StyledBoardView>
<NavBar
setMenuOpen={setMenuOpen}
setShowHelpModal={setShowHelpModal}
setShowInfoModal={setShowInfoModal}
setEditMode={setEdit}
edit={edit}
/>
{!editMode && (
<BoardMenu
isOpen={menuOpen}
setMenuOpen={setMenuOpen}
setShowLoadGameModal={setShowLoadGameModal}
edit={edit}
/>
)}
{editMode && (
<BoardMenuEdit
isOpen={menuOpen}
setMenuOpen={setMenuOpen}
setShowLoadGameModal={setShowLoadGameModal}
edit={edit}
/>
)}
<HelpModal show={showHelpModal} setShow={setShowHelpModal} />
<InfoModal show={showInfoModal} setShow={setShowInfoModal} />
<NavBar setEditMode={setEdit} edit={edit} />
<WelcomeModal show={showWelcomeModal} setShow={setShowWelcomeModal} />
<LoadGameModal
showModal={showLoadGameModal}
setShowModal={setShowLoadGameModal}
/>
<SubscribeUserEvents />
<AutoSave />
{gameLoaded && (
@ -91,9 +54,9 @@ export const BoardView = ({ namespace, edit: editMode = false }) => {
/>
</ImageDropNPaste>
<SelectedItemsPane edit={edit} />
{edit && <GameController />}
</BoardContainer>
)}
<AddItemButton />
</StyledBoardView>
);
};

View file

@ -35,7 +35,7 @@ const GameList = styled.ul`
const Game = styled.li`
width: 100%;
background-color: hsl(210, 26%, 19%);
background-color: var(--bg-secondary-color);
color: hsl(210, 14%, 75%);
position: relative;
min-width: 300px;

View file

@ -3,23 +3,24 @@ import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { useC2C } from "../hooks/useC2C";
import styled from "styled-components";
import HelpModal from "../views/HelpModal";
import InfoModal from "../views/InfoModal";
import LoadSaveModal from "../views/LoadSaveModal";
import logo from "../images/logo.png";
const StyledNavBar = styled.div.attrs(() => ({ className: "nav" }))`
position: fixed;
top: 0;
width: 100%;
background-color: var(--color-grey);
background-color: var(--bg-secondary-color);
z-index: 10;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
`;
const NavBar = ({}) => {
const NavBar = () => {
const { t } = useTranslation();
const [showLoadGameModal, setShowLoadGameModal] = React.useState(false);
@ -31,32 +32,32 @@ const NavBar = ({}) => {
<StyledNavBar>
<div className="nav-left">
<Link to="/games/" className="brand">
<span>{t("Home")}</span>
<img src={logo} />
</Link>
<a
className="button outline"
className="button clear icon-only"
onClick={() => setShowLoadGameModal((prev) => !prev)}
>
{t("Load/Save")}
<img src="https://icongr.am/feather/save.svg?size=50&color=ffffff" />
</a>
</div>
<div className="nav-center">
<h3>Air Board Game</h3>
<a
className="button outline"
className="button clear icon-only"
onClick={() => setShowInfoModal((prev) => !prev)}
>
{t("Info")}
<img src="https://icongr.am/feather/info.svg?size=50&color=ffffff" />
</a>
</div>
<div className="nav-right">
<a
className="button outline"
className="button clear icon-only"
onClick={() => setShowHelpModal((prev) => !prev)}
>
{t("Help")}
<img src="https://icongr.am/feather/help-circle.svg?size=50&color=ffffff" />
</a>
</div>