move windows by zIndex instead of rearranging them, to keep scroll positions

This commit is contained in:
HF 2021-05-02 15:31:57 +02:00
parent 403a5493e5
commit a2ca757e0b
7 changed files with 93 additions and 44 deletions

View File

@ -52,6 +52,7 @@ const Window = ({ id }) => {
width, height, width, height,
xPos, yPos, xPos, yPos,
windowType, windowType,
z,
title, title,
open, open,
hidden, hidden,
@ -104,6 +105,7 @@ const Window = ({ id }) => {
top: yPos, top: yPos,
width, width,
height, height,
zIndex: z,
}} }}
> >
<div <div

View File

@ -11,15 +11,19 @@ import Window from './Window';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const selectWindowIds = (state) => state.windows.windows.map((win) => win.windowId); const selectWindowIds = (state) => state.windows.windows.map((win) => win.windowId);
const WindowsRoot = () => { const WindowManager = () => {
const windowIds = useSelector(selectWindowIds, shallowEqual); const windowIds = useSelector(selectWindowIds, shallowEqual);
const showWindows = useSelector((state) => state.windows.showWindows); const showWindows = useSelector((state) => state.windows.showWindows);
if (!showWindows) return null; if (!showWindows) return null;
return windowIds.map((id) => ( return (
<Window key={id} id={id} /> <div id="wm">
)); {
windowIds.map((id) => (<Window key={id} id={id} />))
}
</div>
);
}; };
export default WindowsRoot; export default WindowManager;

View File

