From 75666e71354373de3344a9841a7422b7c55d58bd Mon Sep 17 00:00:00 2001 From: Prozilla Date: Tue, 12 Dec 2023 22:53:17 +0100 Subject: [PATCH] Updated file & folder icons --- .gitignore | 1 + .../file-explorer/icons/file-code.svg | 29 +++++++++++++ .../file-explorer/icons/file-info.svg | 28 +++++++++++++ .../file-explorer/icons/file-text.svg | 30 ++++++++++++++ .../applications/file-explorer/icons/file.svg | 27 ++++++++++++ .../file-explorer/icons/folder-images.svg | 24 +++++++++++ .../file-explorer/icons/folder-link.svg | 24 +++++++++++ .../file-explorer/icons/folder-text.svg | 23 +++++++++++ .../file-explorer/icons/folder.svg | 27 ++++++++++++ .../file-explorer/FileExplorer.jsx | 4 +- .../file-explorer/FilePreview.jsx | 31 -------------- .../file-explorer/FolderPreview.jsx | 18 -------- .../file-explorer/FolderPreview.module.css | 20 --------- .../{ => directory-list}/DirectoryList.jsx | 33 ++++++++------- .../DirectoryList.module.css | 31 +++++++------- .../file-explorer/directory-list/FileIcon.jsx | 38 +++++++++++++++++ .../directory-list/FolderIcon.jsx | 26 ++++++++++++ .../directory-list/ImagePreview.jsx | 19 +++++++++ .../ImagePreview.module.css} | 6 +-- .../applications/media-viewer/MediaViewer.jsx | 3 +- .../applications/text-editor/TextEditor.jsx | 15 ++++++- src/components/desktop/Desktop.jsx | 17 ++++++-- src/components/desktop/Desktop.module.css | 4 +- src/components/task-bar/TaskBar.jsx | 4 +- src/components/task-bar/menus/HomeMenu.jsx | 11 ++--- src/components/task-bar/menus/SearchMenu.jsx | 6 +-- src/components/windows/WindowView.jsx | 14 ++++++- src/constants/applications.js | 7 ++++ src/features/applications/applications.js | 35 +++++++++++----- .../terminal/commands/neofetch.js | 5 ++- src/features/virtual-drive/virtualBase.js | 24 ++++++++++- src/features/virtual-drive/virtualFolder.js | 8 ++-- src/features/virtual-drive/virtualRoot.js | 41 ++++++++++++++++--- src/features/windows/windowsManager.js | 13 +++--- 34 files changed, 492 insertions(+), 154 deletions(-) create mode 100644 public/media/applications/file-explorer/icons/file-code.svg create mode 100644 public/media/applications/file-explorer/icons/file-info.svg create mode 100644 public/media/applications/file-explorer/icons/file-text.svg create mode 100644 public/media/applications/file-explorer/icons/file.svg create mode 100644 public/media/applications/file-explorer/icons/folder-images.svg create mode 100644 public/media/applications/file-explorer/icons/folder-link.svg create mode 100644 public/media/applications/file-explorer/icons/folder-text.svg create mode 100644 public/media/applications/file-explorer/icons/folder.svg delete mode 100644 src/components/applications/file-explorer/FilePreview.jsx delete mode 100644 src/components/applications/file-explorer/FolderPreview.jsx delete mode 100644 src/components/applications/file-explorer/FolderPreview.module.css rename src/components/applications/file-explorer/{ => directory-list}/DirectoryList.jsx (60%) rename src/components/applications/file-explorer/{ => directory-list}/DirectoryList.module.css (70%) create mode 100644 src/components/applications/file-explorer/directory-list/FileIcon.jsx create mode 100644 src/components/applications/file-explorer/directory-list/FolderIcon.jsx create mode 100644 src/components/applications/file-explorer/directory-list/ImagePreview.jsx rename src/components/applications/file-explorer/{FilePreview.module.css => directory-list/ImagePreview.module.css} (73%) create mode 100644 src/constants/applications.js diff --git a/.gitignore b/.gitignore index 4d29575..56f3bce 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +*.ini diff --git a/public/media/applications/file-explorer/icons/file-code.svg b/public/media/applications/file-explorer/icons/file-code.svg new file mode 100644 index 0000000..27daca8 --- /dev/null +++ b/public/media/applications/file-explorer/icons/file-code.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/file-info.svg b/public/media/applications/file-explorer/icons/file-info.svg new file mode 100644 index 0000000..f079907 --- /dev/null +++ b/public/media/applications/file-explorer/icons/file-info.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/file-text.svg b/public/media/applications/file-explorer/icons/file-text.svg new file mode 100644 index 0000000..7cae1ff --- /dev/null +++ b/public/media/applications/file-explorer/icons/file-text.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/file.svg b/public/media/applications/file-explorer/icons/file.svg new file mode 100644 index 0000000..6cf4702 --- /dev/null +++ b/public/media/applications/file-explorer/icons/file.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/folder-images.svg b/public/media/applications/file-explorer/icons/folder-images.svg new file mode 100644 index 0000000..dccb4fb --- /dev/null +++ b/public/media/applications/file-explorer/icons/folder-images.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/folder-link.svg b/public/media/applications/file-explorer/icons/folder-link.svg new file mode 100644 index 0000000..8f08e0f --- /dev/null +++ b/public/media/applications/file-explorer/icons/folder-link.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/folder-text.svg b/public/media/applications/file-explorer/icons/folder-text.svg new file mode 100644 index 0000000..371686f --- /dev/null +++ b/public/media/applications/file-explorer/icons/folder-text.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/media/applications/file-explorer/icons/folder.svg b/public/media/applications/file-explorer/icons/folder.svg new file mode 100644 index 0000000..f5d4036 --- /dev/null +++ b/public/media/applications/file-explorer/icons/folder.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/applications/file-explorer/FileExplorer.jsx b/src/components/applications/file-explorer/FileExplorer.jsx index 04b7341..c4c5aab 100644 --- a/src/components/applications/file-explorer/FileExplorer.jsx +++ b/src/components/applications/file-explorer/FileExplorer.jsx @@ -11,7 +11,7 @@ import { QuickAccessButton } from "./QuickAccessButton.jsx"; import { useDialogBox } from "../../../hooks/modals/dialogBox.js"; import Vector2 from "../../../features/math/vector2.js"; import { DIALOG_CONTENT_TYPES } from "../../../constants/modals.js"; -import { DirectoryList } from "./DirectoryList.jsx"; +import { DirectoryList } from "./directory-list/DirectoryList.jsx"; export function FileExplorer({ startPath, app }) { const virtualRoot = useVirtualRoot(); @@ -130,8 +130,8 @@ export function FileExplorer({ startPath, app }) {
{ changeDirectory("~"); }} icon={faHouse}/> { changeDirectory("~/Desktop"); }} icon={faDesktop}/> - { changeDirectory("~/Documents"); }} icon={faFileLines}/> { changeDirectory("~/Images"); }} icon={faImage}/> + { changeDirectory("~/Documents"); }} icon={faFileLines}/>
- {file.id} -
); - break; - case "txt": - preview = ; - break; - case "md": - preview = ; - break; - default: - preview = ; - break; - } - - return preview; -} \ No newline at end of file diff --git a/src/components/applications/file-explorer/FolderPreview.jsx b/src/components/applications/file-explorer/FolderPreview.jsx deleted file mode 100644 index 0e8b1b5..0000000 --- a/src/components/applications/file-explorer/FolderPreview.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import { faFolder, faLink } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import styles from "./FolderPreview.module.css"; -import { VirtualFolder } from "../../../features/virtual-drive/virtualFolder.js"; - -/** - * @param {object} props - * @param {VirtualFolder} props.folder - */ -export function FolderPreview({ folder }) { - return (
- - {folder.linkedPath - ?
- : null - } -
); -} \ No newline at end of file diff --git a/src/components/applications/file-explorer/FolderPreview.module.css b/src/components/applications/file-explorer/FolderPreview.module.css deleted file mode 100644 index a27833b..0000000 --- a/src/components/applications/file-explorer/FolderPreview.module.css +++ /dev/null @@ -1,20 +0,0 @@ -.Folder-link-icon { - position: absolute; - display: flex; - justify-content: flex-end; - align-items: flex-end; - top: 0; - left: 0; - width: 92.5%; - height: 87.5%; -} - -.Folder-link-icon svg { - width: 55%; - height: auto; - aspect-ratio: 1; -} - -.Folder-link-icon svg * { - fill: var(--background-color-b); -} \ No newline at end of file diff --git a/src/components/applications/file-explorer/DirectoryList.jsx b/src/components/applications/file-explorer/directory-list/DirectoryList.jsx similarity index 60% rename from src/components/applications/file-explorer/DirectoryList.jsx rename to src/components/applications/file-explorer/directory-list/DirectoryList.jsx index a34ae11..6df84cd 100644 --- a/src/components/applications/file-explorer/DirectoryList.jsx +++ b/src/components/applications/file-explorer/directory-list/DirectoryList.jsx @@ -1,7 +1,7 @@ -import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js"; -import { VirtualFolder } from "../../../features/virtual-drive/virtualFolder.js"; -import { FilePreview } from "./FilePreview.jsx"; -import { FolderPreview } from "./FolderPreview.jsx"; +import { VirtualFile } from "../../../../features/virtual-drive/virtualFile.js"; +import { VirtualFolder } from "../../../../features/virtual-drive/virtualFolder.js"; +import { FileIcon } from "./FileIcon.jsx"; +import { FolderIcon } from "./FolderIcon.jsx"; import styles from "./DirectoryList.module.css"; /** @@ -32,23 +32,28 @@ export function DirectoryList({ directory, showHidden = false, folderClassname, if (!directory) return null; - // const folders = directory.getSubFolders(showHidden); - // const files = directory.getFiles(showHidden); + const folderClassNames = [styles["Folder-button"]]; + const fileClassNames = [styles["File-button"]]; + + if (folderClassname) + folderClassNames.push(folderClassname); + if (fileClassname) + fileClassNames.push(fileClassname); return <> {directory?.getSubFolders(showHidden)?.map((folder) => )} @@ -56,15 +61,15 @@ export function DirectoryList({ directory, showHidden = false, folderClassname, )} diff --git a/src/components/applications/file-explorer/DirectoryList.module.css b/src/components/applications/file-explorer/directory-list/DirectoryList.module.css similarity index 70% rename from src/components/applications/file-explorer/DirectoryList.module.css rename to src/components/applications/file-explorer/directory-list/DirectoryList.module.css index 0cebf7b..dc76e85 100644 --- a/src/components/applications/file-explorer/DirectoryList.module.css +++ b/src/components/applications/file-explorer/directory-list/DirectoryList.module.css @@ -1,6 +1,6 @@ .File-button, .Folder-button { display: flex; - gap: 0.5rem; + gap: 0.25rem; flex-direction: column; align-items: center; justify-content: center; @@ -15,29 +15,26 @@ transition: background-color 100ms ease-in-out; } -.File-button:hover, .Folder-button:hover, -.File-button:focus-visible, .Folder-button:focus-visible { +.File-button:hover, +.Folder-button:hover, +.File-button:focus-visible, +.Folder-button:focus-visible { background-color: hsla(var(--background-color-a-hsl), 35%); } -.File-button svg, .Folder-button > div { - width: 50%; - height: auto; - aspect-ratio: 1; -} - -.Folder-button > div > svg { - width: 100%; - height: 100%; - aspect-ratio: 1; -} - .File-button p, .Folder-button p { max-width: 100%; margin: 0; word-wrap: break-word; } -.Folder-button > div { - position: relative; +.File-icon div, .Folder-icon div { + width: 100%; + height: 100%; +} + +.File-icon svg, .Folder-icon svg { + width: 50%; + height: auto; + aspect-ratio: 1; } \ No newline at end of file diff --git a/src/components/applications/file-explorer/directory-list/FileIcon.jsx b/src/components/applications/file-explorer/directory-list/FileIcon.jsx new file mode 100644 index 0000000..e54ee45 --- /dev/null +++ b/src/components/applications/file-explorer/directory-list/FileIcon.jsx @@ -0,0 +1,38 @@ +import styles from "./DirectoryList.module.css"; +import { VirtualFile } from "../../../../features/virtual-drive/virtualFile.js"; +import { ImagePreview } from "./ImagePreview.jsx"; +import AppsManager from "../../../../features/applications/applications.js"; +import { APPS } from "../../../../constants/applications.js"; + +/** + * @param {object} props + * @param {VirtualFile} props.file + * @param {string} props.iconUrl + */ +export function FileIcon({ file, iconUrl }) { + let preview = null; + + if (iconUrl && file.extension !== "png") { + preview = ; + } else { + switch (file.extension) { + case "png": + preview = ; + break; + case "txt": + case "md": + preview = ; + break; + case "xml": + preview = ; + break; + default: + preview = ; + break; + } + } + + return (
+ {preview} +
); +} \ No newline at end of file diff --git a/src/components/applications/file-explorer/directory-list/FolderIcon.jsx b/src/components/applications/file-explorer/directory-list/FolderIcon.jsx new file mode 100644 index 0000000..b159e14 --- /dev/null +++ b/src/components/applications/file-explorer/directory-list/FolderIcon.jsx @@ -0,0 +1,26 @@ +import styles from "./DirectoryList.module.css"; +import { VirtualFolder } from "../../../../features/virtual-drive/virtualFolder.js"; +import { ImagePreview } from "./ImagePreview.jsx"; +import AppsManager from "../../../../features/applications/applications.js"; +import { APPS } from "../../../../constants/applications.js"; + +/** + * @param {object} props + * @param {VirtualFolder} props.folder + * @param {string} props.iconUrl + */ +export function FolderIcon({ folder, iconUrl }) { + let preview = null; + + if (iconUrl) { + preview = ; + } else if (folder.linkedPath) { + preview = ; + } else { + preview = ; + } + + return (
+ {preview} +
); +} \ No newline at end of file diff --git a/src/components/applications/file-explorer/directory-list/ImagePreview.jsx b/src/components/applications/file-explorer/directory-list/ImagePreview.jsx new file mode 100644 index 0000000..d9d62ca --- /dev/null +++ b/src/components/applications/file-explorer/directory-list/ImagePreview.jsx @@ -0,0 +1,19 @@ +import { useState } from "react"; +import styles from "./ImagePreview.module.css"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faFile } from "@fortawesome/free-solid-svg-icons"; +import { ReactSVG } from "react-svg"; + +export function ImagePreview({ source }) { + const [loadingFailed, setLoadingFailed] = useState(false); + + if (loadingFailed) + return ; + + return (
+ {source.endsWith(".svg") + ? + : { setLoadingFailed(true); }} alt="Preview" draggable="false"/> + } +
); +} \ No newline at end of file diff --git a/src/components/applications/file-explorer/FilePreview.module.css b/src/components/applications/file-explorer/directory-list/ImagePreview.module.css similarity index 73% rename from src/components/applications/file-explorer/FilePreview.module.css rename to src/components/applications/file-explorer/directory-list/ImagePreview.module.css index b2a92e9..b2daeaa 100644 --- a/src/components/applications/file-explorer/FilePreview.module.css +++ b/src/components/applications/file-explorer/directory-list/ImagePreview.module.css @@ -1,4 +1,4 @@ -.File-button-preview { +.Image-preview { display: flex; justify-content: center; align-items: center; @@ -6,13 +6,13 @@ overflow: hidden; } -.File-button-preview > * { +.Image-preview > * { width: 100%; height: 100%; object-fit: contain; } -.File-button-preview > img { +.Image-preview > img { height: auto; max-height: 100%; border-radius: 0.5rem; diff --git a/src/components/applications/media-viewer/MediaViewer.jsx b/src/components/applications/media-viewer/MediaViewer.jsx index 0092645..89632a8 100644 --- a/src/components/applications/media-viewer/MediaViewer.jsx +++ b/src/components/applications/media-viewer/MediaViewer.jsx @@ -3,6 +3,7 @@ import { useEffect } from "react"; import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js"; import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js"; import styles from "./MediaViewer.module.css"; +import { APPS } from "../../../constants/applications.js"; /** * @param {object} props @@ -20,7 +21,7 @@ export function MediaViewer({ file, close, setTitle }) { if (file == null) { setTimeout(() => { - windowsManager.open("file-explorer", { startPath: "~/Images" }); + windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Images" }); close(); }, 10); return; diff --git a/src/components/applications/text-editor/TextEditor.jsx b/src/components/applications/text-editor/TextEditor.jsx index 6fe6af9..72feb64 100644 --- a/src/components/applications/text-editor/TextEditor.jsx +++ b/src/components/applications/text-editor/TextEditor.jsx @@ -5,6 +5,7 @@ import { HeaderMenu } from "../.common/HeaderMenu.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 AppsManager from "../../../features/applications/applications.js"; /** * @param {object} props @@ -13,8 +14,9 @@ import { DEFAULT_ZOOM, ZOOM_FACTOR } from "../../../constants/applications/textE * @param {Function} props.close * @param {string} props.mode * @param {Application} props.app + * @param {Function} props.setIconUrl */ -export function TextEditor({ file, setTitle, close, mode, app }) { +export function TextEditor({ file, setTitle, setIconUrl, close, mode, app }) { const [currentFile, setCurrentFile] = useState(file); const [currentMode, setCurrentMode] = useState(mode); const [content, setContent] = useState(file?.content ?? ""); @@ -25,6 +27,7 @@ export function TextEditor({ file, setTitle, close, mode, app }) { (async () => { let newContent = ""; + // Load file if (currentFile) { if (currentFile.content) { newContent = currentFile.content; @@ -35,13 +38,21 @@ export function TextEditor({ file, setTitle, close, mode, app }) { newContent = response; }); } + + const iconUrl = currentFile.getIconUrl(); + console.log(iconUrl); + if (iconUrl) + setIconUrl(iconUrl); + } else { + setIconUrl(AppsManager.getAppIconUrl(app.id)); } setContent(newContent); })(); - }, [currentFile]); + }, [app.id, currentFile, setIconUrl]); useEffect(() => { + // Update title let label = currentFile?.id ?? "Untitled"; if (unsavedChanges) diff --git a/src/components/desktop/Desktop.jsx b/src/components/desktop/Desktop.jsx index 93af1a9..6730c08 100644 --- a/src/components/desktop/Desktop.jsx +++ b/src/components/desktop/Desktop.jsx @@ -10,7 +10,9 @@ import { useContextMenu } from "../../hooks/modals/contextMenu.js"; import { FALLBACK_WALLPAPER } from "../../constants/desktop.js"; import { reloadViewport } from "../../features/utils/browser.js"; import { useVirtualRoot } from "../../hooks/virtual-drive/virtualRootContext.js"; -import { DirectoryList } from "../applications/file-explorer/DirectoryList.jsx"; +import { DirectoryList } from "../applications/file-explorer/directory-list/DirectoryList.jsx"; +import { APPS } from "../../constants/applications.js"; +import Vector2 from "../../features/math/vector2.js"; export const Desktop = memo(() => { const settingsManager = useSettingsManager(); @@ -23,7 +25,7 @@ export const Desktop = memo(() => { options: { "Refresh": () => { reloadViewport(); }, "Change appearance": () => { windowsManager.open("settings", { initialTabIndex: 0 }); }, - "Open in Files": () => { windowsManager.open("file-explorer", { startPath: "~/Desktop" }); }, + "Open in Files": () => { windowsManager.open(APPS.FILE_EXPLORER, { startPath: "~/Desktop" }); }, } }); @@ -54,10 +56,17 @@ export const Desktop = memo(() => { folderClassname={styles["Item"]} onClickFile={(event, file) => { event.preventDefault(); - windowsManager.openFile(file); + + const options = {}; + if (file.name === "info.md") { + options.mode = "view"; + options.size = new Vector2(575, 675); + } + + windowsManager.openFile(file, options); }} onClickFolder={(event, { linkedPath, path }) => { - windowsManager.open("file-explorer", { startPath: linkedPath ?? path }); + windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path }); }} /> diff --git a/src/components/desktop/Desktop.module.css b/src/components/desktop/Desktop.module.css index 7f2e561..e82c14a 100644 --- a/src/components/desktop/Desktop.module.css +++ b/src/components/desktop/Desktop.module.css @@ -36,9 +36,9 @@ .Item { padding: 0.25rem; - text-shadow: 0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 50%); + text-shadow: 0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 75%); } -.Item > svg, .Item > div > svg { +.Item svg { filter: drop-shadow(0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 50%)); } \ No newline at end of file diff --git a/src/components/task-bar/TaskBar.jsx b/src/components/task-bar/TaskBar.jsx index b625a01..f020b51 100644 --- a/src/components/task-bar/TaskBar.jsx +++ b/src/components/task-bar/TaskBar.jsx @@ -2,7 +2,7 @@ import { memo, useRef, useState } from "react"; import styles from "./TaskBar.module.css"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSearch } from "@fortawesome/free-solid-svg-icons"; -import ApplicationsManager from "../../features/applications/applications.js"; +import AppsManager from "../../features/applications/applications.js"; import { ReactSVG } from "react-svg"; import { HomeMenu } from "./menus/HomeMenu.jsx"; import OutsideClickListener from "../../hooks/utils/outsideClick.js"; @@ -105,7 +105,7 @@ export const Taskbar = memo(() => {
- {ApplicationsManager.APPLICATIONS.map((app) => + {AppsManager.APPLICATIONS.map((app) => )}
diff --git a/src/components/task-bar/menus/HomeMenu.jsx b/src/components/task-bar/menus/HomeMenu.jsx index 51abba1..47c6a94 100644 --- a/src/components/task-bar/menus/HomeMenu.jsx +++ b/src/components/task-bar/menus/HomeMenu.jsx @@ -3,7 +3,7 @@ import styles from "./HomeMenu.module.css"; import appStyles from "./AppList.module.css"; import { faCircleInfo, faFileLines, faGear, faImage, faPowerOff } from "@fortawesome/free-solid-svg-icons"; import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js"; -import ApplicationsManager from "../../../features/applications/applications.js"; +import AppsManager from "../../../features/applications/applications.js"; import { ReactSVG } from "react-svg"; import { closeViewport } from "../../../features/utils/browser.js"; import { useKeyboardListener } from "../../../hooks/utils/keyboard.js"; @@ -11,6 +11,7 @@ import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext. import { useEffect, useState } from "react"; import Vector2 from "../../../features/math/vector2.js"; import utilStyles from "../../../styles/utils.module.css"; +import { APPS } from "../../../constants/applications.js"; /** * @param {object} props @@ -82,13 +83,13 @@ export function HomeMenu({ active, setActive, search }) { @@ -96,7 +97,7 @@ export function HomeMenu({ active, setActive, search }) {

ProzillaOS

- {ApplicationsManager.APPLICATIONS.map(({ name, id }) => + {AppsManager.APPLICATIONS.map(({ name, id }) => )} diff --git a/src/components/task-bar/menus/SearchMenu.jsx b/src/components/task-bar/menus/SearchMenu.jsx index 92e7e4b..559deda 100644 --- a/src/components/task-bar/menus/SearchMenu.jsx +++ b/src/components/task-bar/menus/SearchMenu.jsx @@ -1,6 +1,6 @@ import styles from "./SearchMenu.module.css"; import appStyles from "./AppList.module.css"; -import ApplicationsManager from "../../../features/applications/applications.js"; +import AppsManager from "../../../features/applications/applications.js"; import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext.js"; import { ReactSVG } from "react-svg"; import { useEffect } from "react"; @@ -32,7 +32,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp }, [inputRef]); useEffect(() => { - setApps(ApplicationsManager.APPLICATIONS.filter(({ name }) => + setApps(AppsManager.APPLICATIONS.filter(({ name }) => name.toLowerCase().includes(searchQuery.toLowerCase().trim()) )); }, [searchQuery]); @@ -78,7 +78,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp windowsManager.open(id); }} > - +

{name}

)} diff --git a/src/components/windows/WindowView.jsx b/src/components/windows/WindowView.jsx index ac41ace..e2c74f1 100644 --- a/src/components/windows/WindowView.jsx +++ b/src/components/windows/WindowView.jsx @@ -12,6 +12,7 @@ import utilStyles from "../../styles/utils.module.css"; import { useModals } from "../../hooks/modals/modals.js"; import { ModalsView } from "../modals/ModalsView.jsx"; import { useContextMenu } from "../../hooks/modals/contextMenu.js"; +import AppsManager from "../../features/applications/applications.js"; /** * @param {object} props @@ -40,6 +41,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options, const [screenHeight, setScreenHeight] = useState(100); const [title, setTitle] = useState(app.name); + const [iconUrl, setIconUrl] = useState(AppsManager.getAppIconUrl(app.id)); const { onContextMenu } = useContextMenu({ modalsManager, @@ -137,7 +139,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,

{title}

- +
diff --git a/src/constants/applications.js b/src/constants/applications.js new file mode 100644 index 0000000..54b7861 --- /dev/null +++ b/src/constants/applications.js @@ -0,0 +1,7 @@ +export const APPS = { + TERMINAL: "terminal", + SETTINGS: "settings", + MEDIA_VIEWER: "media-viewer", + TEXT_EDITOR: "text-editor", + FILE_EXPLORER: "file-explorer" +}; \ No newline at end of file diff --git a/src/features/applications/applications.js b/src/features/applications/applications.js index 71ebf68..226c058 100644 --- a/src/features/applications/applications.js +++ b/src/features/applications/applications.js @@ -7,17 +7,18 @@ import { TextEditor } from "../../components/applications/text-editor/TextEditor import { Settings } from "../../components/applications/settings/Settings.jsx"; // import { Calculator } from "../../components/applications/calculator/Calculator.jsx"; import Vector2 from "../math/vector2.js"; +import { APPS } from "../../constants/applications.js"; -export default class ApplicationsManager { +export default class AppsManager { static APPLICATIONS = [ - new Application("Commands", "terminal", Terminal), - new Application("Settings", "settings", Settings), - new Application("Photos", "media-viewer", MediaViewer), + new Application("Commands", APPS.TERMINAL, Terminal), + new Application("Settings", APPS.SETTINGS, Settings), + new Application("Photos", APPS.MEDIA_VIEWER, MediaViewer), // new Application("Browser", "browser"), // new Application("Calculator", "calculator", Calculator, { size: new Vector2(400, 600) }), - new Application("Notes", "text-editor", TextEditor), + new Application("Notes", APPS.TEXT_EDITOR, TextEditor), // new Application("Code Editor", "code-editor"), - new Application("Files", "file-explorer", FileExplorer), + new Application("Files", APPS.FILE_EXPLORER, FileExplorer), new Application("Wordle", "wordle", WebView, { source: "https://prozilla.dev/wordle", size: new Vector2(400, 650) @@ -36,7 +37,7 @@ export default class ApplicationsManager { * @param {string} id * @returns {Application | null} */ - static getApplication(id) { + static getApp(id) { let application = null; this.APPLICATIONS.forEach((app) => { @@ -54,21 +55,35 @@ export default class ApplicationsManager { * @param {string} fileExtension * @returns {Application} */ - static getFileApplication(fileExtension) { + static getFileApp(fileExtension) { let app = null; // eslint-disable-next-line default-case switch (fileExtension) { case "png": - app = this.getApplication("media-viewer"); + app = this.getApp(APPS.MEDIA_VIEWER); break; case "txt": case "md": case "xml": - app = this.getApplication("text-editor"); + app = this.getApp(APPS.TEXT_EDITOR); break; } return app; } + + /** + * Returns the url of an icon inside the icons folder or the default icon of an app + * @param {string} appId + * @param {string | null} iconName + * @returns {string} + */ + static getAppIconUrl(appId, iconName) { + if (iconName == null) { + return `${process.env.PUBLIC_URL}/media/applications/icons/${appId}.svg`; + } else { + return `${process.env.PUBLIC_URL}/media/applications/${appId}/icons/${iconName}.svg`; + } + } } \ No newline at end of file diff --git a/src/features/applications/terminal/commands/neofetch.js b/src/features/applications/terminal/commands/neofetch.js index 5f50d27..208270c 100644 --- a/src/features/applications/terminal/commands/neofetch.js +++ b/src/features/applications/terminal/commands/neofetch.js @@ -1,7 +1,8 @@ +import { APPS } from "../../../../constants/applications.js"; import { ASCII_LOGO, NAME } from "../../../../constants/branding.js"; import { START_DATE } from "../../../../index.js"; import { formatRelativeTime } from "../../../utils/date.js"; -import ApplicationsManager from "../../applications.js"; +import AppsManager from "../../applications.js"; import Command from "../command.js"; export const neofetch = new Command("neofetch", (args, { username, hostname }) => { @@ -32,7 +33,7 @@ export const neofetch = new Command("neofetch", (args, { username, hostname }) = `RESOLUTION: ${window.innerWidth}x${window.innerHeight}`, "THEME: default", "ICONS: Font Awesome", - `TERMINAL: ${ApplicationsManager.getApplication("terminal")?.name ?? "Unknown"}`, + `TERMINAL: ${AppsManager.getApp(APPS.TERMINAL)?.name ?? "Unknown"}`, `BROWSER: ${browserName}`, `PLATFORM: ${navigator.platform}`, `LANGUAGE: ${navigator.language}`, diff --git a/src/features/virtual-drive/virtualBase.js b/src/features/virtual-drive/virtualBase.js index d550809..7cefed0 100644 --- a/src/features/virtual-drive/virtualBase.js +++ b/src/features/virtual-drive/virtualBase.js @@ -69,6 +69,27 @@ export class VirtualBase extends EventEmitter { return this; } + /** + * @param {string} iconUrl + * @returns {VirtualBase} + */ + setIconUrl(iconUrl) { + if (this.iconUrl === iconUrl || !this.canBeEdited) + return; + + this.iconUrl = iconUrl; + + this.confirmChanges(); + return this; + } + + /** + * @returns {string} + */ + getIconUrl = () => { + return this.iconUrl ?? this.linkedFile?.iconUrl ?? this.linkedFolder?.iconUrl; + }; + delete() { if (!this.canBeEdited) return; @@ -168,7 +189,8 @@ export class VirtualBase extends EventEmitter { */ toJSON() { const object = { - nam: this.name + nam: this.name, + ico: this.iconUrl, }; return object; diff --git a/src/features/virtual-drive/virtualFolder.js b/src/features/virtual-drive/virtualFolder.js index 63dc836..7d6d2ee 100644 --- a/src/features/virtual-drive/virtualFolder.js +++ b/src/features/virtual-drive/virtualFolder.js @@ -26,7 +26,7 @@ export class VirtualFolder extends VirtualBase { /** * @param {string} alias - * @returns {VirtualFolder} + * @returns {ThisType} */ setAlias(alias) { return super.setAlias(alias); @@ -36,7 +36,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 {VirtualFile} + * @returns {ThisType} */ hasFile(name, extension) { return this.findFile(name, extension) !== null; @@ -61,7 +61,9 @@ export class VirtualFolder extends VirtualBase { let resultFile = null; this.files.forEach((file) => { - if ((file.name === name || (file.alias && file.alias === name)) && file.extension === extension) { + const matchingName = (file.name === name || (file.alias && file.alias === name)); + const matchingExtension = (extension == null || file.extension === extension); + if (matchingName && matchingExtension) { return resultFile = file; } }); diff --git a/src/features/virtual-drive/virtualRoot.js b/src/features/virtual-drive/virtualRoot.js index 55d3779..a9f40d8 100644 --- a/src/features/virtual-drive/virtualRoot.js +++ b/src/features/virtual-drive/virtualRoot.js @@ -1,4 +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 { VirtualFile } from "./virtualFile.js"; @@ -56,7 +58,7 @@ export class VirtualRoot extends VirtualFolder { }); }) .createFolder("Images", (folder) => { - linkedPaths.images = folder.path; + folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-images")); folder.createFolder("Wallpapers", (folder) => { folder.setProtected(true); for (let i = 0; i < WALLPAPERS.length; i++) { @@ -68,15 +70,19 @@ export class VirtualRoot extends VirtualFolder { }).createFile("ProzillaOS", "png", (file) => { file.setSource("/media/banner-logo-title.png"); }); + linkedPaths.images = folder.path; }) .createFolder("Documents", (folder) => { - linkedPaths.documents = folder.path; + 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; - file.setProtected(true).setSource("/documents/info.md"); }); + linkedPaths.documents = folder.path; }) .createFolder("Desktop", (folder) => { folder.createFileLink("info.md", (fileLink) => { @@ -126,10 +132,20 @@ export class VirtualRoot extends VirtualFolder { const shortcuts = {...object.scs}; - const addFile = ({ nam: name, ext: extension, src: source, cnt: content, lnk: link }, parent = this) => { + const addFile = ({ + nam: name, + ext: extension, + src: source, + cnt: content, + lnk: link, + ico: iconUrl, + }, parent = this) => { if (link) { parent.createFileLink(name, (fileLink) => { fileLink.setLinkedPath(link); + if (iconUrl != null) { + fileLink.setIconUrl(iconUrl); + } }); return; } @@ -140,13 +156,25 @@ export class VirtualRoot extends VirtualFolder { } else if (content != null) { file.setContent(content); } + if (iconUrl != null) { + file.setIconUrl(iconUrl); + } }); }; - const addFolder = ({ nam: name, fds: folders, fls: files, lnk: link }, parent = this) => { + const addFolder = ({ + nam: name, + fds: folders, + fls: files, + lnk: link, + ico: iconUrl, + }, parent = this) => { if (link) { parent.createFolderLink(name, (folderLink) => { folderLink.setLinkedPath(link); + if (iconUrl != null) { + folderLink.setIconUrl(iconUrl); + } }); return; } @@ -170,6 +198,9 @@ export class VirtualRoot extends VirtualFolder { addFile(file, folder); }); } + if (iconUrl != null) { + folder.setIconUrl(iconUrl); + } }); }; diff --git a/src/features/windows/windowsManager.js b/src/features/windows/windowsManager.js index 0334126..4523e94 100644 --- a/src/features/windows/windowsManager.js +++ b/src/features/windows/windowsManager.js @@ -1,5 +1,5 @@ import { SCREEN_MARGIN, TASKBAR_HEIGHT } from "../../constants/windows.js"; -import ApplicationsManager from "../applications/applications.js"; +import AppsManager from "../applications/applications.js"; import { randomRange } from "../math/random.js"; import Vector2 from "../math/vector2.js"; import { VirtualFile } from "../virtual-drive/virtualFile.js"; @@ -16,7 +16,7 @@ export default class WindowsManager { * @returns {object | null} */ open(appId, options) { - const app = ApplicationsManager.getApplication(appId); + const app = AppsManager.getApp(appId); if (app == null) { console.warn(`Failed to open app ${appId}: app not found`); @@ -52,14 +52,13 @@ export default class WindowsManager { /** * @param {VirtualFile} file + * @param {object} options * @returns {object} */ - openFile(file) { - console.log(file); - const app = ApplicationsManager.getFileApplication(file.extension); - console.log(app); + openFile(file, options = {}) { + const app = AppsManager.getFileApp(file.extension); if (app != null) - return this.open(app.id, { file }); + return this.open(app.id, { file, ...options }); } /**