Replace Modal by Side panel
This commit is contained in:
parent
f5be632cb5
commit
a28d2d8e4e
9 changed files with 203 additions and 224 deletions
|
@ -72,7 +72,12 @@ const Account = ({ disabled, ...props }) => {
|
|||
)}
|
||||
</div>
|
||||
{loginInProgress && <Waiter message={t("In progress...")} />}
|
||||
<Modal show={showLogin} setShow={setShowLogin} title={t("Login")}>
|
||||
<Modal
|
||||
show={showLogin}
|
||||
setShow={setShowLogin}
|
||||
title={t("Login")}
|
||||
width="33%"
|
||||
>
|
||||
{!emailSent && (
|
||||
<>
|
||||
<input
|
||||
|
@ -88,7 +93,7 @@ const Account = ({ disabled, ...props }) => {
|
|||
marginTop: "2em",
|
||||
}}
|
||||
>
|
||||
<button onClick={handleSubmit} className="button primary">
|
||||
<button onClick={handleSubmit} className="button success">
|
||||
{t("Ask authentication link")}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -107,7 +112,7 @@ const Account = ({ disabled, ...props }) => {
|
|||
}}
|
||||
>
|
||||
<button
|
||||
className="button primary"
|
||||
className="button success"
|
||||
onClick={() => setShowLogin(false)}
|
||||
>
|
||||
Ok
|
||||
|
|
|
@ -40,6 +40,7 @@ const AddItemButton = () => {
|
|||
setShowAddPanel(false);
|
||||
}}
|
||||
position="right"
|
||||
width="33%"
|
||||
>
|
||||
<nav className="tabs">
|
||||
{
|
||||
|
@ -47,6 +48,7 @@ const AddItemButton = () => {
|
|||
<a
|
||||
onClick={() => setTab("standard")}
|
||||
className={tab === "standard" ? "active" : ""}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
{t("Standard")}
|
||||
</a>
|
||||
|
@ -56,6 +58,7 @@ const AddItemButton = () => {
|
|||
<a
|
||||
onClick={() => setTab("other")}
|
||||
className={tab === "other" ? "active" : ""}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
{t("Other")}
|
||||
</a>
|
||||
|
|
|
@ -58,11 +58,6 @@ const Message = ({
|
|||
);
|
||||
};
|
||||
|
||||
const StyledMessageList = styled.div`
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const computeMessageGroup = (messages, userMap, maxTimeDiff = 30000) => {
|
||||
if (!messages || messages.length === 0) return [];
|
||||
|
||||
|
@ -105,6 +100,11 @@ const computeMessageGroup = (messages, userMap, maxTimeDiff = 30000) => {
|
|||
return messageGroups;
|
||||
};
|
||||
|
||||
const StyledMessageList = styled.div`
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const MessageList = ({ messages }) => {
|
||||
const messageList = React.useRef(null);
|
||||
const { users } = useUsers();
|
||||
|
@ -216,9 +216,10 @@ const MessageButton = () => {
|
|||
}}
|
||||
position="left"
|
||||
noMargin
|
||||
title={t("Chat")}
|
||||
width="25%"
|
||||
>
|
||||
<StyledChat>
|
||||
<h3>{t("Chat")}</h3>
|
||||
<MessageList messages={messages} />
|
||||
<Composer sendMessage={sendMessage} />
|
||||
</StyledChat>
|
||||
|
|
|
@ -286,26 +286,31 @@ export const SelectedItemsPane = ({ hideMenu = false }) => {
|
|||
});
|
||||
};*/
|
||||
|
||||
let title = "";
|
||||
if (selectedItems.length === 1) {
|
||||
title = t("Edit item");
|
||||
}
|
||||
if (selectedItems.length > 1) {
|
||||
title = t("Edit all items");
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showEdit && !boardState.selecting && (
|
||||
<SidePanel
|
||||
key={selectedItems[0]}
|
||||
onClose={() => {
|
||||
setShowEdit(false);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<header>
|
||||
{selectedItems.length === 1 && <h3>{t("Edit item")}</h3>}
|
||||
{selectedItems.length > 1 && <h3>{t("Edit all items")}</h3>}
|
||||
</header>
|
||||
<CardContent>
|
||||
<ItemFormFactory />
|
||||
</CardContent>
|
||||
</div>
|
||||
</SidePanel>
|
||||
)}
|
||||
<SidePanel
|
||||
key={selectedItems[0]}
|
||||
open={showEdit && !boardState.selecting}
|
||||
onClose={() => {
|
||||
setShowEdit(false);
|
||||
}}
|
||||
title={title}
|
||||
width="25%"
|
||||
>
|
||||
<div>
|
||||
<CardContent>
|
||||
<ItemFormFactory />
|
||||
</CardContent>
|
||||
</div>
|
||||
</SidePanel>
|
||||
{selectedItems.length && !hideMenu && (
|
||||
<ActionPane
|
||||
{...boundingBoxLast}
|
||||
|
|
110
src/ui/Modal.jsx
110
src/ui/Modal.jsx
|
@ -1,107 +1,15 @@
|
|||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styled from "styled-components";
|
||||
|
||||
import { hasClass } from "../utils";
|
||||
|
||||
const StyledModal = styled.div.attrs(() => ({ className: "overlay" }))`
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 5px;
|
||||
|
||||
.modal-content {
|
||||
max-width: 500px;
|
||||
min-height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
padding: 8px 8px 8px 8px;
|
||||
padding: 2em;
|
||||
border-radius: 2px;
|
||||
|
||||
background-color: var(--color-darkGrey);
|
||||
box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px,
|
||||
rgba(0, 0, 0, 0.23) 0px 6px 6px;
|
||||
}
|
||||
& .title {
|
||||
font-weight: 700;
|
||||
}
|
||||
& .content {
|
||||
& header {
|
||||
padding: 0.5em;
|
||||
margin-top: 2em;
|
||||
background-color: var(--color-blueGrey);
|
||||
border-radius: 0.5em 0.5em 0em 0em;
|
||||
& h3 {
|
||||
margin: 0.2em 0.2em 0.2em;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
& section {
|
||||
border-radius: 0em 0em 0.5em 0.5em;
|
||||
padding: 2em;
|
||||
background-color: var(--color-darkBlueGrey);
|
||||
}
|
||||
}
|
||||
& .close {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
& footer {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
& .modal-content {
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const Modal = ({ setShow, show, children, footer, title }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
import SidePanel from "./SidePanel";
|
||||
|
||||
export const Modal = ({ setShow, show, ...rest }) => {
|
||||
return (
|
||||
<StyledModal
|
||||
onClick={(e) => {
|
||||
if (hasClass(e.target, "overlay")) setShow(false);
|
||||
}}
|
||||
>
|
||||
<div className="modal-content">
|
||||
<article>
|
||||
<header>
|
||||
<h2 className="title">{title}</h2>
|
||||
<button
|
||||
className="button clear icon-only close"
|
||||
onClick={() => {
|
||||
setShow(false);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="https://icongr.am/feather/x.svg?size=42&color=ffffff"
|
||||
alt={t("Close")}
|
||||
/>
|
||||
</button>
|
||||
</header>
|
||||
<div className="content">{children}</div>
|
||||
<footer>{footer}</footer>
|
||||
</article>
|
||||
</div>
|
||||
</StyledModal>
|
||||
<SidePanel
|
||||
open={show}
|
||||
onClose={() => setShow(false)}
|
||||
position="right"
|
||||
modal
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -3,27 +3,40 @@ import styled from "styled-components";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import usePortal from "react-useportal";
|
||||
|
||||
const Overlay = styled.div`
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
`;
|
||||
|
||||
const StyledSidePanel = styled.div`
|
||||
position: fixed;
|
||||
${({ position }) => (position === "right" ? "right: 0;" : "left: 0;")}
|
||||
top: 0;
|
||||
bottom: 0em;
|
||||
bottom: 0;
|
||||
z-index: 22;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
background-color: var(--color-blueGrey);
|
||||
background-color: ${({ modal }) =>
|
||||
modal ? "var(--color-darkGrey)" : "var(--color-blueGrey)"};
|
||||
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
width: 25%;
|
||||
|
||||
min-width: 280px;
|
||||
max-width: 500px;
|
||||
${({ width }) => (width ? `width: ${width};` : "")}
|
||||
|
||||
overflow-y: auto;
|
||||
& .close {
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
transform: translateX(100%);
|
||||
transition: all 500ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
${({ noMargin }) => (noMargin ? "" : "padding: 1em")};
|
||||
|
||||
${({ open, position }) => {
|
||||
let start = -100;
|
||||
|
@ -37,6 +50,43 @@ const StyledSidePanel = styled.div`
|
|||
}}
|
||||
|
||||
${({ open }) => (open ? "opacity: 1;" : "opacity: 0.2;")}
|
||||
|
||||
& .close {
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
& .title {
|
||||
font-weight: 700;
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
& > .content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
${({ noMargin }) => (noMargin ? "" : "padding: 1em")};
|
||||
& header {
|
||||
padding: 0.5em;
|
||||
margin-top: 2em;
|
||||
background-color: var(--color-blueGrey);
|
||||
border-radius: 0.5em 0.5em 0em 0em;
|
||||
& h3 {
|
||||
margin: 0.2em 0.2em 0.2em;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
& section {
|
||||
border-radius: 0em 0em 0.5em 0.5em;
|
||||
padding: 2em;
|
||||
background-color: var(--color-darkBlueGrey);
|
||||
}
|
||||
}
|
||||
|
||||
& footer {
|
||||
margin-top: 1em;
|
||||
}
|
||||
`;
|
||||
|
||||
const SidePanel = ({
|
||||
|
@ -44,11 +94,15 @@ const SidePanel = ({
|
|||
position,
|
||||
noMargin,
|
||||
onClose = () => {},
|
||||
title,
|
||||
footer,
|
||||
open,
|
||||
modal = false,
|
||||
width,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { ref, Portal, openPortal, closePortal, isOpen } = usePortal({
|
||||
closeOnOutsideClick: false,
|
||||
closeOnOutsideClick: modal,
|
||||
});
|
||||
|
||||
const onAnimationEnd = React.useCallback(() => {
|
||||
|
@ -68,23 +122,30 @@ const SidePanel = ({
|
|||
return (
|
||||
<>
|
||||
<Portal>
|
||||
{modal && isOpen && <Overlay onClick={closePortal} />}
|
||||
<StyledSidePanel
|
||||
position={position}
|
||||
open={isOpen}
|
||||
onTransitionEnd={onAnimationEnd}
|
||||
noMargin={noMargin}
|
||||
ref={ref}
|
||||
width={width}
|
||||
modal={modal}
|
||||
>
|
||||
<button
|
||||
className="button clear icon-only close"
|
||||
onClick={closePortal}
|
||||
>
|
||||
<img
|
||||
src="https://icongr.am/feather/x.svg?size=42&color=ffffff"
|
||||
alt={t("Close")}
|
||||
/>
|
||||
</button>
|
||||
{children}
|
||||
<header>
|
||||
{title && <h2 className="title">{title}</h2>}
|
||||
<button
|
||||
className="button clear icon-only close"
|
||||
onClick={closePortal}
|
||||
>
|
||||
<img
|
||||
src="https://icongr.am/feather/x.svg?size=42&color=ffffff"
|
||||
alt={t("Close")}
|
||||
/>
|
||||
</button>
|
||||
</header>
|
||||
<div className="content">{children}</div>
|
||||
{footer && <footer>{footer}</footer>}
|
||||
</StyledSidePanel>
|
||||
</Portal>
|
||||
</>
|
||||
|
|
|
@ -10,11 +10,9 @@ const InfoModal = ({ show, setShow }) => {
|
|||
|
||||
return (
|
||||
<Modal title={t("Edit game information")} setShow={setShow} show={show}>
|
||||
<>
|
||||
<section>
|
||||
<BoardConfig />
|
||||
</section>
|
||||
</>
|
||||
<section>
|
||||
<BoardConfig />
|
||||
</section>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -53,78 +53,76 @@ const InfoModal = ({ show, setShow }) => {
|
|||
|
||||
return (
|
||||
<Modal title={t("Help & info")} setShow={setShow} show={show}>
|
||||
<>
|
||||
<header>
|
||||
<h3>{t("Game information")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
{translation.description && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: info,
|
||||
}}
|
||||
></div>
|
||||
)}
|
||||
{!translation.description && <div>{t("No information")}</div>}
|
||||
</section>
|
||||
<header>
|
||||
<h3>{t("Board interactions")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
<Trans i18nKey="helpBoard">
|
||||
<ul>
|
||||
<li>
|
||||
Move the board with middle mouse button click. Alternatively you
|
||||
can use left button with alt key.
|
||||
</li>
|
||||
<li>Zoom with mouse wheel.</li>
|
||||
<li>
|
||||
Switch to edit mode with top button to be able to edit the game.
|
||||
</li>
|
||||
<li>You can save and reload game by clicking the burger menu.</li>
|
||||
</ul>
|
||||
</Trans>{" "}
|
||||
</section>
|
||||
<header>
|
||||
<h3>{t("Item interactions")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
<Trans i18nKey="helpItem">
|
||||
<ul>
|
||||
<li>Double click on any item that can be flipped to flip it.</li>
|
||||
<li>
|
||||
<Kbd>t</Kbd> key to tap/untap selected items.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>f</Kbd> key to flip/unflip selected items.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>o</Kbd> key to reveal front side of selected flipped items
|
||||
ONLY ONLY to you.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>l</Kbd> key to be able to selected previously locked item.
|
||||
</li>
|
||||
</ul>
|
||||
</Trans>
|
||||
</section>
|
||||
<header>
|
||||
<h3>{t("Game information")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
{translation.description && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: info,
|
||||
}}
|
||||
></div>
|
||||
)}
|
||||
{!translation.description && <div>{t("No information")}</div>}
|
||||
</section>
|
||||
<header>
|
||||
<h3>{t("Board interactions")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
<Trans i18nKey="helpBoard">
|
||||
<ul>
|
||||
<li>
|
||||
Move the board with middle mouse button click. Alternatively you
|
||||
can use left button with alt key.
|
||||
</li>
|
||||
<li>Zoom with mouse wheel.</li>
|
||||
<li>
|
||||
Switch to edit mode with top button to be able to edit the game.
|
||||
</li>
|
||||
<li>You can save and reload game by clicking the burger menu.</li>
|
||||
</ul>
|
||||
</Trans>
|
||||
</section>
|
||||
<header>
|
||||
<h3>{t("Item interactions")}</h3>
|
||||
</header>
|
||||
<section>
|
||||
<Trans i18nKey="helpItem">
|
||||
<ul>
|
||||
<li>Double click on any item that can be flipped to flip it.</li>
|
||||
<li>
|
||||
<Kbd>t</Kbd> key to tap/untap selected items.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>f</Kbd> key to flip/unflip selected items.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>o</Kbd> key to reveal front side of selected flipped items
|
||||
ONLY ONLY to you.
|
||||
</li>
|
||||
<li>
|
||||
<Kbd>l</Kbd> key to be able to selected previously locked item.
|
||||
</li>
|
||||
</ul>
|
||||
</Trans>
|
||||
</section>
|
||||
|
||||
<header>
|
||||
<h3>{t("More information")}</h3>
|
||||
</header>
|
||||
<header>
|
||||
<h3>{t("More information")}</h3>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
<Trans i18nKey="moreInformation">
|
||||
<p>
|
||||
For more information, visit{" "}
|
||||
<a href="https://github.com/jrmi/airboardgame/">
|
||||
github repository
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Trans>
|
||||
</section>
|
||||
</>
|
||||
<section>
|
||||
<Trans i18nKey="moreInformation">
|
||||
<p>
|
||||
For more information, visit{" "}
|
||||
<a href="https://github.com/jrmi/airboardgame/">
|
||||
github repository
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Trans>
|
||||
</section>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import Modal from "../ui/Modal";
|
|||
|
||||
const LoadSessionModal = ({ show, setShow }) => {
|
||||
const { t } = useTranslation();
|
||||
const {c2c} = useC2C();
|
||||
const { c2c } = useC2C();
|
||||
|
||||
const loadGame = React.useCallback(
|
||||
(game) => {
|
||||
|
|
Loading…
Reference in a new issue