treat Modal equal to Window, move them to WindowManager

This commit is contained in:
HF 2022-08-12 22:35:09 +02:00
parent 43c2f1d012
commit 196e701150
19 changed files with 442 additions and 511 deletions

View File

@ -7,6 +7,7 @@ import { useSelector, useDispatch } from 'react-redux';
import GlobalCaptcha from './GlobalCaptcha';
import BanInfo from './BanInfo';
import Overlay from './Overlay';
import { closeAlert } from '../store/actions';
const Alert = () => {
@ -25,14 +26,12 @@ const Alert = () => {
dispatch(closeAlert());
}, [dispatch]);
const onTransitionEnd = () => {
if (!open) setRender(false);
};
useEffect(() => {
window.setTimeout(() => {
if (open) setRender(true);
}, 10);
if (open) {
window.setTimeout(() => {
setRender(true);
}, 10);
}
}, [open]);
let Content = null;
@ -47,37 +46,43 @@ const Alert = () => {
// nothing
}
if (!render && !open) {
return null;
}
const show = open && render;
return (
(render || open) && (
<div>
<div
className={(open && render)
? 'OverlayAlert show'
: 'OverlayAlert'}
onTransitionEnd={onTransitionEnd}
tabIndex={-1}
onClick={close}
/>
<div
className={(open && render) ? 'Alert show' : 'Alert'}
>
<h2>{title}</h2>
{(message) && (
<p className="modaltext">
{message}
</p>
)}
{(Content) ? (
<Content close={close} />
) : (
<button
type="button"
onClick={close}
>{btn}</button>
)}
</div>
<>
<Overlay
z={6}
show={show}
onClick={close}
/>
(render || open) && (
<div
className={(show) ? 'Alert show' : 'Alert'}
onTransitionEnd={() => {
if (!open) setRender(false);
}}
>
<h2>{title}</h2>
{(message) && (
<p className="modaltext">
{message}
</p>
)}
{(Content) ? (
<Content close={close} />
) : (
<button
type="button"
onClick={close}
>{btn}</button>
)}
</div>
)
)
</>
);
};

View File

@ -15,7 +15,6 @@ import ChatButton from './buttons/ChatButton';
import Menu from './Menu';
import UI from './UI';
import ExpandMenuButton from './buttons/ExpandMenuButton';
import ModalRoot from './ModalRoot';
import WindowManager from './WindowManager';
const iconContextValue = { style: { verticalAlign: 'middle' } };
@ -32,7 +31,6 @@ const App = () => (
<CoordinatesBox />
<ExpandMenuButton />
<UI />
<ModalRoot />
<WindowManager />
</IconContext.Provider>
</div>

View File

@ -41,7 +41,7 @@ function ChatMessage({
const pArray = parseParagraph(msg);
return (
<li className="chatmsg">
<li className="chatmsg" ref={refEmbed}>
{(!isInfo && !isEvent)
&& (
<div className="chathead" key="ch">
@ -86,7 +86,6 @@ function ChatMessage({
<div className={className} key="cm">
<MarkdownParagraph refEmbed={refEmbed} pArray={pArray} />
</div>
<div className="chatembed" ref={refEmbed} key="ce" />
</li>
);
}

View File

@ -20,14 +20,14 @@ const keepState = {
/*
* sorting function for array sort
*/
function compare(a, b) {
function compare(a, b, asc) {
if (typeof a === 'string' && typeof b === 'string') {
return a.localeCompare(b);
}
if (a === 'N/A') a = 0;
if (b === 'N/A') b = 0;
if (a < b) return -1;
if (a > b) return 1;
if (a < b) return (asc) ? -1 : 1;
if (a > b) return (asc) ? 1 : -1;
return 0;
}
@ -73,6 +73,7 @@ function ModWatchtools() {
const [tlcoords, selectTLCoords] = useState(keepState.tlcoords);
const [brcoords, selectBRCoords] = useState(keepState.brcoords);
const [interval, selectInterval] = useState(keepState.interval);
const [sortAsc, setSortAsc] = useState(true);
const [sortBy, setSortBy] = useState(0);
const [table, setTable] = useState({});
const [iid, selectIid] = useState(keepState.iid);
@ -266,116 +267,121 @@ function ModWatchtools() {
{(rows && columns && types) && (
<React.Fragment key="pxltable">
<div className="modaldivider" />
<table
style={{
userSelect: 'text',
fontSize: 11,
}}
>
<table style={{ fontSize: 11 }} >
<thead>
<tr>
{columns.slice(1).map((col, ind) => (
<th
key={col}
style={
(sortBy - 1 === ind)
? { fontWeight: 'normal' }
: { cursor: 'pointer' }
(sortBy - 1 === ind) ? {
cursor: 'pointer',
fontWeight: 'normal',
} : {
cursor: 'pointer',
}
}
onClick={() => setSortBy(ind + 1)}
onClick={() => {
if (sortBy - 1 === ind) {
setSortAsc(!sortAsc);
} else {
setSortBy(ind + 1);
}
}}
>{col}</th>
))}
</tr>
</thead>
<tbody>
{rows.sort((a, b) => compare(a[sortBy], b[sortBy])).map((row) => (
<tr key={row[0]}>
{row.slice(1).map((val, ind) => {
const type = types[ind + 1];
switch (type) {
case 'ts': {
const date = new Date(val);
let minutes = date.getMinutes();
if (minutes < 10) minutes = `0${minutes}`;
return (
<td title={date.toLocaleDateString()}>
{`${date.getHours()}:${minutes}`}
</td>
);
}
case 'clr': {
const cid = (cidColumn > 0)
? row[cidColumn] : selectedCanvas;
const rgb = canvases[cid]
<tbody style={{ userSelect: 'text' }}>
{rows.sort((a, b) => compare(a[sortBy], b[sortBy], sortAsc))
.map((row) => (
<tr key={row[0]}>
{row.slice(1).map((val, ind) => {
const type = types[ind + 1];
switch (type) {
case 'ts': {
const date = new Date(val);
let minutes = date.getMinutes();
if (minutes < 10) minutes = `0${minutes}`;
return (
<td title={date.toLocaleDateString()}>
{`${date.getHours()}:${minutes}`}
</td>
);
}
case 'clr': {
const cid = (cidColumn > 0)
? row[cidColumn] : selectedCanvas;
const rgb = canvases[cid]
&& canvases[cid].colors
&& canvases[cid].colors[val];
if (!rgb) {
if (!rgb) {
return (<td>{val}</td>);
}
const color = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
return (
<td style={{ backgroundColor: color }}>{val}</td>
);
}
case 'coord': {
const cid = (cidColumn > 0)
? row[cidColumn] : selectedCanvas;
const ident = canvases[cid] && canvases[cid].ident;
const coords = `./#${ident},${val},47`;
return (
<td>
<a href={coords}>{val}</a>
</td>
);
}
case 'flag': {
const flag = val.toLowerCase();
return (
<td title={val}><img
style={{
height: '1em',
imageRendering: 'crisp-edges',
}}
alt={val}
src={`${window.ssv.assetserver}/cf/${flag}.gif`}
/></td>
);
}
case 'cid': {
const ident = canvases[val] && canvases[val].ident;
return (<td>{ident}</td>);
}
case 'uuid': {
return (
<td>
<span
role="button"
tabIndex={-1}
style={{ cursor: 'pointer' }}
title={t`Copy to Clipboard`}
onClick={() => copyTextToClipboard(val)}
>{val}</span>
</td>
);
}
case 'user': {
const seperator = val.lastIndexOf(',');
if (seperator === -1) {
return (<td>{val}</td>);
}
return (
<td title={val.slice(seperator + 1)}>
{val.slice(0, seperator)}
</td>
);
}
default: {
return (<td>{val}</td>);
}
const color = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
return (
<td style={{ backgroundColor: color }}>{val}</td>
);
}
case 'coord': {
const cid = (cidColumn > 0)
? row[cidColumn] : selectedCanvas;
const ident = canvases[cid] && canvases[cid].ident;
const coords = `./#${ident},${val},47`;
return (
<td>
<a href={coords}>{val}</a>
</td>
);
}
case 'flag': {
const flag = val.toLowerCase();
return (
<td title={val}><img
style={{
height: '1em',
imageRendering: 'crisp-edges',
}}
alt={val}
src={`${window.ssv.assetserver}/cf/${flag}.gif`}
/></td>
);
}
case 'cid': {
const ident = canvases[val] && canvases[val].ident;
return (<td>{ident}</td>);
}
case 'uuid': {
return (
<td>
<span
role="button"
tabIndex={-1}
style={{ cursor: 'pointer' }}
title={t`Copy to Clipboard`}
onClick={() => copyTextToClipboard(val)}
>{val}</span>
</td>
);
}
case 'user': {
const seperator = val.lastIndexOf(',');
if (seperator === -1) {
return (<td>{val}</td>);
}
return (
<td title={val.slice(seperator + 1)}>
{val.slice(0, seperator)}
</td>
);
}
default: {
return (<td>{val}</td>);
}
}
})}
</tr>
))}
})}
</tr>
))}
</tbody>
</table>
</React.Fragment>

View File

@ -1,90 +0,0 @@
/**
*
* https://stackoverflow.com/questions/35623656/how-can-i-display-a-modal-dialog-in-redux-that-performs-asynchronous-actions/35641680#35641680
*
*/
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { MdClose } from 'react-icons/md';
import { t } from 'ttag';
import {
closeWindow,
restoreWindow,
removeWindow,
} from '../store/actions';
import COMPONENTS from './windows';
const ModalRoot = () => {
const [render, setRender] = useState(false);
const { windowType, open, title } = useSelector(
(state) => state.windows.modal,
);
const showWindows = useSelector((state) => state.windows.showWindows);
const dispatch = useDispatch();
const onTransitionEnd = () => {
if (!open) {
setRender(false);
dispatch(removeWindow(0));
}
};
useEffect(() => {
window.setTimeout(() => {
if (open) setRender(true);
}, 10);
}, [open]);
if (!windowType) {
return null;
}
const [Content, name] = COMPONENTS[windowType];
return (
(render || open) && (
<>
<div
className={(open && render)
? 'OverlayModal show'
: 'OverlayModal'}
onTransitionEnd={onTransitionEnd}
tabIndex={-1}
onClick={() => dispatch(closeWindow(0))}
/>
<div
className={(open && render) ? 'Modal show' : 'Modal'}
>
<h2>{(title) ? `${name} - ${title}` : name}</h2>
<div
onClick={() => dispatch(closeWindow(0))}
className="ModalClose"
role="button"
label="close"
title={t`Close`}
tabIndex={-1}
><MdClose /></div>
{(showWindows) && (
<div
onClick={() => dispatch(restoreWindow())}
className="ModalRestore"
role="button"
label="restore"
title={t`Restore`}
tabIndex={-1}
></div>
)}
<div className="Modal-content">
<Content windowId={0} />
</div>
</div>,
</>
)
);
};
export default React.memo(ModalRoot);

View File

@ -0,0 +1,37 @@
/*
* Overlay to fade out background
*/
import React, { useState, useEffect } from 'react';
const Overlay = ({ show, onClick, z }) => {
const [render, setRender] = useState(false);
useEffect(() => {
if (show) {
window.setTimeout(() => {
setRender(true);
}, 10);
}
}, [show]);
if (!render && !show) {
return null;
}
return (
<div
className={(show && render)
? 'overlay show'
: 'overlay'}
style={(z) ? { zIndex: z } : {}}
onTransitionEnd={() => {
if (!show) setRender(false);
}}
tabIndex={-1}
onClick={onClick}
/>
);
};
export default React.memo(Overlay);

View File

@ -13,7 +13,7 @@ import {
removeWindow,
resizeWindow,
closeWindow,
maximizeWindow,
toggleMaximizeWindow,
cloneWindow,
focusWindow,
} from '../store/actions';
@ -30,22 +30,76 @@ const Window = ({ id }) => {
const resizeRef = useRef(null);
const win = useSelector((state) => selectWindowById(state, id));
const showWindows = useSelector((state) => state.windows.showWindows);
const dispatch = useDispatch();
const focus = useCallback(() => dispatch(focusWindow(id)), []);
const clone = (evt) => {
const {
open,
hidden,
fullscreen,
} = win;
const focus = useCallback(() => {
dispatch(focusWindow(id));
}, [dispatch]);
const clone = useCallback((evt) => {
evt.stopPropagation();
dispatch(cloneWindow(id));
};
const maximize = (evt) => {
evt.stopPropagation();
dispatch(maximizeWindow(id));
};
const close = (evt) => {
}, [dispatch]);
const toggleMaximize = useCallback((evt) => {
setRender(false);
}, [dispatch]);
const close = useCallback((evt) => {
evt.stopPropagation();
dispatch(closeWindow(id));
};
}, [dispatch]);
useDrag(
titleBarRef,
focus,
useCallback((xDiff, yDiff) => dispatch(
moveWindow(id, xDiff, yDiff),
), [fullscreen, !render && hidden]),
);
useDrag(
resizeRef,
focus,
useCallback((xDiff, yDiff) => dispatch(
resizeWindow(id, xDiff, yDiff),
), [fullscreen, !render && hidden]),
);
const onTransitionEnd = useCallback(() => {
if (hidden) {
setRender(false);
return;
}
if (!open) {
dispatch(removeWindow(id));
return;
}
if (!render) {
dispatch(toggleMaximizeWindow(id));
setTimeout(() => setRender(true), 10);
}
}, [dispatch, hidden, open, render]);
useEffect(() => {
if (open && !hidden) {
window.setTimeout(() => {
setRender(true);
}, 10);
}
}, [open, hidden]);
if (!render && (hidden || !open)) {
return null;
}
const {
width, height,
@ -53,50 +107,62 @@ const Window = ({ id }) => {
windowType,
z,
title,
open,
hidden,
} = win;
useDrag(
titleBarRef,
focus,
useCallback((xDiff, yDiff) => dispatch(moveWindow(id, xDiff, yDiff)),
[hidden]),
);
useDrag(
resizeRef,
focus,
useCallback((xDiff, yDiff) => dispatch(resizeWindow(id, xDiff, yDiff)),
[hidden]),
);
const onTransitionEnd = () => {
if (hidden) {
setRender(false);
}
if (!open) {
dispatch(removeWindow(id));
}
};
useEffect(() => {
window.setTimeout(() => {
if (open && !hidden) setRender(true);
}, 10);
}, [open, hidden]);
const [Content, name] = COMPONENTS[windowType];
if (!render && hidden) {
const windowTitle = (title) ? `${name} - ${title}` : name;
const extraClasses = `${windowType}${
(open && !hidden && render) ? ' show' : ''}`;
if (fullscreen) {
return (
<div
className={`modal ${extraClasses}`}
onTransitionEnd={onTransitionEnd}
onClick={focus}
style={{
zIndex: z,
}}
>
<h2>{windowTitle}</h2>
<div
onClick={close}
className="ModalClose"
role="button"
label="close"
key="closebtn"
title={t`Close`}
tabIndex={-1}
></div>
{(showWindows) && (
<div
onClick={toggleMaximize}
className="ModalRestore"
key="resbtn"
role="button"
label="restore"
title={t`Restore`}
tabIndex={-1}
></div>
)}
<div
className="modal-content"
key="content"
>
<Content windowId={id} />
</div>
</div>
);
}
if (!showWindows) {
return null;
}
return (
<div
className={`window ${windowType}${
(open && !hidden && render) ? ' show' : ''
}`}
className={`window ${extraClasses}`}
onTransitionEnd={onTransitionEnd}
onClick={focus}
style={{
@ -125,12 +191,12 @@ const Window = ({ id }) => {
ref={titleBarRef}
title={t`Move`}
>
{(title) ? `${name} - ${title}` : name}
{windowTitle}
</span>
<span
className="win-topbtn"
key="maxbtn"
onClick={maximize}
onClick={toggleMaximize}
title={t`Maximize`}
>
@ -146,9 +212,9 @@ const Window = ({ id }) => {
</div>
<div
className="win-resize"
key="winres"
title={t`Resize`}
ref={resizeRef}
key="winres"
>
</div>

View File

@ -3,24 +3,35 @@
*/
import React from 'react';
import { useSelector, shallowEqual } from 'react-redux';
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
import Window from './Window';
import Overlay from './Overlay';
import {
closeFullscreenWindows,
} from '../store/actions';
// eslint-disable-next-line max-len
const selectWindowIds = (state) => state.windows.windows.map((win) => win.windowId);
// eslint-disable-next-line max-len
const selectMeta = (state) => [state.windows.showWindows, state.windows.someFullscreen];
const WindowManager = () => {
const windowIds = useSelector(selectWindowIds, shallowEqual);
const showWindows = useSelector((state) => state.windows.showWindows);
const [showWindows, someFullscreen] = useSelector(selectMeta, shallowEqual);
const dispatch = useDispatch();
if (!showWindows) return null;
if ((!showWindows && !someFullscreen) || !windowIds.length) {
return null;
}
return (
<div id="wm">
{
windowIds.map((id) => (<Window key={id} id={id} />))
}
<Overlay
show={someFullscreen}
onClick={() => dispatch(closeFullscreenWindows())}
/>
{windowIds.map((id) => <Window key={id} id={id} />)}
</div>
);
};

View File

@ -23,8 +23,7 @@ import {
const selectChatWindowStatus = (state) => [
state.windows.showWindows,
state.windows.windows.find((win) => win.windowType === 'CHAT'
&& win.hidden === false)
|| (state.windows.modal.open && state.windows.modal.windowType === 'CHAT'),
&& win.hidden === false),
state.windows.windows.find((win) => win.windowType === 'CHAT'
&& win.hidden === true),
];

View File

@ -46,9 +46,11 @@ function useDrag(elRef, startHandler, diffHandler) {
document.addEventListener('mouseup', stopDrag);
document.addEventListener('touchcancel', stopDrag);
document.addEventListener('touchend', stopDrag);
}, [startHandler]);
}, [startHandler, diffHandler]);
useEffect(() => {
let prevCurrent = null;
if (elRef.current) {
elRef.current.addEventListener('mousedown', startDrag, {
passive: false,
@ -56,14 +58,16 @@ function useDrag(elRef, startHandler, diffHandler) {
elRef.current.addEventListener('touchstart', startDrag, {
passive: false,
});
prevCurrent = elRef.current;
}
return () => {
if (elRef.current) {
elRef.current.removeEventListener('mousedown', startDrag);
elRef.current.removeEventListener('touchstart', startDrag);
if (prevCurrent) {
prevCurrent.removeEventListener('mousedown', startDrag);
prevCurrent.removeEventListener('touchstart', startDrag);
}
};
}, [elRef, diffHandler]);
}, [elRef, startDrag]);
}
export default useDrag;

View File

@ -86,8 +86,8 @@ export type Action =
| { type: 'CLOSE_ALL_WINDOW_TYPE', windowType: string}
| { type: 'FOCUS_WINDOW', windowId: number }
| { type: 'CLONE_WINDOW', windowId: number }
| { type: 'MAXIMIZE_WINDOW', windowId: number }
| { type: 'RESTORE_WINDOW' }
| { type: 'TOGGLE_MAXIMIZE_WINDOW', windowId: number }
| { type: 'CLOSE_FULLSCREEN_WINDOWS' }
| { type: 'MOVE_WINDOW', windowId: number, xDiff: number, yDiff: number }
| { type: 'RESIZE_WINDOW', windowId: number, xDiff: number, yDiff: number }
| { type: 'CHANGE_WINDOW_TYPE',

View File

@ -611,7 +611,7 @@ export function setWindowArgs(
};
}
export function showModal(modalType, title) {
function showFullscreenWindow(modalType, title) {
return openWindow(
modalType,
title,
@ -620,15 +620,21 @@ export function showModal(modalType, title) {
);
}
export function closeFullscreenWindows() {
return {
type: 'CLOSE_FULLSCREEN_WINDOWS',
};
}
export function showSettingsModal() {
return showModal(
return showFullscreenWindow(
'SETTINGS',
'',
);
}
export function showUserAreaModal() {
return showModal(
return showFullscreenWindow(
'USERAREA',
'',
);
@ -658,34 +664,34 @@ export function setWindowTitle(windowId, title) {
}
export function showRegisterModal() {
return showModal(
return showFullscreenWindow(
'REGISTER',
t`Register New Account`,
);
}
export function showForgotPasswordModal() {
return showModal(
return showFullscreenWindow(
'FORGOT_PASSWORD',
t`Restore my Password`,
);
}
export function showHelpModal() {
return showModal(
return showFullscreenWindow(
'HELP',
t`Welcome to PixelPlanet.fun`,
);
}
export function showArchiveModal() {
return showModal(
return showFullscreenWindow(
'ARCHIVE',
t`Look at past Canvases`,
);
}
export function showCanvasSelectionModal() {
return showModal(
return showFullscreenWindow(
'CANVAS_SELECTION',
'',
);
@ -823,19 +829,13 @@ export function cloneWindow(windowId) {
};
}
export function maximizeWindow(windowId) {
export function toggleMaximizeWindow(windowId) {
return {
type: 'MAXIMIZE_WINDOW',
type: 'TOGGLE_MAXIMIZE_WINDOW',
windowId,
};
}
export function restoreWindow() {
return {
type: 'RESTORE_WINDOW',
};
}
export function moveWindow(windowId, xDiff, yDiff) {
return {
type: 'MOVE_WINDOW',

View File

@ -1,5 +1,5 @@
/*
* state for open windows and modal and its content
* state for open windows and its content
*/
import { clamp } from '../../core/utils';
@ -70,8 +70,8 @@ function clampPos(prefXPos, prefYPos, width, height) {
/*
* resort the zIndex, remove gaps
*/
function sortWindows(newState) {
if (newState.zMax >= MAX_AMOUNT_WINDOWS * 0.5) {
function sortWindows(newState, force = false) {
if (newState.zMax >= MAX_AMOUNT_WINDOWS * 0.5 || force) {
const orderedZ = newState.windows.map((win) => win.z)
.sort((a, b) => !b || (a && a >= b));
newState.windows = newState.windows.map((win) => ({
@ -86,30 +86,16 @@ function sortWindows(newState) {
const initialState = {
// if windows get shown, false on small screens
showWindows: true,
// if at least one window is in fullscreen
someFullscreen: false,
// highest zIndex of window
zMax: 0,
// modal is considerd as "fullscreen window"
// its windowId is considered 0 and args are under args[0]
modal: {
windowType: null,
title: null,
open: false,
// used to remember and restore the size
// of a maximized window when restoring
// {
// xPos: number,
// yPos: number,
// width: number,
// height: number,
// cloneable: boolean,
// }
prevWinSize: {},
},
// [
// {
// windowId: number,
// open: boolean,
// hidden: boolean,
// fullscreen: boolean,
// z: number,
// windowType: string,
// title: string,
@ -158,31 +144,8 @@ export default function windows(
const [width, height] = clampSize(prefWidth, prefHeight, true);
const [xPos, yPos] = clampPos(prefXPos, prefYPos, width, height);
// fullscreen means to open as Modal
const fullscreen = !state.showWindows || action.fullscreen;
if (fullscreen) {
return {
...state,
modal: {
windowType,
title,
open: true,
prevWinSize: {
width,
height,
xPos,
yPos,
cloneable,
},
},
args: {
...state.args,
0: {
...args,
},
},
};
}
if (state.windows.length >= MAX_AMOUNT_WINDOWS) {
return state;
}
@ -195,6 +158,7 @@ export default function windows(
windowType,
open: true,
hidden: false,
fullscreen,
z: newZMax,
title,
width,
@ -204,8 +168,14 @@ export default function windows(
cloneable,
},
];
const someFullscreen = newWindows.some(
(win) => win.fullscreen && win.open,
);
return sortWindows({
...state,
someFullscreen,
zMax: newZMax,
windows: newWindows,
args: {
@ -224,18 +194,6 @@ export default function windows(
const args = { ...state.args };
delete args[windowId];
if (windowId === 0) {
return {
...state,
modal: {
windowType: null,
title: null,
open: false,
prevWinSize: {},
},
args,
};
}
return {
...state,
windows: state.windows.filter((win) => win.windowId !== windowId),
@ -247,15 +205,6 @@ export default function windows(
const {
windowId,
} = action;
if (windowId === 0) {
return {
...state,
modal: {
...state.modal,
open: false,
},
};
}
const newWindows = state.windows.map((win) => {
if (win.windowId !== windowId) return win;
@ -264,8 +213,14 @@ export default function windows(
open: false,
};
});
const someFullscreen = newWindows.some(
(win) => win.fullscreen && win.open,
);
return {
...state,
someFullscreen,
windows: newWindows,
};
}
@ -281,16 +236,14 @@ export default function windows(
open: false,
};
});
let { modal } = state;
if (modal.open && modal.windowType === windowType) {
modal = {
...modal,
open: false,
};
}
const someFullscreen = newWindows.some(
(win) => win.fullscreen && win.open,
);
return {
...state,
modal,
someFullscreen,
windows: newWindows,
};
}
@ -307,16 +260,8 @@ export default function windows(
hidden: hide,
};
});
let { modal } = state;
if (hide && modal.open && modal.windowType === windowType) {
modal = {
...modal,
open: false,
};
}
return {
...state,
modal,
windows: newWindows,
};
}
@ -366,17 +311,6 @@ export default function windows(
...action.args,
},
};
if (windowId === 0) {
return {
...state,
args,
modal: {
...state.modal,
windowType,
title,
},
};
}
const newWindows = state.windows.map((win) => {
if (win.windowId !== windowId) return win;
return {
@ -385,8 +319,14 @@ export default function windows(
title,
};
});
const someFullscreen = newWindows.some(
(win) => win.fullscreen && win.open,
);
return {
...state,
someFullscreen,
args,
windows: newWindows,
};
@ -423,89 +363,48 @@ export default function windows(
});
}
case 'MAXIMIZE_WINDOW': {
case 'TOGGLE_MAXIMIZE_WINDOW': {
const {
windowId,
} = action;
const args = {
...state.args,
0: state.args[windowId],
};
const {
windowType,
title,
xPos,
yPos,
width,
height,
cloneable,
} = state.windows
.find((w) => w.windowId === windowId);
delete args[windowId];
const newWindows = state.windows.map((win) => {
if (win.windowId !== windowId) return win;
return {
...win,
fullscreen: !win.fullscreen,
open: true,
hidden: false,
};
});
const someFullscreen = newWindows.some(
(win) => win.fullscreen && win.open,
);
return {
...state,
modal: {
windowType,
title,
open: true,
prevWinSize: {
xPos,
yPos,
width,
height,
cloneable,
},
},
windows: state.windows.filter((w) => w.windowId !== windowId),
args,
someFullscreen,
windows: newWindows,
};
}
case 'RESTORE_WINDOW': {
const windowId = generateWindowId(state);
const { windowType, title, prevWinSize } = state.modal;
const [width, height] = clampSize(
prevWinSize.width,
prevWinSize.height,
);
const [xPos, yPos] = clampPos(
prevWinSize.xPos,
prevWinSize.yPos,
width,
height,
);
const cloneable = prevWinSize.cloneable || true;
const newZMax = state.zMax + 1;
return sortWindows({
...state,
zMax: newZMax,
modal: {
...state.modal,
open: false,
},
windows: [
...state.windows,
{
windowType,
windowId,
open: true,
hidden: false,
title,
width,
height,
xPos,
yPos,
z: newZMax,
cloneable,
},
],
args: {
...state.args,
[windowId]: {
...state.args[0],
},
},
case 'CLOSE_FULLSCREEN_WINDOWS': {
const newWindows = state.windows.map((win) => {
if (win.fullscreen) {
return {
...win,
open: false,
};
}
return win;
});
return {
...state,
someFullscreen: false,
windows: newWindows,
};
}
case 'MOVE_WINDOW': {
@ -576,8 +475,8 @@ export default function windows(
const xMax = width - SCREEN_MARGIN_EW;
const yMax = height - SCREEN_MARGIN_S;
let modified = false;
let newWindows = [];
for (let i = 0; i < state.windows.length; i += 1) {
const win = state.windows[i];
const {
@ -613,12 +512,17 @@ export default function windows(
return false;
});
return {
const someFullscreen = state.windows.some(
(win) => win.fullscreen && win.open,
);
return sortWindows({
...state,
someFullscreen,
showWindows: true,
windows: newWindows,
args,
};
}, true);
}
return {

View File

@ -185,17 +185,6 @@ tr:nth-child(even) {
z-index: 3;
}
.window {
position: fixed;
background-color: rgba(252, 252, 252, 0.95);
border: solid black;
border-width: thin;
overflow: hidden;
padding: 3px;
transition: opacity 200ms ease-in-out;
opacity: 0;
}
.win-topbar {
display: flex;
height: 24px;
@ -485,7 +474,7 @@ tr:nth-child(even) {
padding: 0;
}
.Modal, .Alert {
.modal, .Alert {
position: fixed;
top: 50%;
left: 50%;
@ -501,14 +490,25 @@ tr:nth-child(even) {
opacity: 0;
}
.Modal {
.modal {
height: 80%;
width: 70%;
max-height: 900px;
z-index: 5;
}
.Modal-content {
.window {
position: fixed;
background-color: rgba(252, 252, 252, 0.95);
border: solid black;
border-width: thin;
overflow: hidden;
padding: 3px;
transition: opacity 200ms ease-in-out;
opacity: 0;
}
.modal-content {
position: relative;
width: calc(100% - 3px);
height: calc(100% - 50px);
@ -632,7 +632,7 @@ tr:nth-child(even) {
}
@media (max-width: 604px) {
.Modal, .Alert {
.modal, .Alert {
position: fixed;
top: 0px;
left: 0px;
@ -647,7 +647,7 @@ tr:nth-child(even) {
}
}
.OverlayModal, .OverlayAlert {
.overlay {
position: fixed;
top: 0px;
left: 0px;
@ -658,14 +658,6 @@ tr:nth-child(even) {
transition: opacity 200ms ease-in-out;
}
.OverlayModal {
z-index: 4;
}
.OverlayAlert {
z-index: 6;
}
.chatbox div .chatarea {
height: 174px;
}
@ -948,7 +940,7 @@ tr:nth-child(even) {
visibility: hidden;
}
.Modal.show, .Alert.show, .OverlayAlert.show, .OverlayModal.show, .window.show {
.modal.show, .Alert.show, .overlay.show, .window.show {
opacity: 1;
}

View File

@ -11,7 +11,7 @@ tr:nth-child(odd) {
border-radius: 10px;
}
.OverlayModal, .OverlayAlert {
.overlay {
background: linear-gradient(175deg, #61dceaab , #ffb1e1, #ecffec, #ffb1e1, #61dceaab);
}
@ -51,7 +51,7 @@ tr:nth-child(odd) {
background: linear-gradient(135deg, orange , yellow, green, aqua, blue, violet);
}
.Modal {
.modal {
background: #f4edf0 none repeat scroll 0 0;
background-image: url("../jew.png");
background-repeat: no-repeat;

View File

@ -86,12 +86,12 @@ tr:nth-child(even) {
background-color: #15374fd1;
}
.Modal, .Alert {
.modal, .Alert {
background: #444242 none repeat scroll 0 0;;
color: #f4f4f4;
}
.Modal {
.modal {
border-radius: 21px;
}
@ -132,7 +132,7 @@ tr:nth-child(even) {
background-color: #6f6f75;
}
.OverlayModal, .OverlayAlert {
.overlay {
background-color: rgba(187, 187, 187, 0.75);
}

View File

@ -91,12 +91,12 @@ tr:nth-child(even) {
border-top: thin solid #ffa14c;
}
.Modal, .Alert {
.modal, .Alert {
background: #262626 none repeat scroll 0 0;;
color: #ff8c22;
}
.Modal {
.modal {
border-radius: 15px;
}
@ -137,7 +137,7 @@ tr:nth-child(even) {
background-color: #6f6f75;
}
.OverlayModal, .OverlayAlert {
.overlay {
background-color: rgba(187, 187, 187, 0.75);
}

View File

@ -65,7 +65,7 @@ tr:nth-child(even) {
background-color: #15374fd1;
}
.Modal, .Alert {
.modal, .Alert {
background: #444242 none repeat scroll 0 0;;
color: #f4f4f4;
}
@ -117,7 +117,7 @@ tr:nth-child(even) {
background-color: #6f6f75;
}
.OverlayModal, .OverlayAlert {
.overlay {
background-color: rgba(187, 187, 187, 0.75);
}

View File

@ -14,7 +14,7 @@
border-radius: 21px;
}
.Modal {
.modal {
border-radius: 21px;
}