Added interactable component
This commit is contained in:
parent
e19d284a91
commit
2fab7d5193
25 changed files with 386 additions and 165 deletions
|
|
@ -60,6 +60,7 @@
|
|||
"error",
|
||||
"double"
|
||||
],
|
||||
"object-curly-spacing": ["warn", "always"],
|
||||
"default-case": "off",
|
||||
"arrow-parens": "error",
|
||||
"space-infix-ops": "warn",
|
||||
|
|
|
|||
15
public/documents/links.md
Normal file
15
public/documents/links.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Links
|
||||
|
||||
**ProzillaOS**
|
||||
|
||||
- GitHub: https://github.com/Prozilla/Prozilla-OS
|
||||
|
||||
**Prozilla**
|
||||
|
||||
- Website: https://prozilla.dev/
|
||||
- Ko-fi: https://ko-fi.com/prozilla
|
||||
|
||||
**Crumbling City**
|
||||
|
||||
- Website: https://daisygames.org/crumbling-city/
|
||||
- Steam page: https://store.steampowered.com/app/1520290/Crumbling_City/
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { useShortcuts } from "../../../hooks/utils/keyboard.js";
|
||||
import { DropdownButton } from "../../utils/DropdownButton.jsx";
|
||||
import { DropdownButton } from "../../utils/dropdown-button/DropdownButton.jsx";
|
||||
import styles from "./HeaderMenu.module.css";
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -112,6 +112,20 @@ export function FileExplorer({ startPath, app, modalsManager }) {
|
|||
|
||||
const directory = virtualRoot.navigate(value);
|
||||
|
||||
if (directory == null) {
|
||||
openWindowedModal({
|
||||
title: "Error",
|
||||
iconUrl: AppsManager.getAppIconUrl(APPS.FILE_EXPLORER),
|
||||
size: new Vector2(300, 150),
|
||||
Modal: (props) =>
|
||||
<DialogBox {...props}>
|
||||
<p>Invalid path: "{value}"</p>
|
||||
<button data-type={DIALOG_CONTENT_TYPES.CloseButton}>Ok</button>
|
||||
</DialogBox>
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentDirectory(directory);
|
||||
setPath(directory.root ? "/" : directory.path);
|
||||
}
|
||||
|
|
@ -185,24 +199,24 @@ export function FileExplorer({ startPath, app, modalsManager }) {
|
|||
<div className={styles.Sidebar}>
|
||||
<QuickAccessButton name={"Home"} onClick={() => { changeDirectory("~"); }} icon={faHouse}/>
|
||||
<QuickAccessButton name={"Desktop"} onClick={() => { changeDirectory("~/Desktop"); }} icon={faDesktop}/>
|
||||
<QuickAccessButton name={"Images"} onClick={() => { changeDirectory("~/Images"); }} icon={faImage}/>
|
||||
<QuickAccessButton name={"Images"} onClick={() => { changeDirectory("~/Pictures"); }} icon={faImage}/>
|
||||
<QuickAccessButton name={"Documents"} onClick={() => { changeDirectory("~/Documents"); }} icon={faFileLines}/>
|
||||
</div>
|
||||
<div id="main" className={styles.Main}>
|
||||
<DirectoryList
|
||||
directory={currentDirectory}
|
||||
showHidden={showHidden}
|
||||
onClickFile={(event, file) => {
|
||||
event.preventDefault();
|
||||
windowsManager.openFile(file);
|
||||
}}
|
||||
onClickFolder={(event, folder) => {
|
||||
changeDirectory(folder.linkedPath ?? folder.name);
|
||||
}}
|
||||
onContextMenuFile={onContextMenuFile}
|
||||
onContextMenuFolder={onContextMenuFolder}
|
||||
/>
|
||||
</div>
|
||||
<DirectoryList
|
||||
directory={currentDirectory}
|
||||
id="main"
|
||||
className={styles.Main}
|
||||
showHidden={showHidden}
|
||||
onClickFile={(event, file) => {
|
||||
event.preventDefault();
|
||||
windowsManager.openFile(file, { mode: "view" });
|
||||
}}
|
||||
onClickFolder={(event, folder) => {
|
||||
changeDirectory(folder.linkedPath ?? folder.name);
|
||||
}}
|
||||
onContextMenuFile={onContextMenuFile}
|
||||
onContextMenuFolder={onContextMenuFolder}
|
||||
/>
|
||||
</div>
|
||||
<span className={styles.Footer}>
|
||||
<p className={utilStyles["Text-light"]}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { VirtualFile } from "../../../../features/virtual-drive/virtualFile.js";
|
||||
import { VirtualFolder } from "../../../../features/virtual-drive/virtualFolder.js";
|
||||
import { Interactable } from "../../../utils/interactable/Interactable.jsx";
|
||||
import styles from "./DirectoryList.module.css";
|
||||
import { ImagePreview } from "./ImagePreview.jsx";
|
||||
|
||||
|
|
@ -19,36 +21,145 @@ import { ImagePreview } from "./ImagePreview.jsx";
|
|||
* @param {object} props
|
||||
* @param {VirtualFolder} props.directory
|
||||
* @param {boolean} props.showHidden
|
||||
* @param {string} props.folderClassname
|
||||
* @param {string} props.fileClassname
|
||||
* @param {string} props.folderClassName
|
||||
* @param {string} props.fileClassName
|
||||
* @param {string} props.className
|
||||
* @param {fileEvent} props.onContextMenuFile
|
||||
* @param {folderEvent} props.onContextMenuFolder
|
||||
* @param {fileEvent} props.onClickFile
|
||||
* @param {folderEvent} props.onClickFolder
|
||||
*/
|
||||
export function DirectoryList({ directory, showHidden = false, folderClassname, fileClassname,
|
||||
onContextMenuFile, onContextMenuFolder, onClickFile, onClickFolder }) {
|
||||
if (!directory)
|
||||
return null;
|
||||
export function DirectoryList({ directory, showHidden = false, folderClassName, fileClassName, className,
|
||||
onContextMenuFile, onContextMenuFolder, onClickFile, onClickFolder, ...props }) {
|
||||
const [selectedFolders, setSelectedFolders] = useState([]);
|
||||
const [selectedFiles, setSelectedFiles] = useState([]);
|
||||
|
||||
const ref = useRef(null);
|
||||
const [rectSelectStart, setRectSelectStart] = useState(null);
|
||||
const [rectSelectEnd, setRectSelectEnd] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
clearSelection();
|
||||
}, [directory]);
|
||||
|
||||
useEffect(() => {
|
||||
const onMoveRectSelect = (event) => {
|
||||
if (rectSelectStart == null)
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
setRectSelectEnd({ x: event.clientX, y: event.clientY });
|
||||
};
|
||||
const onStopRectSelect = (event) => {
|
||||
if (rectSelectStart == null || rectSelectEnd == null) {
|
||||
setRectSelectStart(null);
|
||||
setRectSelectEnd(null);
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
setRectSelectStart(null);
|
||||
setRectSelectEnd(null);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMoveRectSelect);
|
||||
document.addEventListener("pointermove", onMoveRectSelect);
|
||||
document.addEventListener("mouseup", onStopRectSelect);
|
||||
document.addEventListener("pointerup", onStopRectSelect);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", onMoveRectSelect);
|
||||
document.removeEventListener("pointermove", onMoveRectSelect);
|
||||
document.removeEventListener("mouseup", onStopRectSelect);
|
||||
document.removeEventListener("pointerup", onStopRectSelect);
|
||||
};
|
||||
});
|
||||
|
||||
if (!directory)
|
||||
return;
|
||||
|
||||
const clearSelection = () => {
|
||||
setSelectedFolders([]);
|
||||
setSelectedFiles([]);
|
||||
};
|
||||
const selectFolder = (folder, exclusive = false) => {
|
||||
setSelectedFolders(exclusive ? [folder.id] : [...selectedFolders, folder.id]);
|
||||
if (exclusive)
|
||||
setSelectedFiles([]);
|
||||
};
|
||||
const selectFile = (file, exclusive = false) => {
|
||||
setSelectedFiles(exclusive ? [file.id] : [...selectedFiles, file.id]);
|
||||
if (exclusive)
|
||||
setSelectedFolders([]);
|
||||
};
|
||||
|
||||
const onStartRectSelect = (event) => {
|
||||
setRectSelectStart({ x: event.clientX, y: event.clientY });
|
||||
};
|
||||
const getRectSelectStyle = () => {
|
||||
let x, y, width, height = null;
|
||||
const containerRect = ref.current?.getBoundingClientRect();
|
||||
|
||||
if (rectSelectStart.x < rectSelectEnd.x) {
|
||||
x = rectSelectStart.x;
|
||||
width = rectSelectEnd.x - rectSelectStart.x;
|
||||
} else {
|
||||
x = rectSelectEnd.x;
|
||||
width = rectSelectStart.x - rectSelectEnd.x;
|
||||
}
|
||||
if (rectSelectStart.y < rectSelectEnd.y) {
|
||||
y = rectSelectStart.y;
|
||||
height = rectSelectEnd.y - rectSelectStart.y;
|
||||
} else {
|
||||
y = rectSelectEnd.y;
|
||||
height = rectSelectStart.y - rectSelectEnd.y;
|
||||
}
|
||||
|
||||
if (containerRect) {
|
||||
x -= containerRect.x;
|
||||
y -= containerRect.y;
|
||||
}
|
||||
|
||||
|
||||
return { top: y, left: x, width, height };
|
||||
};
|
||||
|
||||
const classNames = [styles.Container];
|
||||
const folderClassNames = [styles["Folder-button"]];
|
||||
const fileClassNames = [styles["File-button"]];
|
||||
|
||||
if (folderClassname)
|
||||
folderClassNames.push(folderClassname);
|
||||
if (fileClassname)
|
||||
fileClassNames.push(fileClassname);
|
||||
if (className)
|
||||
classNames.push(className);
|
||||
if (folderClassName)
|
||||
folderClassNames.push(folderClassName);
|
||||
if (fileClassName)
|
||||
fileClassNames.push(fileClassName);
|
||||
|
||||
return <>
|
||||
return <div
|
||||
ref={ref}
|
||||
className={classNames.join(" ")}
|
||||
onClick={clearSelection}
|
||||
onMouseDown={onStartRectSelect}
|
||||
onPointerDown={onStartRectSelect}
|
||||
{...props}
|
||||
>
|
||||
{rectSelectStart != null && rectSelectEnd != null
|
||||
? <div className={styles["Selection-rect"]} style={getRectSelectStyle()}/>
|
||||
: null
|
||||
}
|
||||
{directory?.getSubFolders(showHidden)?.map((folder) =>
|
||||
<button
|
||||
<Interactable
|
||||
key={folder.id}
|
||||
tabIndex={0}
|
||||
className={folderClassNames.join(" ")}
|
||||
data-selected={selectedFolders.includes(folder.id)}
|
||||
onContextMenu={(event) => {
|
||||
onContextMenuFolder?.(event, folder);
|
||||
}}
|
||||
onClick={(event) => {
|
||||
selectFolder(folder, !event.ctrlKey);
|
||||
}}
|
||||
onDoubleClick={(event) => {
|
||||
onClickFolder?.(event, folder);
|
||||
}}
|
||||
>
|
||||
|
|
@ -56,17 +167,21 @@ export function DirectoryList({ directory, showHidden = false, folderClassname,
|
|||
<ImagePreview source={folder.getIconUrl()}/>
|
||||
</div>
|
||||
<p>{folder.name}</p>
|
||||
</button>
|
||||
</Interactable>
|
||||
)}
|
||||
{directory?.getFiles(showHidden)?.map((file) =>
|
||||
<button
|
||||
<Interactable
|
||||
key={file.id}
|
||||
tabIndex={0}
|
||||
className={fileClassNames.join(" ")}
|
||||
data-selected={selectedFiles.includes(file.id)}
|
||||
onContextMenu={(event) => {
|
||||
onContextMenuFile?.(event, file);
|
||||
}}
|
||||
onClick={(event) => {
|
||||
selectFile(file, !event.ctrlKey);
|
||||
}}
|
||||
onDoubleClick={(event) => {
|
||||
onClickFile?.(event, file);
|
||||
}}
|
||||
>
|
||||
|
|
@ -74,7 +189,7 @@ export function DirectoryList({ directory, showHidden = false, folderClassname,
|
|||
<ImagePreview source={file.getIconUrl()}/>
|
||||
</div>
|
||||
<p>{file.id}</p>
|
||||
</button>
|
||||
</Interactable>
|
||||
)}
|
||||
</>;
|
||||
</div>;
|
||||
}
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
.Container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.File-button, .Folder-button {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
|
|
@ -15,11 +21,16 @@
|
|||
transition: background-color 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.File-button[data-selected=true],
|
||||
.Folder-button[data-selected=true] {
|
||||
background-color: hsla(var(--background-color-a-hsl), 40%) !important;
|
||||
}
|
||||
|
||||
.File-button:hover,
|
||||
.Folder-button:hover,
|
||||
.File-button:focus-visible,
|
||||
.Folder-button:focus-visible {
|
||||
background-color: hsla(var(--background-color-a-hsl), 35%);
|
||||
background-color: hsla(var(--background-color-a-hsl), 20%);
|
||||
}
|
||||
|
||||
.File-button p, .Folder-button p {
|
||||
|
|
@ -37,4 +48,12 @@
|
|||
width: 50%;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.Selection-rect {
|
||||
opacity: 25%;
|
||||
position: absolute;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--blue-b);
|
||||
border: 0.25rem solid var(--blue-a);
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ export function MediaViewer({ file, close, setTitle }) {
|
|||
|
||||
if (file == null) {
|
||||
setTimeout(() => {
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Images" });
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Pictures" });
|
||||
close();
|
||||
}, 10);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Button } from "../../utils/Button.jsx";
|
||||
import { Button } from "../../utils/button/Button.jsx";
|
||||
import styles from "./Settings.module.css";
|
||||
import utilStyles from "../../../styles/utils.module.css";
|
||||
import Vector2 from "../../../features/math/vector2.js";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import styles from "./Settings.module.css";
|
||||
import utilStyles from "../../../styles/utils.module.css";
|
||||
import { round } from "../../../features/math/round.js";
|
||||
import { ProgressBar } from "../../utils/ProgressBar.jsx";
|
||||
import { Button } from "../../utils/Button.jsx";
|
||||
import { ProgressBar } from "../../utils/progress-bar/ProgressBar.jsx";
|
||||
import { Button } from "../../utils/button/Button.jsx";
|
||||
import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext.js";
|
||||
import { StorageManager } from "../../../features/storage/storageManager.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -85,29 +85,27 @@ export const Desktop = memo(() => {
|
|||
onContextMenu={onContextMenu}
|
||||
>
|
||||
<ModalsView modalsManager={modalsManager} modals={modals}/>
|
||||
<div className={styles.Content}>
|
||||
<DirectoryList
|
||||
directory={directory}
|
||||
fileClassname={styles["Item"]}
|
||||
folderClassname={styles["Item"]}
|
||||
onClickFile={(event, file) => {
|
||||
event.preventDefault();
|
||||
<DirectoryList
|
||||
directory={directory}
|
||||
className={styles.Content}
|
||||
fileClassName={styles["Item"]}
|
||||
folderClassName={styles["Item"]}
|
||||
onClickFile={(event, file) => {
|
||||
event.preventDefault();
|
||||
|
||||
const options = {};
|
||||
if (file.name === "info.md") {
|
||||
options.mode = "view";
|
||||
options.size = new Vector2(575, 675);
|
||||
}
|
||||
const options = { mode: "view" };
|
||||
if (file.name === "info.md") {
|
||||
options.size = new Vector2(575, 675);
|
||||
}
|
||||
|
||||
windowsManager.openFile(file, options);
|
||||
}}
|
||||
onClickFolder={(event, { linkedPath, path }) => {
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path });
|
||||
}}
|
||||
onContextMenuFile={onContextMenuFile}
|
||||
onContextMenuFolder={onContextMenuFolder}
|
||||
/>
|
||||
</div>
|
||||
windowsManager.openFile(file, options);
|
||||
}}
|
||||
onClickFolder={(event, { linkedPath, path }) => {
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path });
|
||||
}}
|
||||
onContextMenuFile={onContextMenuFile}
|
||||
onContextMenuFolder={onContextMenuFolder}
|
||||
/>
|
||||
{wallpaper
|
||||
? <img src={wallpaper} className={styles.Wallpaper} alt="Desktop wallpaper" onError={onError}/>
|
||||
: null
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export function HomeMenu({ active, setActive, search }) {
|
|||
</button>
|
||||
<button title="Images" tabIndex={tabIndex} onClick={() => {
|
||||
setActive(false);
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Images" });
|
||||
windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Pictures" });
|
||||
}}>
|
||||
<FontAwesomeIcon icon={faImage}/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import styles from "./DropdownButton.module.css";
|
||||
import OutsideClickListener from "../../hooks/utils/outsideClick.js";
|
||||
import { formatShortcut } from "../../features/utils/string.js";
|
||||
import OutsideClickListener from "../../../hooks/utils/outsideClick.js";
|
||||
import { formatShortcut } from "../../../features/utils/string.js";
|
||||
|
||||
/**
|
||||
* @param {object} props
|
||||
34
src/components/utils/interactable/Interactable.jsx
Normal file
34
src/components/utils/interactable/Interactable.jsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { useState } from "react";
|
||||
import { INTERACTIBLE_DOUBLE_CLICK_DELAY } from "../../../constants/utils.js";
|
||||
|
||||
let timeoutId = null;
|
||||
|
||||
export function Interactable({ onClick, onDoubleClick, children, ...props }) {
|
||||
const [clicked, setClicked] = useState(false);
|
||||
|
||||
const onButtonClick = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (timeoutId != null)
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (clicked) {
|
||||
setClicked(false);
|
||||
onDoubleClick?.(event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setClicked(true);
|
||||
onClick?.(event);
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
setClicked(false);
|
||||
}, INTERACTIBLE_DOUBLE_CLICK_DELAY);
|
||||
};
|
||||
|
||||
return <button {...props} onClick={onButtonClick}>
|
||||
{children}
|
||||
</button>;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { clamp } from "../../features/math/clamp.js";
|
||||
import { clamp } from "../../../features/math/clamp.js";
|
||||
import styles from "./ProgressBar.module.css";
|
||||
|
||||
/**
|
||||
|
|
@ -1 +1 @@
|
|||
export const WALLPAPERS_PATH = "~/Images/Wallpapers";
|
||||
export const WALLPAPERS_PATH = "~/Pictures/Wallpapers";
|
||||
1
src/constants/utils.js
Normal file
1
src/constants/utils.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const INTERACTIBLE_DOUBLE_CLICK_DELAY = 250;
|
||||
|
|
@ -15,7 +15,7 @@ export default class Application {
|
|||
}
|
||||
|
||||
WindowContent = (props) => {
|
||||
props = {...props, ...this.windowOptions};
|
||||
props = { ...props, ...this.windowOptions };
|
||||
|
||||
if (this.windowContent == null) {
|
||||
return null;
|
||||
|
|
|
|||
117
src/features/virtual-drive/defaultData.js
Normal file
117
src/features/virtual-drive/defaultData.js
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import { APPS } from "../../constants/applications.js";
|
||||
import { WALLPAPERS } from "../../constants/desktop.js";
|
||||
import AppsManager from "../applications/applications.js";
|
||||
import { VirtualRoot } from "./virtualRoot.js";
|
||||
|
||||
/**
|
||||
* Loads default data on the virtual root
|
||||
* @param {VirtualRoot} virtualRoot
|
||||
*/
|
||||
export function loadDefaultData(virtualRoot) {
|
||||
virtualRoot.createFolder("bin", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "echo" },
|
||||
{ name: "cd" },
|
||||
{ name: "ls" },
|
||||
{ name: "clear" },
|
||||
]);
|
||||
});
|
||||
|
||||
virtualRoot.createFolder("dev", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "null" },
|
||||
{ name: "zero" },
|
||||
{ name: "random" },
|
||||
]);
|
||||
});
|
||||
|
||||
virtualRoot.createFolder("etc");
|
||||
|
||||
virtualRoot.createFolder("usr", (folder) => {
|
||||
folder.createFolders(["bin", "sbin", "lib", "share"]);
|
||||
});
|
||||
|
||||
const linkedPaths = {};
|
||||
|
||||
virtualRoot.createFolder("home", (folder) => {
|
||||
folder.createFolder("prozilla-os", (folder) => {
|
||||
folder.setAlias("~")
|
||||
.createFolder(".config", (folder) => {
|
||||
folder.createFile("desktop", "xml", (file) => {
|
||||
file.setSource("/config/desktop.xml");
|
||||
}).createFile("taskbar", "xml", (file) => {
|
||||
file.setSource("/config/taskbar.xml");
|
||||
});
|
||||
})
|
||||
.createFolder("Pictures", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-images"));
|
||||
folder.createFolder("Wallpapers", (folder) => {
|
||||
folder.setProtected(true);
|
||||
for (let i = 0; i < WALLPAPERS.length; i++) {
|
||||
const source = WALLPAPERS[i];
|
||||
folder.createFile(`Wallpaper${i + 1}`, "png", (file) => {
|
||||
file.setSource(source);
|
||||
});
|
||||
}
|
||||
}).createFile("ProzillaOS", "png", (file) => {
|
||||
file.setSource("/assets/banner-logo-title.png");
|
||||
}).createFolder("Crumbling City", (folder) => {
|
||||
folder.createFile("Japan", "png", (file) => {
|
||||
file.setSource("https://daisygames.org/media/Games/Crumbling%20City/CrumblingCityRelease.png");
|
||||
}).createFile("City Center", "png", (file) => {
|
||||
file.setSource("https://daisygames.org/media/Games/Crumbling%20City/Screenshot_City_Firegun.png");
|
||||
}).createFile("Farms", "png", (file) => {
|
||||
file.setSource("https://daisygames.org/media/Games/Crumbling%20City/Screenshot_Farms_Hammer.png");
|
||||
});
|
||||
});
|
||||
linkedPaths.images = folder.path;
|
||||
})
|
||||
.createFolder("Documents", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-text"));
|
||||
folder.createFile("text", "txt", (file) => {
|
||||
file.setContent("Hello world!");
|
||||
}).createFile("info", "md", (file) => {
|
||||
file.setProtected(true)
|
||||
.setSource("/documents/info.md")
|
||||
.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-info"));
|
||||
linkedPaths.info = file.path;
|
||||
}).createFile("links", "md", (file) => {
|
||||
file.setProtected(true)
|
||||
.setSource("/documents/links.md");
|
||||
linkedPaths.links = file.path;
|
||||
});
|
||||
linkedPaths.documents = folder.path;
|
||||
})
|
||||
.createFolder("Desktop", (folder) => {
|
||||
folder.createFileLink("info.md", (fileLink) => {
|
||||
fileLink.setLinkedPath(linkedPaths.info);
|
||||
}).createFileLink("links.md", (fileLink) => {
|
||||
fileLink.setLinkedPath(linkedPaths.links);
|
||||
}).createFolderLink("Pictures", (folderLink) => {
|
||||
folderLink.setLinkedPath(linkedPaths.images);
|
||||
}).createFolderLink("Documents", (folderLink) => {
|
||||
folderLink.setLinkedPath(linkedPaths.documents);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
virtualRoot.createFolder("lib");
|
||||
virtualRoot.createFolder("sbin");
|
||||
virtualRoot.createFolder("tmp");
|
||||
virtualRoot.createFolder("var");
|
||||
virtualRoot.createFolder("boot");
|
||||
|
||||
virtualRoot.createFolder("proc", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "cpuinfo" },
|
||||
{ name: "meminfo" },
|
||||
]);
|
||||
});
|
||||
|
||||
virtualRoot.createFolder("var");
|
||||
virtualRoot.createFolder("opt");
|
||||
virtualRoot.createFolder("media");
|
||||
virtualRoot.createFolder("mnt");
|
||||
virtualRoot.createFolder("srv");
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ export class VirtualBase extends EventEmitter {
|
|||
|
||||
/**
|
||||
* @param {string} alias
|
||||
* @returns {ThisType}
|
||||
* @returns {VirtualBase}
|
||||
*/
|
||||
setAlias(alias) {
|
||||
if (this.alias === alias || !this.canBeEdited)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class VirtualFolder extends VirtualBase {
|
|||
|
||||
/**
|
||||
* @param {string} alias
|
||||
* @returns {ThisType}
|
||||
* @returns {VirtualFolder}
|
||||
*/
|
||||
setAlias(alias) {
|
||||
return super.setAlias(alias);
|
||||
|
|
@ -39,7 +39,7 @@ export class VirtualFolder extends VirtualBase {
|
|||
* Returns true if this folder contains a file matching a name and extension
|
||||
* @param {string} name
|
||||
* @param {string} extension
|
||||
* @returns {ThisType}
|
||||
* @returns {VirtualFolder}
|
||||
*/
|
||||
hasFile(name, extension) {
|
||||
return this.findFile(name, extension) !== null;
|
||||
|
|
@ -130,7 +130,7 @@ export class VirtualFolder extends VirtualBase {
|
|||
if (!this.canBeEdited)
|
||||
return;
|
||||
|
||||
files.forEach(({name, extension}) => {
|
||||
files.forEach(({ name, extension }) => {
|
||||
this.createFile(name, extension);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { APPS } from "../../constants/applications.js";
|
||||
import { WALLPAPERS } from "../../constants/desktop.js";
|
||||
import AppsManager from "../applications/applications.js";
|
||||
import { StorageManager } from "../storage/storageManager.js";
|
||||
import { VirtualFolderLink } from "./VirtualFolderLink.js";
|
||||
import { loadDefaultData } from "./defaultData.js";
|
||||
import { VirtualFile } from "./virtualFile.js";
|
||||
import { VirtualFolder } from "./virtualFolder.js";
|
||||
|
||||
|
|
@ -24,98 +22,7 @@ export class VirtualRoot extends VirtualFolder {
|
|||
}
|
||||
|
||||
loadDefaultData() {
|
||||
this.createFolder("bin", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "echo" },
|
||||
{ name: "cd" },
|
||||
{ name: "ls" },
|
||||
{ name: "clear" },
|
||||
]);
|
||||
});
|
||||
|
||||
this.createFolder("dev", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "null" },
|
||||
{ name: "zero" },
|
||||
{ name: "random" },
|
||||
]);
|
||||
});
|
||||
|
||||
this.createFolder("etc");
|
||||
|
||||
this.createFolder("usr", (folder) => {
|
||||
folder.createFolders(["bin", "sbin", "lib", "share"]);
|
||||
});
|
||||
|
||||
const linkedPaths = {};
|
||||
|
||||
this.createFolder("home", (folder) => {
|
||||
folder.createFolder("prozilla-os", (folder) => {
|
||||
folder.setAlias("~")
|
||||
.createFolder(".config", (folder) => {
|
||||
folder.createFile("desktop", "xml", (file) => {
|
||||
file.setSource("/config/desktop.xml");
|
||||
}).createFile("taskbar", "xml", (file) => {
|
||||
file.setSource("/config/taskbar.xml");
|
||||
});
|
||||
})
|
||||
.createFolder("Images", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-images"));
|
||||
folder.createFolder("Wallpapers", (folder) => {
|
||||
folder.setProtected(true);
|
||||
for (let i = 0; i < WALLPAPERS.length; i++) {
|
||||
const source = WALLPAPERS[i];
|
||||
folder.createFile(`Wallpaper${i + 1}`, "png", (file) => {
|
||||
file.setSource(source);
|
||||
});
|
||||
}
|
||||
}).createFile("ProzillaOS", "png", (file) => {
|
||||
file.setSource("/assets/banner-logo-title.png");
|
||||
});
|
||||
linkedPaths.images = folder.path;
|
||||
})
|
||||
.createFolder("Documents", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-text"));
|
||||
folder.createFile("text", "txt", (file) => {
|
||||
file.setContent("Hello world!");
|
||||
}).createFile("info", "md", (file) => {
|
||||
file.setProtected(true)
|
||||
.setSource("/documents/info.md")
|
||||
.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-info"));
|
||||
linkedPaths.info = file.path;
|
||||
});
|
||||
linkedPaths.documents = folder.path;
|
||||
})
|
||||
.createFolder("Desktop", (folder) => {
|
||||
folder.createFileLink("info.md", (fileLink) => {
|
||||
fileLink.setLinkedPath(linkedPaths.info);
|
||||
}).createFolderLink("Images", (folderLink) => {
|
||||
folderLink.setLinkedPath(linkedPaths.images);
|
||||
}).createFolderLink("Documents", (folderLink) => {
|
||||
folderLink.setLinkedPath(linkedPaths.documents);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.createFolder("lib");
|
||||
this.createFolder("sbin");
|
||||
this.createFolder("tmp");
|
||||
this.createFolder("var");
|
||||
this.createFolder("boot");
|
||||
|
||||
this.createFolder("proc", (folder) => {
|
||||
folder.createFiles([
|
||||
{ name: "cpuinfo" },
|
||||
{ name: "meminfo" },
|
||||
]);
|
||||
});
|
||||
|
||||
this.createFolder("var");
|
||||
this.createFolder("opt");
|
||||
this.createFolder("media");
|
||||
this.createFolder("mnt");
|
||||
this.createFolder("srv");
|
||||
loadDefaultData(this);
|
||||
}
|
||||
|
||||
loadData() {
|
||||
|
|
@ -132,7 +39,7 @@ export class VirtualRoot extends VirtualFolder {
|
|||
if (object == null)
|
||||
return;
|
||||
|
||||
const shortcuts = {...object.scs};
|
||||
const shortcuts = { ...object.scs };
|
||||
|
||||
const addFile = ({
|
||||
nam: name,
|
||||
|
|
|
|||
Loading…
Reference in a new issue