@ -15,7 +15,7 @@ function useDrag(elRef, startHandler, diffHandler) {
const startDrag = useCallback((event) => { const startDrag = useCallback((event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
startHandler(); startHandler && startHandler();
let { let {
clientX: startX, clientX: startX,

View File

@ -15,7 +15,7 @@ const imageStyle = {
}; };
const Archive = () => ( const Archive = () => (
<p style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}> <div style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}>
<p className="modaltext"> <p className="modaltext">
{t`While we tend to not delete canvases, some canvases are started for fun or as a request by users who currently like a meme. \ {t`While we tend to not delete canvases, some canvases are started for fun or as a request by users who currently like a meme. \
Those canvases can get boring after a while and after weeks of no major change and if they really aren't worth being kept active, we decide to remove them.`}<br /> Those canvases can get boring after a while and after weeks of no major change and if they really aren't worth being kept active, we decide to remove them.`}<br />
@ -42,7 +42,7 @@ Those canvases can get boring after a while and after weeks of no major change a
alt="political-compass" alt="political-compass"
src="https://storage.pixelplanet.fun/compass-final.png" src="https://storage.pixelplanet.fun/compass-final.png"
/> />
</p> </div>
); );
export default Archive; export default Archive;

View File

@ -21,7 +21,7 @@ const CanvasSelect = ({ windowId }) => {
[dispatch]); [dispatch]);
return ( return (
<p style={{ <div style={{
textAlign: 'center', textAlign: 'center',
paddingLeft: '5%', paddingLeft: '5%',
paddingRight: '5%', paddingRight: '5%',
@ -51,7 +51,7 @@ const CanvasSelect = ({ windowId }) => {
) )
)) ))
} }
</p> </div>
); );
}; };

View File

@ -15,6 +15,8 @@ const MIN_HEIGHT = 50;
// if screen smaller than this, hide all windows and just // if screen smaller than this, hide all windows and just
// allow Modals // allow Modals
const SCREEN_WIDTH_THRESHOLD = 604; const SCREEN_WIDTH_THRESHOLD = 604;
// how many windows can be open
const MAX_AMOUNT_WINDOWS = 100;
function generateWindowId(state) { function generateWindowId(state) {
let windowId = Math.floor(Math.random() * 99999) + 1; let windowId = Math.floor(Math.random() * 99999) + 1;
@ -24,6 +26,9 @@ function generateWindowId(state) {
return windowId; return windowId;
} }
/*
* clamp size and position to screen borders and restrictions
*/
function clampSize(prefWidth, prefHeight, margin = false) { function clampSize(prefWidth, prefHeight, margin = false) {
const width = prefWidth || 550; const width = prefWidth || 550;
const height = prefHeight || 330; const height = prefHeight || 330;
@ -66,10 +71,29 @@ function clampPos(prefXPos, prefYPos, width, height) {
]; ];
} }
/*
* resort the zIndex, remove gaps
*/
function sortWindows(newState) {
if (newState.zMax >= MAX_AMOUNT_WINDOWS * 0.5) {
const orderedZ = newState.windows.map((win) => win.z)
.sort((a, b) => !b || (a && a >= b));
newState.windows = newState.windows.map((win) => ({
...win,
z: orderedZ.indexOf(win.z),
}));
newState.zMax = orderedZ.length - 1;
}
return newState;
}
export type WindowsState = { export type WindowsState = {
// if windows get shown, false on small screens
showWindows: boolean,
// highest zIndex of window
zMax: number,
// modal is considerd as "fullscreen window" // modal is considerd as "fullscreen window"
// its windowId is considered 0 and args are under args[0] // its windowId is considered 0 and args are under args[0]
showWindows: boolean,
modal: { modal: {
windowType: ?string, windowType: ?string,
title: ?string, title: ?string,
@ -90,6 +114,7 @@ export type WindowsState = {
// windowId: number, // windowId: number,
// open: boolean, // open: boolean,
// hidden: boolean, // hidden: boolean,
// z: number,
// windowType: string, // windowType: string,
// title: string, // title: string,
// width: number, // width: number,
@ -110,6 +135,7 @@ export type WindowsState = {
const initialState: WindowsState = { const initialState: WindowsState = {
showWindows: true, showWindows: true,
zMax: 0,
modal: { modal: {
windowType: null, windowType: null,
title: null, title: null,
@ -168,29 +194,36 @@ export default function windows(
}, },
}; };
} }
if (state.windows.length >= MAX_AMOUNT_WINDOWS) {
return state;
}
const windowId = generateWindowId(state); const windowId = generateWindowId(state);
return { const newZMax = state.zMax + 1;
let newWindows = [
...state.windows,
{
windowId,
windowType,
open: true,
hidden: false,
z: newZMax,
title,
width,
height,
xPos,
yPos,
cloneable,
},
];
return sortWindows({
...state, ...state,
windows: [ zMax: newZMax,
...state.windows, windows: newWindows,
{
windowId,
windowType,
open: true,
hidden: false,
title,
width,
height,
xPos,
yPos,
cloneable,
},
],
args: { args: {
...state.args, ...state.args,
[windowId]: args, [windowId]: args,
}, },
}; });
} }
case 'REMOVE_WINDOW': { case 'REMOVE_WINDOW': {
@ -349,9 +382,7 @@ export default function windows(
}; };
} }
const newWindows = state.windows.map((win) => { const newWindows = state.windows.map((win) => {
if (win.windowId !== windowId) { if (win.windowId !== windowId) return win;
return win;
}
return { return {
...win, ...win,
windowType, windowType,
@ -369,22 +400,30 @@ export default function windows(
windowId, windowId,
} = action; } = action;
const { const {
windows: oldWindows, windows: oldWindows, zMax,
} = state; } = state;
if (oldWindows.length === 0
|| oldWindows[oldWindows.length - 1].windowId === windowId let newWindows = [];
) {
return state; for (let i = 0; i < oldWindows.length; i += 1) {
const win = oldWindows[i];
if (win.windowId !== windowId) {
newWindows.push(win);
} else {
if (win.z === zMax) {
return state;
}
newWindows.push({
...win,
z: zMax + 1,
});
}
} }
const newWindows = oldWindows.filter((w) => w.windowId !== windowId); return sortWindows({
const win = oldWindows.find((w) => w.windowId === windowId);
if (win) {
newWindows.push(win);
}
return {
...state, ...state,
zMax: zMax + 1,
windows: newWindows, windows: newWindows,
}; });
} }
case 'MAXIMIZE_WINDOW': { case 'MAXIMIZE_WINDOW': {

View File

@ -127,6 +127,11 @@ tr:nth-child(even) {
background-color: #dddddd; background-color: #dddddd;
} }
#wm {
position: absolute;
z-index: 3;
}
.window { .window {
position: fixed; position: fixed;
background-color: rgba(252, 252, 252, 0.95); background-color: rgba(252, 252, 252, 0.95);
@ -134,7 +139,6 @@ tr:nth-child(even) {
border-width: thin; border-width: thin;
overflow: hidden; overflow: hidden;
padding: 3px; padding: 3px;
z-index: 3;
transition: opacity 200ms ease-in-out; transition: opacity 200ms ease-in-out;
opacity: 0; opacity: 0;
} }