Fixed bugs related to modals

This commit is contained in:
Prozilla 2023-12-13 12:07:41 +01:00
parent 75666e7135
commit d73db00326
No known key found for this signature in database
GPG key ID: 5858DFE71CAF31EE
20 changed files with 105 additions and 45 deletions

View file

@ -5,34 +5,34 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowUp, faCaretLeft, faCaretRight, faCog, faDesktop, faFileLines, faHouse, faImage, faPlus, faSearch } from "@fortawesome/free-solid-svg-icons"; import { faArrowUp, faCaretLeft, faCaretRight, faCog, faDesktop, faFileLines, faHouse, faImage, faPlus, faSearch } from "@fortawesome/free-solid-svg-icons";
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js"; import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js";
import { useContextMenu } from "../../../hooks/modals/contextMenu.js"; import { useContextMenu } from "../../../hooks/modals/contextMenu.js";
import { useModals } from "../../../hooks/modals/modals.js";
import { ModalsView } from "../../modals/ModalsView.jsx";
import { QuickAccessButton } from "./QuickAccessButton.jsx"; import { QuickAccessButton } from "./QuickAccessButton.jsx";
import { useDialogBox } from "../../../hooks/modals/dialogBox.js"; import { useDialogBox } from "../../../hooks/modals/dialogBox.js";
import Vector2 from "../../../features/math/vector2.js"; import Vector2 from "../../../features/math/vector2.js";
import { DIALOG_CONTENT_TYPES } from "../../../constants/modals.js"; import { DIALOG_CONTENT_TYPES } from "../../../constants/modals.js";
import { DirectoryList } from "./directory-list/DirectoryList.jsx"; import { DirectoryList } from "./directory-list/DirectoryList.jsx";
export function FileExplorer({ startPath, app }) { /**
* @param {import("../../windows/WindowView.jsx").windowProps} props
*/
export function FileExplorer({ startPath, app, modalsManager }) {
const virtualRoot = useVirtualRoot(); const virtualRoot = useVirtualRoot();
const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~")); const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~"));
const [path, setPath] = useState(currentDirectory?.path ?? ""); const [path, setPath] = useState(currentDirectory?.path ?? "");
const windowsManager = useWindowsManager(); const windowsManager = useWindowsManager();
const [showHidden] = useState(true); const [showHidden] = useState(true);
const [modalsManager, modals] = useModals();
const { onContextMenu: onContextMenuFile } = useContextMenu({ const { onContextMenu: onContextMenuFile } = useContextMenu({
modalsManager, modalsManager,
options: { options: {
"Open": ({ file }) => { windowsManager.openFile(file); }, "Open": (file) => { file.open(windowsManager); },
"Delete": ({ file }) => { file.delete(); }, "Delete": (file) => { file.delete(); },
} }
}); });
const { onContextMenu: onContextMenuFolder } = useContextMenu({ const { onContextMenu: onContextMenuFolder } = useContextMenu({
modalsManager, modalsManager,
options: { options: {
"Open": ({ name }) => { changeDirectory(name); }, "Open": (folder) => { changeDirectory(folder.name); },
"Delete": ({ name }) => { currentDirectory.findSubFolder(name)?.delete(); } "Delete": (folder) => { folder.delete(); }
} }
}); });
// const { onContextMenu: onNew } = useContextMenu({ // const { onContextMenu: onNew } = useContextMenu({
@ -78,7 +78,6 @@ export function FileExplorer({ startPath, app }) {
return ( return (
<div className={styles.Container}> <div className={styles.Container}>
<ModalsView modalsManager={modalsManager} modals={modals}/>
<div className={styles.Header}> <div className={styles.Header}>
<button title="Back" tabIndex={0} className={styles["Icon-button"]}> <button title="Back" tabIndex={0} className={styles["Icon-button"]}>
<FontAwesomeIcon icon={faCaretLeft}/> <FontAwesomeIcon icon={faCaretLeft}/>

View file

@ -1,15 +1,11 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js";
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js"; import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js";
import styles from "./MediaViewer.module.css"; import styles from "./MediaViewer.module.css";
import { APPS } from "../../../constants/applications.js"; import { APPS } from "../../../constants/applications.js";
/** /**
* @param {object} props * @param {import("../../windows/WindowView.jsx").windowProps} props
* @param {VirtualFile} props.file
* @param {Function} props.close
* @param {Function} props.setTitle
*/ */
export function MediaViewer({ file, close, setTitle }) { export function MediaViewer({ file, close, setTitle }) {
const windowsManager = useWindowsManager(); const windowsManager = useWindowsManager();

View file

@ -8,8 +8,7 @@ import { AboutSettings } from "./AboutSettings.jsx";
import { StorageTab } from "./StorageSettings.jsx"; import { StorageTab } from "./StorageSettings.jsx";
/** /**
* @param {object} props * @param {import("../../windows/WindowView.jsx").windowProps} props
* @param {number} props.initialTabIndex
*/ */
export function Settings({ initialTabIndex }) { export function Settings({ initialTabIndex }) {
return ( return (

View file

@ -8,6 +8,9 @@ import { HOSTNAME, USERNAME } from "../../../constants/applications/terminal.js"
import CommandsManager from "../../../features/applications/terminal/commands.js"; import CommandsManager from "../../../features/applications/terminal/commands.js";
import { removeFromArray } from "../../../features/utils/array.js"; import { removeFromArray } from "../../../features/utils/array.js";
/**
* @param {import("../../windows/WindowView.jsx").windowProps} props
*/
export function Terminal({ setTitle, close: exit }) { export function Terminal({ setTitle, close: exit }) {
const [inputKey, setInputKey] = useState(0); const [inputKey, setInputKey] = useState(0);
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");

View file

@ -1,20 +1,12 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js";
import styles from "./TextEditor.module.css"; import styles from "./TextEditor.module.css";
import { HeaderMenu } from "../.common/HeaderMenu.jsx"; import { HeaderMenu } from "../.common/HeaderMenu.jsx";
import Markdown from "markdown-to-jsx"; import Markdown from "markdown-to-jsx";
import Application from "../../../features/applications/application.js";
import { DEFAULT_ZOOM, ZOOM_FACTOR } from "../../../constants/applications/textEditor.js"; import { DEFAULT_ZOOM, ZOOM_FACTOR } from "../../../constants/applications/textEditor.js";
import AppsManager from "../../../features/applications/applications.js"; import AppsManager from "../../../features/applications/applications.js";
/** /**
* @param {object} props * @param {import("../../windows/WindowView.jsx").windowProps} props
* @param {VirtualFile} props.file
* @param {Function} props.setTitle
* @param {Function} props.close
* @param {string} props.mode
* @param {Application} props.app
* @param {Function} props.setIconUrl
*/ */
export function TextEditor({ file, setTitle, setIconUrl, close, mode, app }) { export function TextEditor({ file, setTitle, setIconUrl, close, mode, app }) {
const [currentFile, setCurrentFile] = useState(file); const [currentFile, setCurrentFile] = useState(file);
@ -40,7 +32,6 @@ export function TextEditor({ file, setTitle, setIconUrl, close, mode, app }) {
} }
const iconUrl = currentFile.getIconUrl(); const iconUrl = currentFile.getIconUrl();
console.log(iconUrl);
if (iconUrl) if (iconUrl)
setIconUrl(iconUrl); setIconUrl(iconUrl);
} else { } else {

View file

@ -11,7 +11,7 @@ import { FALLBACK_WALLPAPER } from "../../constants/desktop.js";
import { reloadViewport } from "../../features/utils/browser.js"; import { reloadViewport } from "../../features/utils/browser.js";
import { useVirtualRoot } from "../../hooks/virtual-drive/virtualRootContext.js"; import { useVirtualRoot } from "../../hooks/virtual-drive/virtualRootContext.js";
import { DirectoryList } from "../applications/file-explorer/directory-list/DirectoryList.jsx"; import { DirectoryList } from "../applications/file-explorer/directory-list/DirectoryList.jsx";
import { APPS } from "../../constants/applications.js"; import { APPS, APP_NAMES } from "../../constants/applications.js";
import Vector2 from "../../features/math/vector2.js"; import Vector2 from "../../features/math/vector2.js";
export const Desktop = memo(() => { export const Desktop = memo(() => {
@ -20,12 +20,35 @@ export const Desktop = memo(() => {
const [modalsManager, modals] = useModals(); const [modalsManager, modals] = useModals();
const windowsManager = useWindowsManager(); const windowsManager = useWindowsManager();
const virtualRoot = useVirtualRoot(); const virtualRoot = useVirtualRoot();
const { onContextMenu } = useContextMenu({ const { onContextMenu } = useContextMenu({
modalsManager, modalsManager,
options: { options: {
"Refresh": () => { reloadViewport(); }, "Refresh": () => { reloadViewport(); },
"Change appearance": () => { windowsManager.open("settings", { initialTabIndex: 0 }); }, "Change appearance": () => { windowsManager.open("settings", { initialTabIndex: 0 }); },
"Open in Files": () => { windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Desktop" }); }, [`Open in ${APP_NAMES.FILE_EXPLORER}`]: () => {
windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Desktop" });
},
}
});
const { onContextMenu: onContextMenuFile } = useContextMenu({
modalsManager,
options: {
"Open": (file) => { file.open(windowsManager); },
[`Reveal in ${APP_NAMES.FILE_EXPLORER}`]: (file) => {
windowsManager.open(APPS.FILE_EXPLORER, { startPath: file.parent.path });
},
"Delete": (file) => { file.delete(); },
}
});
const { onContextMenu: onContextMenuFolder } = useContextMenu({
modalsManager,
options: {
"Open": (folder) => { folder.open(windowsManager); },
[`Reveal in ${APP_NAMES.FILE_EXPLORER}`]: (folder) => {
windowsManager.open(APPS.FILE_EXPLORER, { startPath: folder.parent.path });
},
"Delete": (folder) => { folder.delete(); },
} }
}); });
@ -68,6 +91,8 @@ export const Desktop = memo(() => {
onClickFolder={(event, { linkedPath, path }) => { onClickFolder={(event, { linkedPath, path }) => {
windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path }); windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path });
}} }}
onContextMenuFile={onContextMenuFile}
onContextMenuFolder={onContextMenuFolder}
/> />
</div> </div>
{wallpaper {wallpaper

View file

@ -65,10 +65,10 @@ export function DialogBox({ modal, params }) {
position={null} position={null}
scale={1} scale={1}
bounds={{ bounds={{
top: 0, top: -modal.position.y - 1,
bottom: screenHeight - 55, bottom: screenHeight - 55 - modal.position.y,
left: -modal.size.x + 85, left: -modal.size.x + 85 - modal.position.x,
right: screenWidth - 5 right: screenWidth - 5 - modal.position.x
}} }}
cancel="button" cancel="button"
nodeRef={nodeRef} nodeRef={nodeRef}

View file

@ -7,9 +7,7 @@
flex-direction: column; flex-direction: column;
min-width: 300px; min-width: 300px;
min-height: 150px; min-height: 150px;
background-color: var(--background-color-c); background-color: var(--background-color-c) !important;
border-radius: 0.5rem;
box-shadow: var(--window-box-shadow);
resize: both; resize: both;
overflow: hidden; overflow: hidden;
} }

View file

@ -14,6 +14,17 @@ import { ModalsView } from "../modals/ModalsView.jsx";
import { useContextMenu } from "../../hooks/modals/contextMenu.js"; import { useContextMenu } from "../../hooks/modals/contextMenu.js";
import AppsManager from "../../features/applications/applications.js"; import AppsManager from "../../features/applications/applications.js";
/**
* @typedef {object} windowProps
* @property {Application} app
* @property {Function} setTitle
* @property {Function} setIconUrl
* @property {Function} close
* @property {Function} focus
* @property {boolean} active
* @property {import("../../features/modals/modals.js").default} modalsManager
*/
/** /**
* @param {object} props * @param {object} props
* @param {string} props.id * @param {string} props.id
@ -172,6 +183,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,
close={close} close={close}
focus={focus} focus={focus}
active={active} active={active}
modalsManager={modalsManager}
/> />
</div> </div>
</div> </div>

View file

@ -5,3 +5,11 @@ export const APPS = {
TEXT_EDITOR: "text-editor", TEXT_EDITOR: "text-editor",
FILE_EXPLORER: "file-explorer" FILE_EXPLORER: "file-explorer"
}; };
export const APP_NAMES = {
TERMINAL: "Commands",
SETTINGS: "Settings",
MEDIA_VIEWER: "Photos",
TEXT_EDITOR: "Notes",
FILE_EXPLORER: "Files"
};

View file

@ -42,11 +42,11 @@ export default class ModalsManager {
modalId = modalId.toString(); modalId = modalId.toString();
if (!this.modalIds.includes(modalId)) { if (!this.modalIds.includes(modalId)) {
console.log(`Failed to close modal ${modalId}: modal not found`); console.warn(`Failed to close modal ${modalId}: modal not found`);
return; return;
} }
console.log(`Closing modal ${modalId}`); console.info(`Closing modal ${modalId}`);
delete this.modals[modalId]; delete this.modals[modalId];
if (sendModalsUpdate) if (sendModalsUpdate)
@ -60,7 +60,7 @@ export default class ModalsManager {
modalId = modalId.toString(); modalId = modalId.toString();
if (!this.modalIds.includes(modalId)) { if (!this.modalIds.includes(modalId)) {
console.log(`Failed to focus modal ${modalId}: modal not found`); console.warn(`Failed to focus modal ${modalId}: modal not found`);
return; return;
} }

View file

@ -98,6 +98,11 @@ export class VirtualFileLink extends VirtualFile {
return this.isValid() ? this.linkedFile.id : null; return this.isValid() ? this.linkedFile.id : null;
} }
/** @type {VirtualFile["open"]} */
open(...args) {
if (this.isValid()) return this.linkedFile.open(...args);
}
/** @type {VirtualFile["read"]} */ /** @type {VirtualFile["read"]} */
read(...args) { read(...args) {
if (this.isValid()) return this.linkedFile.read(...args); if (this.isValid()) return this.linkedFile.read(...args);

View file

@ -130,4 +130,9 @@ export class VirtualFolderLink extends VirtualFolder {
getSubFolders(...args) { getSubFolders(...args) {
if (this.isValid()) return this.linkedFolder.getSubFolders(...args); if (this.isValid()) return this.linkedFolder.getSubFolders(...args);
} }
/** @type {VirtualFolder["open"]} */
open(...args) {
if (this.isValid()) return this.linkedFolder.open(...args);
}
} }

View file

@ -94,8 +94,6 @@ export class VirtualBase extends EventEmitter {
if (!this.canBeEdited) if (!this.canBeEdited)
return; return;
console.log(this);
const parent = this.parent; const parent = this.parent;
if (parent == null) if (parent == null)

View file

@ -1,3 +1,4 @@
import WindowsManager from "../windows/windows.js";
import { VirtualBase } from "./virtualBase.js"; import { VirtualBase } from "./virtualBase.js";
/** /**
@ -72,6 +73,14 @@ export class VirtualFile extends VirtualBase {
return `${this.name}.${this.extension}`; return `${this.name}.${this.extension}`;
} }
/**
* Opens this file in an app associated with its extension
* @param {WindowsManager} windowsManager
*/
open(windowsManager) {
return windowsManager.openFile(this);
}
/** /**
* @returns {Promise<string | null>} * @returns {Promise<string | null>}
*/ */

View file

@ -1,4 +1,6 @@
import { APPS } from "../../constants/applications.js";
import { removeFromArray } from "../utils/array.js"; import { removeFromArray } from "../utils/array.js";
import WindowsManager from "../windows/windows.js";
import { VirtualFileLink } from "./VirtualFileLink.js"; import { VirtualFileLink } from "./VirtualFileLink.js";
import { VirtualFolderLink } from "./VirtualFolderLink.js"; import { VirtualFolderLink } from "./VirtualFolderLink.js";
import { VirtualBase } from "./virtualBase.js"; import { VirtualBase } from "./virtualBase.js";
@ -339,6 +341,14 @@ export class VirtualFolder extends VirtualBase {
} }
} }
/**
* Opens this folder in file explorer
* @param {WindowsManager} windowsManager
*/
open(windowsManager) {
return windowsManager.open(APPS.FILE_EXPLORER, { startPath: this.path });
}
/** /**
* Deletes this folder and all its files and sub-folders recursively * Deletes this folder and all its files and sub-folders recursively
*/ */

View file

@ -34,7 +34,7 @@ export default class WindowsManager {
id = id.toString(); id = id.toString();
console.log(`Opening window ${id}:${app.id}`); console.info(`Opening window ${id}:${app.id}`);
this.windows[id] = { this.windows[id] = {
id, id,
@ -56,7 +56,7 @@ export default class WindowsManager {
* @returns {object} * @returns {object}
*/ */
openFile(file, options = {}) { openFile(file, options = {}) {
const app = AppsManager.getFileApp(file.extension); const app = AppsManager.getFileApp(file?.extension);
if (app != null) if (app != null)
return this.open(app.id, { file, ...options }); return this.open(app.id, { file, ...options });
} }
@ -72,7 +72,7 @@ export default class WindowsManager {
return; return;
} }
console.log(`Closing window ${windowId}`); console.info(`Closing window ${windowId}`);
delete this.windows[windowId]; delete this.windows[windowId];
this.updateWindows(this.windows); this.updateWindows(this.windows);

View file

@ -22,6 +22,9 @@ import { useShortcuts } from "../utils/keyboard.js";
export function useContextMenu({ modalsManager, options, shortcuts }) { export function useContextMenu({ modalsManager, options, shortcuts }) {
// Open a new modal when context menu is triggered // Open a new modal when context menu is triggered
const onContextMenu = useCallback((event, params = {}) => { const onContextMenu = useCallback((event, params = {}) => {
event.preventDefault();
event.stopPropagation();
let positionX = (event?.clientX ?? 0); let positionX = (event?.clientX ?? 0);
let positionY = (event?.clientY ?? 0); let positionY = (event?.clientY ?? 0);

View file

@ -12,7 +12,6 @@ export function WindowsProvider({ children, windowsManager }) {
const [windows, setWindows] = useState([]); const [windows, setWindows] = useState([]);
const updateWindows = useCallback((updatedWindows) => { const updateWindows = useCallback((updatedWindows) => {
// console.log(updatedWindows);
setWindows(Object.values(updatedWindows)); setWindows(Object.values(updatedWindows));
}, []); }, []);

View file

@ -1,5 +1,5 @@
import { createContext, useContext } from "react"; import { createContext, useContext } from "react";
import WindowsManager from "../../features/windows/windowsManager.js"; import WindowsManager from "../../features/windows/windows.js";
import { WindowsProvider } from "./windowsContext.js"; import { WindowsProvider } from "./windowsContext.js";
const WindowsManagerContext = createContext(); const WindowsManagerContext = createContext();