Updated window rendering
This commit is contained in:
parent
e0c7518070
commit
60a5e5ba30
7 changed files with 94 additions and 40 deletions
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -20,7 +20,6 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-draggable": "^4.4.5",
|
"react-draggable": "^4.4.5",
|
||||||
"react-iframe": "^1.8.5",
|
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-svg": "^16.1.18",
|
"react-svg": "^16.1.18",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|
@ -14853,17 +14852,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
|
||||||
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
|
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
|
||||||
},
|
},
|
||||||
"node_modules/react-iframe": {
|
|
||||||
"version": "1.8.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-iframe/-/react-iframe-1.8.5.tgz",
|
|
||||||
"integrity": "sha512-F4cQJGs3ydaG6fJWfuz9yLwOU0Trzl6kttXuUG+vYwosH8enOOFxZWEDQCSbNVO8ayjfYZeqLxEvdvcsSy4GvA==",
|
|
||||||
"dependencies": {
|
|
||||||
"object-assign": "^4.1.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16.x.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
|
|
||||||
30
package.json
30
package.json
|
|
@ -18,7 +18,6 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-draggable": "^4.4.5",
|
"react-draggable": "^4.4.5",
|
||||||
"react-iframe": "^1.8.5",
|
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-svg": "^16.1.18",
|
"react-svg": "^16.1.18",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|
@ -40,20 +39,31 @@
|
||||||
"jsdoc"
|
"jsdoc"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"indent": ["error", "tab", { "SwitchCase": 1 }],
|
"indent": [
|
||||||
|
"error",
|
||||||
|
"tab",
|
||||||
|
{
|
||||||
|
"SwitchCase": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
"semi": "error",
|
"semi": "error",
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"prefer-const": "error",
|
"prefer-const": "error",
|
||||||
"quotes": ["error", "double"],
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"double"
|
||||||
|
],
|
||||||
"jsdoc/no-undefined-types": "warn",
|
"jsdoc/no-undefined-types": "warn",
|
||||||
"jsdoc/require-param": "warn",
|
"jsdoc/require-param": "warn",
|
||||||
"jsdoc/check-tag-names": "warn",
|
"jsdoc/check-tag-names": "warn",
|
||||||
"jsdoc/check-types": ["warn", {}],
|
"jsdoc/check-types": [
|
||||||
|
"warn",
|
||||||
|
{}
|
||||||
|
],
|
||||||
"jsdoc/check-values": "warn",
|
"jsdoc/check-values": "warn",
|
||||||
"jsdoc/empty-tags": "warn",
|
"jsdoc/empty-tags": "warn",
|
||||||
"jsdoc/check-param-names": "warn",
|
"jsdoc/check-param-names": "warn",
|
||||||
"jsdoc/check-property-names": "warn",
|
"jsdoc/check-property-names": "warn",
|
||||||
"jsdoc/check-access": "warn",
|
"jsdoc/check-access": "warn",
|
||||||
"jsdoc/check-alignment": "warn",
|
"jsdoc/check-alignment": "warn",
|
||||||
"jsdoc/multiline-blocks": "warn",
|
"jsdoc/multiline-blocks": "warn",
|
||||||
|
|
@ -63,10 +73,10 @@
|
||||||
"settings": {
|
"settings": {
|
||||||
"jsdoc": {
|
"jsdoc": {
|
||||||
"preferredTypes": {
|
"preferredTypes": {
|
||||||
"Object":"object",
|
"Object": "object",
|
||||||
"object.<>":"Object<>",
|
"object.<>": "Object<>",
|
||||||
"Object.<>":"Object<>",
|
"Object.<>": "Object<>",
|
||||||
"object<>":"Object<>"
|
"object<>": "Object<>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,47 @@
|
||||||
import Iframe from "react-iframe";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import styles from "./WebView.module.css";
|
import styles from "./WebView.module.css";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} props
|
* @param {Object} props
|
||||||
* @param {String} props.source
|
* @param {String} props.source
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
export function WebView(props) {
|
export function WebView(props) {
|
||||||
|
const [hovered, setHovered] = useState(false);
|
||||||
|
|
||||||
|
const { source, focus } = props;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.focus();
|
||||||
|
|
||||||
|
const onBlur = (event) => {
|
||||||
|
if (hovered) {
|
||||||
|
focus(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("blur", onBlur);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("blur", onBlur);
|
||||||
|
};
|
||||||
|
}, [hovered]);
|
||||||
|
|
||||||
|
const onMouseOver = () => {
|
||||||
|
setHovered(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseOut = () => {
|
||||||
|
window.focus();
|
||||||
|
setHovered(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Iframe url={props.source} className={styles["Web-view"]} {...props}/>
|
<div className={styles.Container} onMouseOver={onMouseOver} onMouseOut={onMouseOut}>
|
||||||
|
<iframe
|
||||||
|
src={source}
|
||||||
|
className={styles["Web-view"]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
.Container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.Web-view {
|
.Web-view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@ import { faMinus, faWindowMaximize as fasWindowMaximize, faXmark } from "@fortaw
|
||||||
import { ReactSVG } from "react-svg";
|
import { ReactSVG } from "react-svg";
|
||||||
import { useWindowsManager } from "../../hooks/windows/WindowsManagerContext.js";
|
import { useWindowsManager } from "../../hooks/windows/WindowsManagerContext.js";
|
||||||
import Draggable from "react-draggable";
|
import Draggable from "react-draggable";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { memo, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import Application from "../../features/applications/application.js";
|
import Application from "../../features/applications/application.js";
|
||||||
|
|
||||||
import Vector2 from "../../features/math/vector2.js";
|
import Vector2 from "../../features/math/vector2.js";
|
||||||
import { faWindowMaximize } from "@fortawesome/free-regular-svg-icons";
|
import { faWindowMaximize } from "@fortawesome/free-regular-svg-icons";
|
||||||
|
|
||||||
|
|
@ -21,7 +19,7 @@ import { faWindowMaximize } from "@fortawesome/free-regular-svg-icons";
|
||||||
* @param {Function} props.onInteract
|
* @param {Function} props.onInteract
|
||||||
* @param {object} props.options
|
* @param {object} props.options
|
||||||
*/
|
*/
|
||||||
export function Window({ id, app, size, position, focused = false, onInteract, options }) {
|
export const Window = memo(function Window({ id, app, size, position, focused = false, onInteract, options }) {
|
||||||
const windowsManager = useWindowsManager();
|
const windowsManager = useWindowsManager();
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
|
|
||||||
|
|
@ -72,12 +70,15 @@ export function Window({ id, app, size, position, focused = false, onInteract, o
|
||||||
windowsManager.close(id);
|
windowsManager.close(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const focus = (event) => {
|
const focus = (event, force = false) => {
|
||||||
|
if (force)
|
||||||
|
return onInteract();
|
||||||
|
|
||||||
if (event.defaultPrevented)
|
if (event.defaultPrevented)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((event.target.closest(".Handle") == null || event.target.closest("button") == null))
|
if (event.target?.closest?.(".Handle") == null || event.target?.closest?.("button") == null)
|
||||||
onInteract(event);
|
onInteract();
|
||||||
};
|
};
|
||||||
|
|
||||||
const classNames = [styles["Window-container"]];
|
const classNames = [styles["Window-container"]];
|
||||||
|
|
@ -86,8 +87,11 @@ export function Window({ id, app, size, position, focused = false, onInteract, o
|
||||||
if (minimized)
|
if (minimized)
|
||||||
classNames.push(styles.Minimized);
|
classNames.push(styles.Minimized);
|
||||||
|
|
||||||
|
// console.log(`Rendering window: ${id}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable
|
<Draggable
|
||||||
|
key={id}
|
||||||
axis="both"
|
axis="both"
|
||||||
handle={".Handle"}
|
handle={".Handle"}
|
||||||
defaultPosition={startPosition}
|
defaultPosition={startPosition}
|
||||||
|
|
@ -122,17 +126,21 @@ export function Window({ id, app, size, position, focused = false, onInteract, o
|
||||||
<button title="Minimize" tabIndex={0} onClick={() => setMinimized(!minimized)}>
|
<button title="Minimize" tabIndex={0} onClick={() => setMinimized(!minimized)}>
|
||||||
<FontAwesomeIcon icon={faMinus}/>
|
<FontAwesomeIcon icon={faMinus}/>
|
||||||
</button>
|
</button>
|
||||||
<button title="Maximize" tabIndex={0} onClick={() => setMaximized(!maximized)}>
|
<button title="Maximize" tabIndex={0} id="maximize-window" onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
setMaximized(!maximized);
|
||||||
|
focus(event, true);
|
||||||
|
}}>
|
||||||
<FontAwesomeIcon icon={maximized ? fasWindowMaximize : faWindowMaximize}/>
|
<FontAwesomeIcon icon={maximized ? fasWindowMaximize : faWindowMaximize}/>
|
||||||
</button>
|
</button>
|
||||||
<button title="Close" tabIndex={0} id="close-window" onClick={close}>
|
<button title="Close" tabIndex={0} id="close-window" onClick={close}>
|
||||||
<FontAwesomeIcon icon={faXmark}/>
|
<FontAwesomeIcon icon={faXmark}/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles["Window-content"]}>
|
<div className={styles["Window-content"]} onClick={(event) => { console.log(event); }}>
|
||||||
<app.WindowContent {...options} setTitle={setTitle} close={close}/>
|
<app.WindowContent {...options} setTitle={setTitle} close={close} focus={focus}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
import { Window } from "./Window.jsx";
|
import { Window } from "./Window.jsx";
|
||||||
import { useWindows } from "../../hooks/windows/WindowsContext.js";
|
import { useWindows } from "../../hooks/windows/WindowsContext.js";
|
||||||
import { useWindowsManager } from "../../hooks/windows/WindowsManagerContext.js";
|
import { useWindowsManager } from "../../hooks/windows/WindowsManagerContext.js";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export function WindowsView() {
|
export function WindowsView() {
|
||||||
const windows = useWindows();
|
const windows = useWindows();
|
||||||
const windowsManager = useWindowsManager();
|
const windowsManager = useWindowsManager();
|
||||||
|
const [sortedWindows, setSortedWindows] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSortedWindows([...windows].sort((windowA, windowB) =>
|
||||||
|
windowA.lastInteraction - windowB.lastInteraction
|
||||||
|
));
|
||||||
|
}, [windows]);
|
||||||
|
|
||||||
// TO DO: prevent windows from being rerendered when order is changed
|
// TO DO: prevent windows from being rerendered when order is changed
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
{windows.sort((windowA, windowB) =>
|
{sortedWindows.map(({ id, app, size, position, options }) =>
|
||||||
windowA.lastInteraction - windowB.lastInteraction
|
|
||||||
).map(({ id, app, size, position, options }) =>
|
|
||||||
<Window
|
<Window
|
||||||
onInteract={() => { windowsManager.focus(id); }}
|
onInteract={() => { windowsManager.focus(id); }}
|
||||||
id={id}
|
id={id}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export default class ApplicationsManager {
|
||||||
new Application("Terminal", "terminal", Terminal),
|
new Application("Terminal", "terminal", Terminal),
|
||||||
new Application("Settings", "settings", Settings),
|
new Application("Settings", "settings", Settings),
|
||||||
// new Application("Browser", "browser"),
|
// new Application("Browser", "browser"),
|
||||||
new Application("Calculator", "calculator", Calculator, { size: new Vector2(400, 600) }),
|
// new Application("Calculator", "calculator", Calculator, { size: new Vector2(400, 600) }),
|
||||||
new Application("Text Editor", "text-editor", TextEditor),
|
new Application("Text Editor", "text-editor", TextEditor),
|
||||||
// new Application("Code Editor", "code-editor"),
|
// new Application("Code Editor", "code-editor"),
|
||||||
new Application("File Explorer", "file-explorer", FileExplorer),
|
new Application("File Explorer", "file-explorer", FileExplorer),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue