Change Modal layout

fix configure store error
add css transition effects
This commit is contained in:
HF 2020-05-11 09:13:34 +02:00
parent 0ed5193982
commit 0b3afeb6e0
24 changed files with 524 additions and 378 deletions

View File

@ -623,8 +623,8 @@ export function showCanvasSelectionModal(): Action {
return showModal('CANVAS_SELECTION'); return showModal('CANVAS_SELECTION');
} }
export function showChatModal(): Action { export function showChatModal(forceModal: boolean = false): Action {
if (window.innerWidth > 604) { return toggleChatBox(); } if (window.innerWidth > 604 && !forceModal) { return toggleChatBox(); }
return showModal('CHAT'); return showModal('CHAT');
} }

View File

@ -5,37 +5,31 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// import FaFacebook from 'react-icons/lib/fa/facebook';
// import FaTwitter from 'react-icons/lib/fa/twitter';
// import FaRedditAlien from 'react-icons/lib/fa/reddit-alien';
import Modal from './Modal';
import CanvasItem from './CanvasItem'; import CanvasItem from './CanvasItem';
import type { State } from '../reducers'; import type { State } from '../reducers';
const CanvasSelectModal = ({ canvases }) => ( const CanvasSelectModal = ({ canvases }) => (
<Modal title="Canvas Selection"> <p style={{
<p style={{ textAlign: 'center',
textAlign: 'center', paddingLeft: '5%',
paddingLeft: '5%', paddingRight: '5%',
paddingRight: '5%', paddingTop: 20,
paddingTop: 20, }}
}} >
> <p className="modaltext">
<p className="modaltext"> Select the canvas you want to use.
Select the canvas you want to use. Every canvas is unique and has different palettes,
Every canvas is unique and has different palettes, cooldown and requirements.
cooldown and requirements.
</p>
{
Object.keys(canvases).map((canvasId) => (
<CanvasItem canvasId={canvasId} canvas={canvases[canvasId]} />
))
}
</p> </p>
</Modal> {
Object.keys(canvases).map((canvasId) => (
<CanvasItem canvasId={canvasId} canvas={canvases[canvasId]} />
))
}
</p>
); );
function mapStateToProps(state: State) { function mapStateToProps(state: State) {
@ -43,4 +37,9 @@ function mapStateToProps(state: State) {
return { canvases }; return { canvases };
} }
export default connect(mapStateToProps)(CanvasSelectModal); const data = {
content: connect(mapStateToProps)(CanvasSelectModal),
title: 'Canvas Selection',
};
export default data;

View File

@ -25,8 +25,8 @@ const Chat = ({ chatMessages, chatChannel }) => {
}, [channelMessages.length]); }, [channelMessages.length]);
return ( return (
<div style={{ height: '100%' }}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<ul className="chatarea" ref={listRef}> <ul className="chatarea" ref={listRef} style={{ flexGrow: 1 }}>
{ {
channelMessages.map((message) => ( channelMessages.map((message) => (
<p className="chatmsg"> <p className="chatmsg">

View File

@ -3,24 +3,66 @@
* @flow * @flow
*/ */
import React from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import type { State } from '../reducers'; import type { State } from '../reducers';
import useWindowSize from '../utils/reactHookResize';
import { showChatModal } from '../actions';
import Chat from './Chat'; import Chat from './Chat';
const ChatBox = ({ chatOpen }) => ( function ChatBox({
<div className={(chatOpen) ? "chatbox show" : "chatbox"}> chatOpen,
<Chat /> triggerModal,
</div> }) {
); const [render, setRender] = useState(false);
useEffect(() => {
window.setTimeout(() => {
if (chatOpen) setRender(true);
}, 10);
}, [chatOpen]);
const onTransitionEnd = () => {
if (!chatOpen) setRender(false);
};
const { width } = useWindowSize();
if (width < 604) {
triggerModal();
}
return (
(render || chatOpen) && (
<div
className={(chatOpen && render) ? 'chatbox show' : 'chatbox'}
onTransitionEnd={onTransitionEnd}
>
<div
id="chatlink"
onClick={triggerModal}
role="button"
tabIndex={-1}
></div>
<Chat />
</div>
)
);
}
// TODO optimize
function mapStateToProps(state: State) { function mapStateToProps(state: State) {
const { chatOpen } = state.modal; const { chatOpen } = state.modal;
return { chatOpen }; return { chatOpen };
} }
export default connect(mapStateToProps)(ChatBox); function mapDispatchToProps(dispatch) {
return {
triggerModal() {
dispatch(showChatModal(true));
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ChatBox);

View File

@ -25,7 +25,7 @@ const ChatButton = ({ open }) => (
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
return { return {
open() { open() {
dispatch(showChatModal()); dispatch(showChatModal(false));
}, },
}; };
} }

View File

@ -49,33 +49,33 @@ class ChatInput extends React.Component {
<div className="chatinput"> <div className="chatinput">
<form <form
onSubmit={(e) => { this.handleSubmit(e, chatChannel); }} onSubmit={(e) => { this.handleSubmit(e, chatChannel); }}
style={{ display: 'inline' }} style={{ display: 'flex', flexDirection: 'row' }}
> >
<input <input
style={{ maxWidth: '58%', width: '240px' }} style={{ flexGrow: 1, minWidth: 40 }}
value={message} value={message}
onChange={(evt) => this.setState({ message: evt.target.value })} onChange={(evt) => this.setState({ message: evt.target.value })}
type="text" type="text"
placeholder="Chat here" placeholder="Chat here"
/> />
<button <button
style={{ flexGrow: 0 }}
id="chatmsginput" id="chatmsginput"
type="submit" type="submit"
style={{ height: 22 }}
> >
</button> </button>
<select
style={{ flexGrow: 0 }}
onChange={(evt) => setChannel(evt.target.selectedIndex)}
>
{
CHAT_CHANNELS.map((ch) => (
<option selected={ch === selectedChannel}>{ch}</option>
))
}
</select>
</form> </form>
<select
onChange={(evt) => setChannel(evt.target.selectedIndex)}
style={{ height: 22 }}
>
{
CHAT_CHANNELS.map((ch) => (
<option selected={ch === selectedChannel}>{ch}</option>
))
}
</select>
</div> </div>
); );
} }

View File

@ -5,19 +5,40 @@
import React from 'react'; import React from 'react';
import Modal from './Modal';
import Chat from './Chat'; import Chat from './Chat';
const ChatModal = () => ( const ChatModal = () => (
<Modal title="Chat"> <div style={{
position: 'fixed',
top: 80,
padding: 10,
bottom: 10,
left: 10,
right: 10,
}}
>
<p style={{ textAlign: 'center' }}> <p style={{ textAlign: 'center' }}>
<p className="modaltext">Chat with other people here</p> <p className="modaltext">Chat with other people here</p>
</p> </p>
<div className="inarea" style={{ height: '65%' }}> <div
className="inarea"
style={{
position: 'absolute',
bottom: 10,
top: 50,
left: 10,
right: 10,
}}
>
<Chat /> <Chat />
</div> </div>
</Modal> </div>
); );
export default ChatModal; const data = {
content: ChatModal,
title: 'Chat',
};
export default data;

View File

@ -19,8 +19,7 @@ function renderCoordinates(cell): string {
const CoordinatesBox = ({ view, hover, notifyCopy }) => ( const CoordinatesBox = ({ view, hover, notifyCopy }) => (
<div <div
className="coorbox" className="coorbox"
// eslint-disable-next-line no-restricted-globals onClick={() => { copy(window.location.hash); notifyCopy(); }}
onClick={() => { copy(location.hash); notifyCopy(); }}
role="button" role="button"
title="Copy to Clipboard" title="Copy to Clipboard"
tabIndex="0" tabIndex="0"

View File

@ -6,24 +6,20 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Modal from './Modal';
import { showUserAreaModal } from '../actions'; import { showUserAreaModal } from '../actions';
import NewPasswordForm from './NewPasswordForm'; import NewPasswordForm from './NewPasswordForm';
const ForgotPasswordModal = ({ login }) => ( const ForgotPasswordModal = ({ login }) => (
<Modal title="Restore my Password"> <p style={{ paddingLeft: '5%', paddingRight: '5%' }}>
<p style={{ paddingLeft: '5%', paddingRight: '5%' }}> <p className="modaltext">
<p className="modaltext"> Enter your mail adress and we will send you a new password:
Enter your mail adress and we will send you a new password: </p><br />
</p><br /> <p style={{ textAlign: 'center' }}>
<p style={{ textAlign: 'center' }}> <NewPasswordForm back={login} />
<NewPasswordForm back={login} /> <p>Also join our Discord:&nbsp;
<p>Also join our Discord:&nbsp; <a href="./discord" target="_blank">pixelplanet.fun/discord</a></p>
<a href="./discord" target="_blank">pixelplanet.fun/discord</a></p>
</p>
</p> </p>
</Modal> </p>
); );
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
@ -34,5 +30,9 @@ function mapDispatchToProps(dispatch) {
}; };
} }
const data = {
content: connect(null, mapDispatchToProps)(ForgotPasswordModal),
title: 'Restore my Password',
};
export default connect(null, mapDispatchToProps)(ForgotPasswordModal); export default data;

View File

@ -10,59 +10,60 @@ import React from 'react';
/* eslint-disable max-len */ /* eslint-disable max-len */
import Modal from './Modal';
const HelpModal = () => ( const HelpModal = () => (
<Modal title="Welcome to PixelPlanet.fun"> <p style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}>
<p style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}> <p className="modaltext">Place color pixels on a large canvas with other players online!
<p className="modaltext">Place color pixels on a large canvas with other players online! Our main canvas is a huge worldmap, you can place wherever you like, but you will have to wait a specific
Our main canvas is a huge worldmap, you can place wherever you like, but you will have to wait a specific Cooldown between pixels. You can check out the cooldown and requiremnts on the Canvas Selection menu (globe button on top).
Cooldown between pixels. You can check out the cooldown and requiremnts on the Canvas Selection menu (globe button on top). Some canvases have a different cooldown for replacing a user-set pixels than placing on a unset pixel. i.e. 4s/7s means 4s on fresh
Some canvases have a different cooldown for replacing a user-set pixels than placing on a unset pixel. i.e. 4s/7s means 4s on fresh pixels and 7s on already set pixels.
pixels and 7s on already set pixels. Higher zoomlevels take some time to update, the 3D globe gets updated at least once per day.
Higher zoomlevels take some time to update, the 3D globe gets updated at least once per day. Have fun!</p>
Have fun!</p> <p>Discord: <a href="./discord" target="_blank" rel="noopener noreferrer">pixelplanet.fun/discord</a></p>
<p>Discord: <a href="./discord" target="_blank" rel="noopener noreferrer">pixelplanet.fun/discord</a></p> <p>Source on <a href="https://github.com/pixelplanetdev/pixelplanet" target="_blank" rel="noopener noreferrer">github</a></p>
<p>Source on <a href="https://github.com/pixelplanetdev/pixelplanet" target="_blank" rel="noopener noreferrer">github</a></p> <p>Reddit: <a href="https://www.reddit.com/r/PixelPlanetFun/" target="_blank" rel="noopener noreferrer">r/PixelPlanetFun</a></p>
<p>Reddit: <a href="https://www.reddit.com/r/PixelPlanetFun/" target="_blank" rel="noopener noreferrer">r/PixelPlanetFun</a></p> <p className="modaltitle">Map Data</p>
<p className="modaltitle">Map Data</p> <p className="modaltext">The bare map data that we use, together with converted OpenStreetMap tiles for orientation,
<p className="modaltext">The bare map data that we use, together with converted OpenStreetMap tiles for orientation, can be downloaded from mega.nz here: <a href="https://mega.nz/#!JpkBwAbJ!EnSLlZmKv3kEBE0HDhakTgAZZycD3ELjduajJxPGaXo">pixelplanetmap.zip</a> (422MB)</p>
can be downloaded from mega.nz here: <a href="https://mega.nz/#!JpkBwAbJ!EnSLlZmKv3kEBE0HDhakTgAZZycD3ELjduajJxPGaXo">pixelplanetmap.zip</a> (422MB)</p> <p className="modaltitle">Detected as Proxy?</p>
<p className="modaltitle">Detected as Proxy?</p> <p className="modaltext">If you got detected as proxy, but you are none, please send us an e-mail with <a href="https://www.whatismyip.com/">your IP</a> to <a href="mailto:pixelplanetdev@gmail.com">pixelplanetdev@gmail.com</a>. Do not post your IP anywhere else. We are sorry for the inconvenience.</p>
<p className="modaltext">If you got detected as proxy, but you are none, please send us an e-mail with <a href="https://www.whatismyip.com/">your IP</a> to <a href="mailto:pixelplanetdev@gmail.com">pixelplanetdev@gmail.com</a>. Do not post your IP anywhere else. We are sorry for the inconvenience.</p> <h3 className="modaltitle">2D Controls</h3>
<h3 className="modaltitle">2D Controls</h3> <p className="modaltext">Click a color in palette to select</p>
<p className="modaltext">Click a color in palette to select</p> <p className="modaltext">Press <kbd>G</kbd> to toggle grid</p>
<p className="modaltext">Press <kbd>G</kbd> to toggle grid</p> <p className="modaltext">Press <kbd>X</kbd> to toggle showing of pixel activity</p>
<p className="modaltext">Press <kbd>X</kbd> to toggle showing of pixel activity</p> <p className="modaltext">Press <kbd>R</kbd> to copy coordinates</p>
<p className="modaltext">Press <kbd>R</kbd> to copy coordinates</p> <p className="modaltext">Press <kbd>Q</kbd> or <kbd>E</kbd> to zoom</p>
<p className="modaltext">Press <kbd>Q</kbd> or <kbd>E</kbd> to zoom</p> <p className="modaltext">Press <kbd>W</kbd>,<kbd>A</kbd>,<kbd>S</kbd>, <kbd>D</kbd> to move</p>
<p className="modaltext">Press <kbd>W</kbd>,<kbd>A</kbd>,<kbd>S</kbd>, <kbd>D</kbd> to move</p> <p className="modaltext">Press <kbd></kbd>,<kbd></kbd>,<kbd></kbd>, <kbd></kbd> to move</p>
<p className="modaltext">Press <kbd></kbd>,<kbd></kbd>,<kbd></kbd>, <kbd></kbd> to move</p> <p className="modaltext">Drag mouse to move</p>
<p className="modaltext">Drag mouse to move</p> <p className="modaltext">Scroll mouse wheel to zoom</p>
<p className="modaltext">Scroll mouse wheel to zoom</p> <p className="modaltext">Click middle mouse button to current hovering color</p>
<p className="modaltext">Click middle mouse button to current hovering color</p> <p className="modaltext">Pinch to zoom (on touch devices)</p>
<p className="modaltext">Pinch to zoom (on touch devices)</p> <p className="modaltext">Pan to move (on touch devices)</p>
<p className="modaltext">Pan to move (on touch devices)</p> <p className="modaltext">Click or tap to place a pixel</p>
<p className="modaltext">Click or tap to place a pixel</p> <h3 className="modaltitle">3D Controls</h3>
<h3 className="modaltitle">3D Controls</h3> <p className="modaltext">Press <kbd>W</kbd>,<kbd>A</kbd>,<kbd>S</kbd>, <kbd>D</kbd> to move</p>
<p className="modaltext">Press <kbd>W</kbd>,<kbd>A</kbd>,<kbd>S</kbd>, <kbd>D</kbd> to move</p> <p className="modaltext">Press <kbd></kbd>,<kbd></kbd>,<kbd></kbd>, <kbd></kbd> to move</p>
<p className="modaltext">Press <kbd></kbd>,<kbd></kbd>,<kbd></kbd>, <kbd></kbd> to move</p> <p className="modaltext">Scroll mouse wheel to zoom</p>
<p className="modaltext">Scroll mouse wheel to zoom</p> <p className="modaltext">Left click and drag mouse to rotate</p>
<p className="modaltext">Left click and drag mouse to rotate</p> <p className="modaltext">Middle click and drag mouse to zoom</p>
<p className="modaltext">Middle click and drag mouse to zoom</p> <p className="modaltext">Right click and drag mouse to pan</p>
<p className="modaltext">Right click and drag mouse to pan</p> <p className="modaltext">Left Click or tap to place a pixel</p>
<p className="modaltext">Left Click or tap to place a pixel</p> <p className="modaltext">Right Click of double tap to remove a pixel</p>
<p className="modaltext">Right Click of double tap to remove a pixel</p> <p>Partners: <a href="https://www.crazygames.com/c/io" target="_blank" rel="noopener noreferrer">crazygames.com</a></p>
<p>Partners: <a href="https://www.crazygames.com/c/io" target="_blank" rel="noopener noreferrer">crazygames.com</a></p> <p className="modaltext">
<p className="modaltext"> <small>This site is protected by reCAPTCHA and the Google
<small>This site is protected by reCAPTCHA and the Google <a href="https://policies.google.com/privacy">Privacy Policy</a> and
<a href="https://policies.google.com/privacy">Privacy Policy</a> and <a href="https://policies.google.com/terms">Terms of Service</a> apply.
<a href="https://policies.google.com/terms">Terms of Service</a> apply. </small>
</small>
</p>
</p> </p>
</Modal> </p>
); );
export default HelpModal; const data = {
content: HelpModal,
title: 'Welcome to PixelPlanet.fun',
};
export default data;

View File

@ -4,7 +4,7 @@
* @flow * @flow
*/ */
import React from 'react'; import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import HelpButton from './HelpButton'; import HelpButton from './HelpButton';
@ -13,15 +13,36 @@ import LogInButton from './LogInButton';
import DownloadButton from './DownloadButton'; import DownloadButton from './DownloadButton';
import MinecraftButton from './MinecraftButton'; import MinecraftButton from './MinecraftButton';
const Menu = ({ menuOpen }) => ( function Menu({
<div className={menuOpen ? 'menu show' : 'menu'}> menuOpen,
<SettingsButton /> }) {
<LogInButton /> const [render, setRender] = useState(false);
<DownloadButton />
<MinecraftButton /> useEffect(() => {
<HelpButton /> window.setTimeout(() => {
</div> if (menuOpen) setRender(true);
); }, 10);
}, [menuOpen]);
const onTransitionEnd = () => {
if (!menuOpen) setRender(false);
};
return (
(render || menuOpen) && (
<div
className={menuOpen ? 'menu show' : 'menu'}
onTransitionEnd={onTransitionEnd}
>
<SettingsButton />
<LogInButton />
<DownloadButton />
<MinecraftButton />
<HelpButton />
</div>
)
);
}
function mapStateToProps(state: State) { function mapStateToProps(state: State) {
const { menuOpen } = state.gui; const { menuOpen } = state.gui;

View File

@ -6,17 +6,13 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Modal from './Modal';
const MinecraftModal = () => ( const MinecraftModal = () => (
<Modal title="PixelPlanet Minecraft Server"> <p style={{ textAlign: 'center' }}>
<p style={{ textAlign: 'center' }}> <p>You can also place pixels from our Minecraft Server at</p>
<p>You can also place pixels from our Minecraft Server at</p> <p><input type="text" value="mc.pixelplanet.fun" readOnly /></p>
<p><input type="text" value="mc.pixelplanet.fun" readOnly /></p> <p>Please Note that the Minecraft Server is down from time to time</p>
<p>Please Note that the Minecraft Server is down from time to time</p> </p>
</p>
</Modal>
); );
function mapStateToProps(state: State) { function mapStateToProps(state: State) {
@ -24,4 +20,9 @@ function mapStateToProps(state: State) {
return { center }; return { center };
} }
export default connect(mapStateToProps)(MinecraftModal); const data = {
content: connect(mapStateToProps)(MinecraftModal),
title: 'PixelPlanet Minecraft Server',
};
export default data;

View File

@ -1,47 +0,0 @@
/**
*
* @flow
*/
import React from 'react';
import Modal from 'react-modal';
import { connect } from 'react-redux';
import { MdClose } from 'react-icons/md';
import {
hideModal,
} from '../actions';
function MyModal({ close, title, children }) {
return (
<Modal
isOpen
onClose={close}
className="Modal"
overlayClassName="Overlay"
contentLabel={`${title} Modal`}
onRequestClose={close}
>
<h2 style={{ paddingLeft: '5%' }}>{title}</h2>
<div
onClick={close}
className="ModalClose"
role="button"
label="close"
tabIndex={-1}
><MdClose /></div>
{children}
</Modal>
);
}
function mapDispatchToProps(dispatch) {
return {
close() {
dispatch(hideModal());
},
};
}
export default connect(null, mapDispatchToProps)(MyModal);

View File

@ -6,7 +6,13 @@
*/ */
import React from 'react'; import React from 'react';
import Modal from 'react-modal';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { MdClose } from 'react-icons/md';
import {
hideModal,
} from '../actions';
import HelpModal from './HelpModal'; import HelpModal from './HelpModal';
import SettingsModal from './SettingsModal'; import SettingsModal from './SettingsModal';
@ -19,6 +25,7 @@ import MinecraftModal from './MinecraftModal';
const MODAL_COMPONENTS = { const MODAL_COMPONENTS = {
NONE: { content: <div />, title: '' },
HELP: HelpModal, HELP: HelpModal,
SETTINGS: SettingsModal, SETTINGS: SettingsModal,
USERAREA: UserAreaModal, USERAREA: UserAreaModal,
@ -30,15 +37,43 @@ const MODAL_COMPONENTS = {
/* other modals */ /* other modals */
}; };
const ModalRoot = ({ modalType }) => { const ModalRoot = ({ modalType, modalOpen, close }) => {
if (!modalType) { const choice = MODAL_COMPONENTS[modalType || 'NONE'];
return null; const { content: SpecificModal, title } = choice;
} return (
<Modal
const SpecificModal = MODAL_COMPONENTS[modalType]; isOpen={modalOpen}
return <SpecificModal />; onClose={close}
className="Modal"
overlayClassName="Overlay"
contentLabel={`${title} Modal`}
closeTimeoutMS={200}
onRequestClose={close}
>
<h2 style={{ paddingLeft: '5%' }}>{title}</h2>
<div
onClick={close}
className="ModalClose"
role="button"
label="close"
tabIndex={-1}
><MdClose /></div>
<SpecificModal />
</Modal>
);
}; };
export default connect( function mapStateToProps(state: State) {
(state) => state.modal, const { modalType, modalOpen } = state.modal;
)(ModalRoot); return { modalType, modalOpen };
}
function mapDispatchToProps(dispatch) {
return {
close() {
dispatch(hideModal());
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ModalRoot);

View File

@ -7,8 +7,8 @@ import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectColor } from '../actions'; import { selectColor } from '../actions';
import type { State } from '../reducers'; import type { State } from '../reducers';
import useWindowSize from '../utils/reactHookResize';
/* /*
@ -90,27 +90,6 @@ function getStylesByWindowSize(
}]; }];
} }
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
function Palette({ function Palette({
colors, colors,
selectedColor, selectedColor,
@ -119,8 +98,20 @@ function Palette({
select, select,
clrIgnore, clrIgnore,
}) { }) {
const [render, setRender] = useState(false);
useEffect(() => {
window.setTimeout(() => {
if (paletteOpen) setRender(true);
}, 10);
}, [paletteOpen]);
const onTransitionEnd = () => {
if (!paletteOpen) setRender(false);
};
const [paletteStyle, spanStyle] = getStylesByWindowSize( const [paletteStyle, spanStyle] = getStylesByWindowSize(
paletteOpen, (render && paletteOpen),
useWindowSize(), useWindowSize(),
colors, colors,
clrIgnore, clrIgnore,
@ -128,28 +119,31 @@ function Palette({
); );
return ( return (
<div (render || paletteOpen) && (
id="palettebox" <div
style={paletteStyle} id="palettebox"
> style={paletteStyle}
{colors.slice(2).map((color, index) => ( onTransitionEnd={onTransitionEnd}
<span >
style={{ {colors.slice(2).map((color, index) => (
backgroundColor: color, <span
...spanStyle, style={{
}} backgroundColor: color,
role="button" ...spanStyle,
tabIndex={0} }}
aria-label={`color ${index + 2}`} role="button"
key={color} tabIndex={0}
className={selectedColor === (index + clrIgnore) aria-label={`color ${index + 2}`}
? 'selected' key={color}
: 'unselected'} className={selectedColor === (index + clrIgnore)
color={color} ? 'selected'
onClick={() => select(index + clrIgnore)} : 'unselected'}
/> color={color}
))} onClick={() => select(index + clrIgnore)}
</div> />
))}
</div>
)
); );
} }

View File

@ -6,8 +6,6 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Modal from './Modal';
import { showUserAreaModal } from '../actions'; import { showUserAreaModal } from '../actions';
// import { send_registration } from '../ui/register'; // import { send_registration } from '../ui/register';
@ -15,17 +13,15 @@ import SignUpForm from './SignUpForm';
const RegisterModal = ({ login }) => ( const RegisterModal = ({ login }) => (
<Modal title="Register New Account"> <p style={{ paddingLeft: '5%', paddingRight: '5%' }}>
<p style={{ paddingLeft: '5%', paddingRight: '5%' }}> <p className="modaltext">Register new account here</p><br />
<p className="modaltext">Register new account here</p><br /> <p style={{ textAlign: 'center' }}>
<p style={{ textAlign: 'center' }}> <SignUpForm back={login} />
<SignUpForm back={login} /> <p>Also join our Discord:&nbsp;
<p>Also join our Discord:&nbsp; <a href="./discord" target="_blank">pixelplanet.fun/discord</a>
<a href="./discord" target="_blank">pixelplanet.fun/discord</a>
</p>
</p> </p>
</p> </p>
</Modal> </p>
); );
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
@ -36,4 +32,9 @@ function mapDispatchToProps(dispatch) {
}; };
} }
export default connect(null, mapDispatchToProps)(RegisterModal); const data = {
content: connect(null, mapDispatchToProps)(RegisterModal),
title: 'Register New Account',
};
export default data;

View File

@ -6,7 +6,6 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Modal from './Modal';
import MdToggleButtonHover from './MdToggleButtonHover'; import MdToggleButtonHover from './MdToggleButtonHover';
import { import {
toggleGrid, toggleGrid,
@ -118,82 +117,80 @@ function SettingsModal({
chatNotify, chatNotify,
}) { }) {
return ( return (
<Modal title="Settings"> <p style={{ paddingLeft: '5%', paddingRight: '5%', paddingTop: 30 }}>
<p style={{ paddingLeft: '5%', paddingRight: '5%', paddingTop: 30 }}> <SettingsItem
<SettingsItem title="Show Grid"
title="Show Grid" description="Turn on grid to highlight pixel borders."
description="Turn on grid to highlight pixel borders." keyBind="G"
keyBind="G" value={isGridShown}
value={isGridShown} onToggle={onToggleGrid}
onToggle={onToggleGrid} />
/> <SettingsItem
<SettingsItem title="Show Pixel Activity"
title="Show Pixel Activity" description="Show circles where pixels are placed."
description="Show circles where pixels are placed." keyBind="X"
keyBind="X" value={isPixelNotifyShown}
value={isPixelNotifyShown} onToggle={onTogglePixelNotify}
onToggle={onTogglePixelNotify} />
/> <SettingsItem
<SettingsItem title="Disable Game Sounds"
title="Disable Game Sounds" // eslint-disable-next-line max-len
// eslint-disable-next-line max-len description="All sound effects except Chat Notification will be disabled."
description="All sound effects except Chat Notification will be disabled." keyBind="M"
keyBind="M" value={isMuted}
value={isMuted} onToggle={onMute}
onToggle={onMute} />
/> <SettingsItem
<SettingsItem title="Enable chat notifications"
title="Enable chat notifications" description="Play a sound when new chat messages arrive"
description="Play a sound when new chat messages arrive" value={chatNotify}
value={chatNotify} onToggle={onToggleChatNotify}
onToggle={onToggleChatNotify} />
/> <SettingsItem
<SettingsItem title="Auto Zoom In"
title="Auto Zoom In" // eslint-disable-next-line max-len
// eslint-disable-next-line max-len description="Zoom in instead of placing a pixel when you tap the canvas and your zoom is small."
description="Zoom in instead of placing a pixel when you tap the canvas and your zoom is small." value={autoZoomIn}
value={autoZoomIn} onToggle={onToggleAutoZoomIn}
onToggle={onToggleAutoZoomIn} />
/> <SettingsItem
<SettingsItem title="Compact Palette"
title="Compact Palette" // eslint-disable-next-line max-len
// eslint-disable-next-line max-len description="Display Palette in a compact form that takes less screen space."
description="Display Palette in a compact form that takes less screen space." value={compactPalette}
value={compactPalette} onToggle={onToggleCompactPalette}
onToggle={onToggleCompactPalette} />
/> <SettingsItem
<SettingsItem title="Potato Mode"
title="Potato Mode" description="For when you are playing on a potato."
description="For when you are playing on a potato." value={isPotato}
value={isPotato} onToggle={onTogglePotatoMode}
onToggle={onTogglePotatoMode} />
/> <SettingsItem
<SettingsItem title="Light Grid"
title="Light Grid" description="Show Grid in white instead of black."
description="Show Grid in white instead of black." value={isLightGrid}
value={isLightGrid} onToggle={onToggleLightGrid}
onToggle={onToggleLightGrid} />
/> { (window.backupurl)
{ (window.backupurl) ? (
? ( <SettingsItem
<SettingsItem title="Historical View"
title="Historical View" description="Check out past versions of the canvas."
description="Check out past versions of the canvas." value={isHistoricalView}
value={isHistoricalView} onToggle={onToggleHistoricalView}
onToggle={onToggleHistoricalView}
/>
) : null }
{(typeof window.availableStyles !== 'undefined') && (
<SettingsItemSelect
title="Themes"
description="How pixelplanet should look like."
values={Object.keys(window.availableStyles)}
selected={selectedStyle}
onSelect={onSelectStyle}
/> />
)} ) : null }
</p> {(typeof window.availableStyles !== 'undefined') && (
</Modal> <SettingsItemSelect
title="Themes"
description="How pixelplanet should look like."
values={Object.keys(window.availableStyles)}
selected={selectedStyle}
onSelect={onSelectStyle}
/>
)}
</p>
); );
} }
@ -263,4 +260,9 @@ function mapDispatchToProps(dispatch) {
}; };
} }
export default connect(mapStateToProps, mapDispatchToProps)(SettingsModal); const data = {
content: connect(mapStateToProps, mapDispatchToProps)(SettingsModal),
title: 'Settings',
};
export default data;

View File

@ -6,8 +6,6 @@
import React, { Suspense } from 'react'; import React, { Suspense } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Modal from './Modal';
import type { State } from '../reducers'; import type { State } from '../reducers';
@ -86,40 +84,38 @@ const LogInArea = ({ register, forgotPassword, me }) => (
const UserAreaModal = ({ const UserAreaModal = ({
name, register, forgotPassword, doMe, logout, setUserName, setUserMailreg, name, register, forgotPassword, doMe, logout, setUserName, setUserMailreg,
}) => ( }) => (
<Modal title="User Area"> <p style={{ textAlign: 'center' }}>
<p style={{ textAlign: 'center' }}> {(name === null)
{(name === null) ? (
? ( <LogInArea
<LogInArea register={register}
register={register} forgotPassword={forgotPassword}
forgotPassword={forgotPassword} me={doMe}
me={doMe} />
/> )
) : (
: ( <Tabs>
<Tabs> <div label="Profile">
<div label="Profile"> <UserArea
<UserArea logout={logout}
logout={logout} setName={setUserName}
setName={setUserName} setMailreg={setUserMailreg}
setMailreg={setUserMailreg} />
/> </div>
</div> <div label="Ranking">
<div label="Ranking"> <Rankings />
<Rankings /> </div>
</div> <div label="Converter">
<div label="Converter"> <Suspense fallback={<div>Loading...</div>}>
<Suspense fallback={<div>Loading...</div>}> <Converter />
<Converter /> </Suspense>
</Suspense> </div>
</div> </Tabs>
</Tabs> )}
)} <p>Also join our Discord:&nbsp;
<p>Also join our Discord:&nbsp; <a href="./discord" target="_blank">pixelplanet.fun/discord</a>
<a href="./discord" target="_blank">pixelplanet.fun/discord</a>
</p>
</p> </p>
</Modal> </p>
); );
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
@ -157,4 +153,9 @@ function mapStateToProps(state: State) {
return { name }; return { name };
} }
export default connect(mapStateToProps, mapDispatchToProps)(UserAreaModal); const data = {
content: connect(mapStateToProps, mapDispatchToProps)(UserAreaModal),
title: 'User Area',
};
export default data;

View File

@ -7,11 +7,13 @@
import type { Action } from '../actions/types'; import type { Action } from '../actions/types';
export type ModalState = { export type ModalState = {
modalOpen: boolean,
modalType: ?string, modalType: ?string,
chatOpen: boolean, chatOpen: boolean,
}; };
const initialState: ModalState = { const initialState: ModalState = {
modalOpen: false,
modalType: null, modalType: null,
chatOpen: false, chatOpen: false,
}; };
@ -31,6 +33,7 @@ export default function modal(
...state, ...state,
modalType, modalType,
chatOpen, chatOpen,
modalOpen: true,
}; };
} }
@ -38,7 +41,7 @@ export default function modal(
case 'HIDE_MODAL': case 'HIDE_MODAL':
return { return {
...state, ...state,
modalType: null, modalOpen: false,
}; };
case 'TOGGLE_CHAT_BOX': { case 'TOGGLE_CHAT_BOX': {

View File

@ -41,7 +41,7 @@ tr:nth-child(even) {
border-radius: 21px; border-radius: 21px;
} }
#menu > div { .menu > div {
z-index: 1; z-index: 1;
background-color: #15374fd1; background-color: #15374fd1;
} }
@ -81,6 +81,10 @@ tr:nth-child(even) {
border-color: #dcddde; border-color: #dcddde;
} }
.ModalClose:hover {
background-color: #6f6f75;
}
.Overlay { .Overlay {
background-color: rgba(187, 187, 187, 0.75); background-color: rgba(187, 187, 187, 0.75);
} }
@ -89,6 +93,10 @@ tr:nth-child(even) {
color: white; color: white;
} }
#chatlink {
color: #f9edde;
}
.statvalue { .statvalue {
color: #ecc9ff; color: #ecc9ff;
} }
@ -98,7 +106,7 @@ tr:nth-child(even) {
border-radius: 21px; border-radius: 21px;
} }
.actionbuttons:hover, .coorbox:hover, #menu > div:hover { .actionbuttons:hover, .coorbox:hover, .menu > div:hover {
background-color: #363637; background-color: #363637;
} }

View File

@ -39,7 +39,7 @@ tr:nth-child(even) {
color: #f4f4f4; color: #f4f4f4;
} }
#menu > div { .menu > div {
z-index: 1; z-index: 1;
background-color: #15374fd1; background-color: #15374fd1;
} }
@ -78,6 +78,10 @@ tr:nth-child(even) {
border-color: #dcddde; border-color: #dcddde;
} }
.ModalClose:hover {
background-color: #6f6f75;
}
.Overlay { .Overlay {
background-color: rgba(187, 187, 187, 0.75); background-color: rgba(187, 187, 187, 0.75);
} }
@ -86,6 +90,10 @@ tr:nth-child(even) {
color: white; color: white;
} }
#chatlink {
color: #f9edde;
}
.statvalue { .statvalue {
color: #ecc9ff; color: #ecc9ff;
} }
@ -94,7 +102,7 @@ tr:nth-child(even) {
background-color: rgba(59, 59, 59, 0.8); background-color: rgba(59, 59, 59, 0.8);
} }
.actionbuttons:hover, .coorbox:hover, #menu > div:hover { .actionbuttons:hover, .coorbox:hover, .menu > div:hover {
background-color: #363637; background-color: #363637;
} }

View File

@ -162,7 +162,7 @@ tr:nth-child(even) {
.menu { .menu {
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
transition: all .1s cubic-bezier(.46,.03,.52,.96); transition: all .15s cubic-bezier(.46,.03,.52,.96);
} }
.menu.show { .menu.show {
@ -341,6 +341,11 @@ tr:nth-child(even) {
border-color: #dcddde; border-color: #dcddde;
top: 30px; top: 30px;
right: 40px; right: 40px;
z-index: 5;
}
.ModalClose:hover {
background-color: #e3e3e4;
} }
@media (max-width: 604px) { @media (max-width: 604px) {
@ -376,7 +381,6 @@ tr:nth-child(even) {
margin: 0px; margin: 0px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: scroll; overflow-y: scroll;
height: 95%;
} }
.chatinput { .chatinput {
height: 22px; height: 22px;
@ -393,6 +397,15 @@ tr:nth-child(even) {
user-select: text; user-select: text;
margin: 0; margin: 0;
} }
#chatlink {
position: absolute;
font-weight: bold;
font-size: 20px;
right: 17px;
top: 5px;
color: #4a4a49;
cursor: pointer;
}
.usermessages { .usermessages {
font-size: 14px; font-size: 14px;
@ -477,7 +490,7 @@ tr:nth-child(even) {
} }
#palettebox, #palettebox span { #palettebox, #palettebox span {
transition: 0.3s; transition: 0.2s;
} }
#palettebox .selected, #palettebox .selected,
@ -506,3 +519,16 @@ tr:nth-child(even) {
.grecaptcha-badge { .grecaptcha-badge {
visibility: hidden; visibility: hidden;
} }
.ReactModal__Overlay {
opacity: 0;
transition: opacity 200ms ease-in-out;
}
.ReactModal__Overlay--after-open{
opacity: 1;
}
.ReactModal__Overlay--before-close{
opacity: 0;
}

View File

@ -5,6 +5,6 @@
import configureStore from '../store/configureStore'; import configureStore from '../store/configureStore';
const store = configureStore(); const store = configureStore(() => null);
export default store; export default store;

View File

@ -0,0 +1,31 @@
/*
* @flex
*
* can be used in react components
* to trigger on window resize
*/
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
export default useWindowSize;