Finished core and file-explorer packages
This commit is contained in:
parent
045ef2ba4e
commit
ade2774b90
66 changed files with 581 additions and 282 deletions
|
|
@ -4,6 +4,7 @@ import eslint from "@eslint/js";
|
|||
import tseslint from "typescript-eslint";
|
||||
import react from "eslint-plugin-react";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
import * as pluginImport from "eslint-plugin-import";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
|
|
@ -22,6 +23,9 @@ export default tseslint.config(
|
|||
plugins: {
|
||||
react,
|
||||
"react-refresh": reactRefresh,
|
||||
import: {
|
||||
rules: pluginImport.rules
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
"quotes": "off",
|
||||
|
|
@ -66,6 +70,7 @@ export default tseslint.config(
|
|||
"warn",
|
||||
{ "allowConstantExport": true }
|
||||
],
|
||||
"import/no-relative-packages": "error"
|
||||
},
|
||||
}
|
||||
);
|
||||
193
package-lock.json
generated
193
package-lock.json
generated
|
|
@ -17,6 +17,7 @@
|
|||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@prozilla-os/core": "^1.0.0",
|
||||
"@prozilla-os/file-explorer": "^1.0.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"anser": "^2.1.1",
|
||||
"escape-carriage": "^1.3.1",
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"gh-pages": "^5.0.0",
|
||||
|
|
@ -1769,6 +1771,12 @@
|
|||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
|
||||
|
|
@ -2238,6 +2246,26 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.findlastindex": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
|
||||
"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-shim-unscopables": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.flat": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
|
||||
|
|
@ -3237,6 +3265,113 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7",
|
||||
"is-core-module": "^2.13.0",
|
||||
"resolve": "^1.22.4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
|
||||
"integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
|
||||
"integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.7",
|
||||
"array.prototype.findlastindex": "^1.2.3",
|
||||
"array.prototype.flat": "^1.3.2",
|
||||
"array.prototype.flatmap": "^1.3.2",
|
||||
"debug": "^3.2.7",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.9",
|
||||
"eslint-module-utils": "^2.8.0",
|
||||
"hasown": "^2.0.0",
|
||||
"is-core-module": "^2.13.1",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^3.1.2",
|
||||
"object.fromentries": "^2.0.7",
|
||||
"object.groupby": "^1.0.1",
|
||||
"object.values": "^1.1.7",
|
||||
"semver": "^6.3.1",
|
||||
"tsconfig-paths": "^3.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.34.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
|
||||
|
|
@ -5140,6 +5275,15 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist-options": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
|
||||
|
|
@ -5312,6 +5456,20 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object.groupby": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
|
||||
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object.hasown": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
|
||||
|
|
@ -6163,8 +6321,6 @@
|
|||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
|
|
@ -6662,6 +6818,15 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-indent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
|
||||
|
|
@ -7006,6 +7171,30 @@
|
|||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json5": "^0.0.29",
|
||||
"json5": "^1.0.2",
|
||||
"minimist": "^1.2.6",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths/node_modules/json5": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
|
|
|
|||
13
package.json
13
package.json
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "@prozilla-os/prozilla-os",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Prozilla",
|
||||
"email": "business@prozilla.dev",
|
||||
|
|
@ -8,10 +9,6 @@
|
|||
},
|
||||
"homepage": "https://os.prozilla.dev/",
|
||||
"repository": "https://github.com/Prozilla/ProzillaOS",
|
||||
"workspaces": [
|
||||
"packages/core",
|
||||
"packages/apps/file-explorer"
|
||||
],
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
|
@ -22,12 +19,17 @@
|
|||
"deploy": "tsx scripts/deploy",
|
||||
"fetch": "tsx scripts/fetchRepository"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/core",
|
||||
"packages/apps/file-explorer"
|
||||
],
|
||||
"dependencies": {
|
||||
"@prozilla-os/core": "^1.0.0",
|
||||
"@prozilla-os/file-explorer": "^1.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@prozilla-os/core": "^1.0.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"anser": "^2.1.1",
|
||||
"escape-carriage": "^1.3.1",
|
||||
|
|
@ -53,6 +55,7 @@
|
|||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"gh-pages": "^5.0.0",
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
# @ProzillaOS/file-explorer
|
||||
# @prozilla-os/file-explorer
|
||||
|
|
@ -11,7 +11,11 @@
|
|||
"scripts": {
|
||||
"test": "tsc --watch"
|
||||
},
|
||||
"repository": "https://github.com/Prozilla/ProzillaOS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Prozilla/ProzillaOS.git",
|
||||
"directory": "packages/apps/file-explorer"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||
import { faArrowUp, faCaretLeft, faCaretRight, faCircleInfo, faCog, faDesktop, faFileLines, faHouse, faImage, faPlus, faSearch, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { QuickAccessButton } from "./QuickAccessButton";
|
||||
import { ImportButton } from "./ImportButton";
|
||||
import { Actions, AppsManager, ClickAction, CODE_EXTENSIONS, DIALOG_CONTENT_TYPES, DialogBox, DirectoryList, Divider, FileEventHandler, FolderEventHandler, OnSelectionChangeParams, useAlert, useContextMenu, useHistory, useSystemManager, useVirtualRoot, useWindowedModal, useWindowsManager, utilStyles, Vector2, VirtualFile, VirtualFolder, VirtualFolderLink, VirtualRoot, WindowProps } from "@prozilla-os/core";
|
||||
import { Actions, ClickAction, CODE_EXTENSIONS, DIALOG_CONTENT_TYPES, DialogBox, DirectoryList, Divider, FileEventHandler, FolderEventHandler, OnSelectionChangeParams, useAlert, useContextMenu, useHistory, useSystemManager, useVirtualRoot, useWindowedModal, useWindowsManager, utilStyles, Vector2, VirtualFile, VirtualFolder, VirtualFolderLink, VirtualRoot, WindowProps } from "@prozilla-os/core";
|
||||
import { SELECTOR_MODE } from "../constants/fileExplorer.const";
|
||||
import { FileProperties } from "./modals/file-properties/FileProperties";
|
||||
|
||||
interface FileExplorerProps extends WindowProps {
|
||||
export interface FileExplorerProps extends WindowProps {
|
||||
path?: string;
|
||||
selectorMode?: number;
|
||||
Footer: FC;
|
||||
|
|
@ -109,7 +109,7 @@ export function FileExplorer({ app, path: startPath, selectorMode, Footer, onSel
|
|||
alert({
|
||||
title: (error as Error).message,
|
||||
text: "You have exceeded the virtual drive capacity. Files and folders will not be saved until more storage is freed.",
|
||||
iconUrl: app?.id != null ? AppsManager.getAppIconUrl(app.id) : undefined,
|
||||
iconUrl: app?.iconUrl as string | undefined,
|
||||
size: new Vector2(300, 200),
|
||||
single: true,
|
||||
});
|
||||
|
|
@ -138,7 +138,7 @@ export function FileExplorer({ app, path: startPath, selectorMode, Footer, onSel
|
|||
if (directory == null) {
|
||||
openWindowedModal({
|
||||
title: "Error",
|
||||
iconUrl: app?.id != null ? AppsManager.getAppIconUrl(app.id) : undefined,
|
||||
iconUrl: app?.iconUrl as string | undefined,
|
||||
size: new Vector2(300, 150),
|
||||
Modal: (props: {}) =>
|
||||
<DialogBox {...props}>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import styles from "./FileProperties.module.css";
|
||||
import utilStyles from "../../../styles/utils.module.css";
|
||||
import { AppsManager, ImagePreview, ModalProps, StorageManager, VirtualFile, WindowedModal } from "@prozilla-os/core";
|
||||
import { ImagePreview, ModalProps, StorageManager, useSystemManager, utilStyles, VirtualFile, WindowedModal } from "@prozilla-os/core";
|
||||
|
||||
interface FilePropetiesProps extends ModalProps {
|
||||
file: VirtualFile;
|
||||
}
|
||||
|
||||
export function FileProperties({ modal, params, file, ...props }: FilePropetiesProps) {
|
||||
const associatedApp = file.extension != null ? AppsManager.getAppByFileExtension(file.extension) : null;
|
||||
const { appsConfig } = useSystemManager();
|
||||
const associatedApp = file.extension != null ? appsConfig.getAppByFileExtension(file.extension) : null;
|
||||
|
||||
return <WindowedModal className={styles.FileProperties} modal={modal} params={params} {...props}>
|
||||
<span className={styles.Section}>
|
||||
|
|
@ -19,7 +19,7 @@ export function FileProperties({ modal, params, file, ...props }: FilePropetiesP
|
|||
{associatedApp != null &&
|
||||
<span className={styles.Line}>
|
||||
Opens with:
|
||||
<ImagePreview className={styles.AppIcon} source={AppsManager.getAppIconUrl(associatedApp.id)}/>
|
||||
<ImagePreview className={styles.AppIcon} source={associatedApp.iconUrl ?? ""}/>
|
||||
{associatedApp.name}
|
||||
</span>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,10 @@
|
|||
export { SELECTOR_MODE } from "./constants/fileExplorer.const";
|
||||
export { FileExplorer } from "./components/FileExplorer";
|
||||
import { App } from "@prozilla-os/core";
|
||||
import { FileExplorer } from "./components/FileExplorer";
|
||||
import { VirtualBase } from "@prozilla-os/core/src/features/virtual-drive/virtualBase";
|
||||
|
||||
const fileExplorer = new App("File Explorer", "file-explorer", FileExplorer)
|
||||
.setIconUrl("https://os.prozilla.dev/assets/apps/icons/file-explorer.svg");
|
||||
|
||||
export { fileExplorer };
|
||||
export { FileSelectorMode } from "./types/index.d";
|
||||
VirtualBase;
|
||||
5
packages/apps/file-explorer/src/types/index.d.ts
vendored
Normal file
5
packages/apps/file-explorer/src/types/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum FileSelectorMode {
|
||||
None = 0,
|
||||
Single = 1,
|
||||
Multi = 2
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
# @ProzillaOS/core
|
||||
# @prozilla-os/core
|
||||
|
|
@ -11,9 +11,14 @@
|
|||
"scripts": {
|
||||
"test": "tsc --watch"
|
||||
},
|
||||
"repository": "https://github.com/Prozilla/ProzillaOS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Prozilla/ProzillaOS.git",
|
||||
"directory": "packages/core"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@prozilla-os/file-explorer": "^1.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
|
|
@ -22,8 +27,7 @@
|
|||
"react-draggable": "^4.4.6",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-ga4": "^2.1.0",
|
||||
"react-svg": "^16.1.34",
|
||||
"@prozilla-os/file-explorer": "^1.0.0"
|
||||
"react-svg": "^16.1.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.2",
|
||||
|
|
@ -31,5 +35,9 @@
|
|||
},
|
||||
"files": [
|
||||
"src/index.ts"
|
||||
]
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com",
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { useState } from "react";
|
||||
import styles from "./ImagePreview.module.css";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { AppsManager } from "../../../features";
|
||||
import { APPS } from "../../../constants/apps.const";
|
||||
import { useSystemManager } from "../../../hooks";
|
||||
|
||||
interface ImagePreviewProps {
|
||||
source: string;
|
||||
|
|
@ -11,6 +10,7 @@ interface ImagePreviewProps {
|
|||
}
|
||||
|
||||
export function ImagePreview({ source, className, onError, ...props }: ImagePreviewProps) {
|
||||
const { virtualDriveConfig } = useSystemManager();
|
||||
const [loadingFailed, setLoadingFailed] = useState(false);
|
||||
|
||||
const onLoadingError = () => {
|
||||
|
|
@ -24,7 +24,7 @@ export function ImagePreview({ source, className, onError, ...props }: ImagePrev
|
|||
|
||||
return (<div className={classNames.join(" ")} {...props}>
|
||||
{loadingFailed
|
||||
? <ReactSVG src={AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file")}/>
|
||||
? <ReactSVG src={virtualDriveConfig.fileIcon}/>
|
||||
: source.endsWith(".svg")
|
||||
? <ReactSVG src={source} onError={onLoadingError}/>
|
||||
: <img src={source} onError={onLoadingError} alt="Preview" draggable="false"/>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export function Interactable({ onClick, onDoubleClick, children, ...props }: Int
|
|||
setClicked(true);
|
||||
onClick?.(event);
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
timeoutId = window.setTimeout(() => {
|
||||
setClicked(false);
|
||||
}, miscConfig.doubleClickDelay);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ import { RadioAction } from "../actions/actions/RadioAction";
|
|||
import { Divider } from "../actions/actions/Divider";
|
||||
import { Share } from "../modals/share/Share";
|
||||
import { ModalProps } from "../modals/ModalView";
|
||||
import { APP_NAMES, APP_ICONS, APPS } from "../../constants/apps.const";
|
||||
import { SettingsManager, reloadViewport, ModalsManager, Vector2, isValidInteger } from "../../features";
|
||||
import { VirtualFile } from "../../features/virtual-drive/file";
|
||||
import { VirtualFolder, VirtualFolderLink } from "../../features/virtual-drive/folder";
|
||||
import { useSettingsManager, useWindowsManager, useVirtualRoot, useWindowedModal, useContextMenu, useSystemManager } from "../../hooks";
|
||||
import { DirectoryList } from "../_utils";
|
||||
import { FileEventHandler, FolderEventHandler } from "../_utils/directory-list/DirectoryList";
|
||||
import { fileExplorer } from "@prozilla-os/file-explorer";
|
||||
|
||||
export const Desktop = memo(() => {
|
||||
const { desktopConfig } = useSystemManager();
|
||||
|
|
@ -83,12 +83,12 @@ export const Desktop = memo(() => {
|
|||
windowsManager?.open("settings", { tab: 2 });
|
||||
}}/>
|
||||
<Divider/>
|
||||
<ClickAction label={`Open in ${APP_NAMES.FILE_EXPLORER}`} icon={APP_ICONS.FILE_EXPLORER} onTrigger={() => {
|
||||
windowsManager?.open(APPS.FILE_EXPLORER, { path: directory?.path });
|
||||
<ClickAction label={`Open in ${fileExplorer.name}`} icon={fileExplorer.iconUrl as string | undefined} onTrigger={() => {
|
||||
windowsManager?.open(fileExplorer.id, { path: directory?.path });
|
||||
}}/>
|
||||
<ClickAction label={`Open in ${APP_NAMES.TERMINAL}`} icon={APP_ICONS.TERMINAL} onTrigger={() => {
|
||||
{/* <ClickAction label={`Open in ${"APP_NAMES.TERMINAL"}`} icon={APP_ICONS.TERMINAL} onTrigger={() => {
|
||||
windowsManager?.open(APPS.TERMINAL, { path: directory?.path });
|
||||
}}/>
|
||||
}}/> */}
|
||||
<Divider/>
|
||||
<ClickAction label={"Share"} icon={ModalsManager.getModalIconUrl("share")} onTrigger={() => {
|
||||
openWindowedModal({
|
||||
|
|
@ -103,7 +103,7 @@ export const Desktop = memo(() => {
|
|||
<ClickAction label="Open" onTrigger={(event, file) => {
|
||||
if (windowsManager != null) (file as VirtualFile).open(windowsManager);
|
||||
}}/>
|
||||
<ClickAction label={`Reveal in ${APP_NAMES.FILE_EXPLORER}`} icon={faFolder} onTrigger={(event, file) => {
|
||||
<ClickAction label={`Reveal in ${fileExplorer.name}`} icon={faFolder} onTrigger={(event, file) => {
|
||||
if (windowsManager != null) (file as VirtualFile).parent?.open(windowsManager);
|
||||
}}/>
|
||||
<ClickAction label="Delete" icon={faTrash} onTrigger={(event, file) => {
|
||||
|
|
@ -116,10 +116,10 @@ export const Desktop = memo(() => {
|
|||
<ClickAction label="Open" onTrigger={(event, folder) => {
|
||||
if (windowsManager != null) (folder as VirtualFolder).open(windowsManager);
|
||||
}}/>
|
||||
<ClickAction label={`Open in ${APP_NAMES.TERMINAL}`} icon={faTerminal} onTrigger={(event, folder) => {
|
||||
{/* <ClickAction label={`Open in ${APP_NAMES.TERMINAL}`} icon={faTerminal} onTrigger={(event, folder) => {
|
||||
windowsManager?.open(APPS.TERMINAL, { path: (folder as VirtualFolder).path });
|
||||
}}/>
|
||||
<ClickAction label={`Reveal in ${APP_NAMES.FILE_EXPLORER}`} icon={faFolder} onTrigger={(event, folder) => {
|
||||
}}/> */}
|
||||
<ClickAction label={`Reveal in ${fileExplorer.name}`} icon={faFolder} onTrigger={(event, folder) => {
|
||||
if (windowsManager != null) (folder as VirtualFolder).parent?.open(windowsManager);
|
||||
}}/>
|
||||
<Divider/>
|
||||
|
|
@ -183,7 +183,7 @@ export const Desktop = memo(() => {
|
|||
windowsManager?.openFile(file, options);
|
||||
}}
|
||||
onOpenFolder={(event, folder) => {
|
||||
windowsManager?.open(APPS.FILE_EXPLORER, {
|
||||
windowsManager?.open(fileExplorer.id, {
|
||||
path: (folder as VirtualFolderLink).linkedPath ?? folder.path
|
||||
});
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,18 @@ import { Button } from "../../_utils/button/Button";
|
|||
import { WindowedModal } from "../_utils/WindowedModal";
|
||||
import styles from "./FileSelector.module.css";
|
||||
import { ModalProps } from "../ModalView";
|
||||
import { APP_ICONS } from "../../../constants/apps.const";
|
||||
import { VirtualFile } from "../../../features/virtual-drive/file";
|
||||
import { VirtualFolder } from "../../../features/virtual-drive/folder";
|
||||
import { FileExplorer, SELECTOR_MODE } from "@prozilla-os/file-explorer";
|
||||
import { FileSelectorMode, fileExplorer } from "@prozilla-os/file-explorer";
|
||||
|
||||
interface FileSelectorProps extends ModalProps {
|
||||
type: number;
|
||||
type: FileSelectorMode;
|
||||
allowedFormats?: string[];
|
||||
onFinish: (result: VirtualFile | VirtualFile[]) => void;
|
||||
}
|
||||
|
||||
export function FileSelector({ modal, params, type, allowedFormats, onFinish, ...props }: FileSelectorProps) {
|
||||
const multi = (type === SELECTOR_MODE.MULTIPLE);
|
||||
const multi = (type == FileSelectorMode.Multi);
|
||||
|
||||
const [selection, setSelection] = useState<string[] | null>(multi ? [] : null);
|
||||
const [directory, setDirectory] = useState<VirtualFolder | null>(null);
|
||||
|
|
@ -45,10 +44,10 @@ export function FileSelector({ modal, params, type, allowedFormats, onFinish, ..
|
|||
|
||||
return <WindowedModal modal={modal} params={{
|
||||
title: multi ? "Select files" : "Select a file",
|
||||
iconUrl: APP_ICONS.FILE_EXPLORER,
|
||||
iconUrl: fileExplorer.iconUrl as string | undefined,
|
||||
...params,
|
||||
}} {...props}>
|
||||
<FileExplorer
|
||||
<fileExplorer.WindowContent
|
||||
selectorMode={type}
|
||||
Footer={() =>
|
||||
<div className={styles.Footer}>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { ModalsManager } from "../../../features/modals/modalsManager";
|
|||
import { WindowedModal } from "../_utils/WindowedModal";
|
||||
import styles from "./Share.module.css";
|
||||
import { copyToClipboard, generateUrl } from "../../../features/_utils/browser.utils";
|
||||
import { AppsManager } from "../../../features/apps/appsManager";
|
||||
import utilStyles from "../../../styles/utils.module.css";
|
||||
import { Button } from "../../_utils/button/Button";
|
||||
import { Option } from "./Option";
|
||||
|
|
@ -13,6 +12,7 @@ import { faSquareCheck } from "@fortawesome/free-solid-svg-icons";
|
|||
import { useAlert } from "../../../hooks/modals/alert";
|
||||
import { ModalProps } from "../ModalView";
|
||||
import { useScrollWithShadow } from "../../../hooks/_utils/scrollWithShadows";
|
||||
import { useSystemManager } from "../../../hooks";
|
||||
|
||||
const APP_OPTIONS: Record<string, { label: string, name: string }[]> = {
|
||||
"terminal": [
|
||||
|
|
@ -46,6 +46,7 @@ const APP_OPTIONS: Record<string, { label: string, name: string }[]> = {
|
|||
};
|
||||
|
||||
export function Share({ modal, params, ...props }: ModalProps) {
|
||||
const { appsConfig } = useSystemManager();
|
||||
const [appId, setAppId] = useState<string>(params?.appId ?? "");
|
||||
const [fullscreen, setFullscreen] = useState<boolean>(params?.fullscreen ?? false);
|
||||
const [standalone, setStandalone] = useState<boolean>(params?.standalone ?? false);
|
||||
|
|
@ -123,7 +124,7 @@ export function Share({ modal, params, ...props }: ModalProps) {
|
|||
<p>App:</p>
|
||||
<select className={styles.Input} name="app" value={appId} onChange={onAppIdChange as unknown as ChangeEventHandler}>
|
||||
<option value={""}>(None)</option>
|
||||
{AppsManager.APPS.map(({ name, id }) =>
|
||||
{appsConfig.apps.map(({ name, id }) =>
|
||||
<option key={id} value={id}>{name}</option>
|
||||
)}
|
||||
</select>
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ import { ModalsConfig, ModalsConfigOptions } from "../../features/system/configs
|
|||
import { TaskbarConfig, TaskbarConfigOptions } from "../../features/system/configs/taskbarConfig";
|
||||
import { TrackingConfig, TrackingConfigOptions } from "../../features/system/configs/trackingConfig";
|
||||
import { WindowsConfig, WindowsConfigOptions } from "../../features/system/configs/windowsConfig";
|
||||
import { OptionalInterface } from "../../types/global";
|
||||
import { OptionalInterface } from "../../types/util";
|
||||
import { TrackingManagerProvider } from "../../hooks/tracking/trackingManagerProvider";
|
||||
import { VirtualDriveConfig, VirtualDriveConfigOptions } from "../../features/system/configs/virtualDriveConfig";
|
||||
|
||||
interface ProzillaOSProps {
|
||||
systemName?: string;
|
||||
|
|
@ -29,6 +30,7 @@ interface ProzillaOSProps {
|
|||
taskbar?: OptionalInterface<TaskbarConfigOptions>;
|
||||
tracking?: OptionalInterface<TrackingConfigOptions>;
|
||||
windows?: OptionalInterface<WindowsConfigOptions>;
|
||||
virtualDrive?: OptionalInterface<VirtualDriveConfigOptions>;
|
||||
}
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
|
@ -45,7 +47,8 @@ export const ProzillaOS = memo(function(props: ProzillaOSProps): ReactElement {
|
|||
modalsConfig: new ModalsConfig(config?.modals),
|
||||
taskbarConfig: new TaskbarConfig(config?.taskbar),
|
||||
trackingConfig: new TrackingConfig(config?.tracking),
|
||||
windowsConfig: new WindowsConfig(config?.windows)
|
||||
windowsConfig: new WindowsConfig(config?.windows),
|
||||
virtualDriveConfig: new VirtualDriveConfig(config?.virtualDrive),
|
||||
} as SystemManagerParams;
|
||||
|
||||
return <SystemManagerProvider {...systemParams}>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { CSSProperties, memo, MouseEvent, MutableRefObject, ReactEventHandler, U
|
|||
import styles from "./Taskbar.module.css";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCog, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { AppsManager } from "../../features/apps/appsManager";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { HomeMenu } from "./menus/HomeMenu";
|
||||
import { OutsideClickListener } from "../../hooks/_utils/outsideClick";
|
||||
|
|
@ -12,19 +11,18 @@ import { AppButton } from "./app-icon/AppIcon";
|
|||
import { useContextMenu } from "../../hooks/modals/contextMenu";
|
||||
import { Actions } from "../actions/Actions";
|
||||
import { ClickAction } from "../actions/actions/ClickAction";
|
||||
import { APPS, APP_NAMES } from "../../constants/apps.const";
|
||||
import { useWindowsManager } from "../../hooks/windows/windowsManagerContext";
|
||||
import { useSettingsManager } from "../../hooks/settings/settingsManagerContext";
|
||||
import { SettingsManager } from "../../features/settings/settingsManager";
|
||||
import { useWindows } from "../../hooks/windows/windowsContext";
|
||||
import { ZIndexManager } from "../../features/z-index/zIndexManager";
|
||||
import { useZIndex } from "../../hooks/z-index/zIndex";
|
||||
import { App } from "../../features/apps/app";
|
||||
import { Battery, Calendar, Network, Volume } from "./indicators";
|
||||
import { useSystemManager } from "../../hooks";
|
||||
import { App } from "../../features";
|
||||
|
||||
export const Taskbar = memo(() => {
|
||||
const { taskbarConfig } = useSystemManager();
|
||||
const { taskbarConfig, appsConfig } = useSystemManager();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const settingsManager = useSettingsManager();
|
||||
const [showHome, setShowHome] = useState(false);
|
||||
|
|
@ -42,8 +40,8 @@ export const Taskbar = memo(() => {
|
|||
const windows = useWindows();
|
||||
const { onContextMenu } = useContextMenu({ Actions: (props) =>
|
||||
<Actions avoidTaskbar={false} {...props}>
|
||||
<ClickAction label={`Open ${APP_NAMES.SETTINGS}`} icon={faCog} onTrigger={() => {
|
||||
windowsManager?.open(APPS.SETTINGS);
|
||||
<ClickAction label={`Open ${"Settings"}`} icon={faCog} onTrigger={() => {
|
||||
windowsManager?.open("settings");
|
||||
}}/>
|
||||
</Actions>
|
||||
});
|
||||
|
|
@ -55,7 +53,7 @@ export const Taskbar = memo(() => {
|
|||
void settings?.get("pins", (pinList: string) => {
|
||||
const pins = pinList.split(",");
|
||||
|
||||
const newApps = AppsManager.APPS.sort((appA, appB) => {
|
||||
const newApps = appsConfig.apps.sort((appA, appB) => {
|
||||
const indexA = pins.indexOf(appA.id);
|
||||
const indexB = pins.indexOf(appB.id);
|
||||
if (indexA < 0 && indexB > 0) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import { FC, memo, MouseEvent } from "react";
|
||||
import { App } from "../../../features/apps/app";
|
||||
import { App } from "../../../features/system/configs/app";
|
||||
import styles from "./AppIcon.module.css";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { useSettingsManager } from "../../../hooks/settings/settingsManagerContext";
|
||||
import { useContextMenu } from "../../../hooks/modals/contextMenu";
|
||||
import { Actions } from "../../actions/Actions";
|
||||
import { ClickAction } from "../../actions/actions/ClickAction";
|
||||
import { AppsManager } from "../../../features/apps/appsManager";
|
||||
import { WindowsManager } from "../../../features/windows/windowsManager";
|
||||
|
||||
interface AppButtonProps {
|
||||
|
|
@ -20,7 +19,7 @@ export const AppButton: FC<AppButtonProps> = memo(({ app, windowsManager, active
|
|||
const settingsManager = useSettingsManager();
|
||||
const { onContextMenu } = useContextMenu({ Actions: (props) =>
|
||||
<Actions avoidTaskbar={false} {...props}>
|
||||
<ClickAction label={app.name} icon={AppsManager.getAppIconUrl(app.id)} onTrigger={() => {
|
||||
<ClickAction label={app.name} icon={app.iconUrl as string | undefined} onTrigger={() => {
|
||||
windowsManager?.open(app.id);
|
||||
}}/>
|
||||
{/* <ClickAction label={isPinned ? "Unpin from taskbar" : "Pin to taskbar"} icon={faThumbTack} onTrigger={() => {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { faCircleInfo, faFileLines, faGear, faImage, faPowerOff } from "@fortawe
|
|||
import { ReactSVG } from "react-svg";
|
||||
import { useEffect, useState } from "react";
|
||||
import { utilStyles } from "../../..";
|
||||
import { APPS } from "../../../constants/apps.const";
|
||||
import { closeViewport, Vector2, AppsManager } from "../../../features";
|
||||
import { closeViewport, Vector2 } from "../../../features";
|
||||
import { useWindowsManager, useVirtualRoot, useKeyboardListener, useSystemManager } from "../../../hooks";
|
||||
import { fileExplorer } from "@prozilla-os/file-explorer";
|
||||
|
||||
interface HomeMenuProps {
|
||||
active: boolean;
|
||||
|
|
@ -17,7 +17,7 @@ interface HomeMenuProps {
|
|||
}
|
||||
|
||||
export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
||||
const { systemName } = useSystemManager();
|
||||
const { systemName, appsConfig } = useSystemManager();
|
||||
const windowsManager = useWindowsManager();
|
||||
const virtualRoot = useVirtualRoot();
|
||||
const [tabIndex, setTabIndex] = useState(active ? 0 : -1);
|
||||
|
|
@ -81,13 +81,13 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
</button>
|
||||
<button title="Images" tabIndex={tabIndex} onClick={() => {
|
||||
setActive(false);
|
||||
windowsManager?.open(APPS.FILE_EXPLORER, { path: "~/Pictures" });
|
||||
windowsManager?.open(fileExplorer.id, { path: "~/Pictures" });
|
||||
}}>
|
||||
<FontAwesomeIcon icon={faImage}/>
|
||||
</button>
|
||||
<button title="Documents" tabIndex={tabIndex} onClick={() => {
|
||||
setActive(false);
|
||||
windowsManager?.open(APPS.FILE_EXPLORER, { path: "~/Documents" }); }
|
||||
windowsManager?.open(fileExplorer.id, { path: "~/Documents" }); }
|
||||
}>
|
||||
<FontAwesomeIcon icon={faFileLines}/>
|
||||
</button>
|
||||
|
|
@ -95,7 +95,7 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
<div className={styles.Apps}>
|
||||
<h1 className={utilStyles.TextBold}>{systemName}</h1>
|
||||
<div className={appStyles.AppList}>
|
||||
{AppsManager.APPS.sort((a, b) => a.name.localeCompare(b.name)).map(({ name, id }) =>
|
||||
{appsConfig.apps.sort((a, b) => a.name.localeCompare(b.name)).map(({ name, id, iconUrl }) =>
|
||||
<button
|
||||
key={id}
|
||||
className={appStyles.AppButton}
|
||||
|
|
@ -106,7 +106,7 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
}}
|
||||
title={name}
|
||||
>
|
||||
<ReactSVG src={AppsManager.getAppIconUrl(id)}/>
|
||||
<ReactSVG src={iconUrl ?? ""}/>
|
||||
<h2 className={utilStyles.TextRegular}>{name}</h2>
|
||||
</button>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import styles from "./SearchMenu.module.css";
|
||||
import appStyles from "./AppList.module.css";
|
||||
import { AppsManager } from "../../../features/apps/appsManager";
|
||||
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext";
|
||||
import { ChangeEventHandler, MutableRefObject, useEffect, useState } from "react";
|
||||
import { useKeyboardListener } from "../../../hooks/_utils/keyboard";
|
||||
import { App } from "../../../features/apps/app";
|
||||
import { App } from "../../../features/system/configs/app";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { useSystemManager } from "../../../hooks";
|
||||
|
||||
interface SearchMenuProps {
|
||||
active: boolean;
|
||||
|
|
@ -16,6 +16,7 @@ interface SearchMenuProps {
|
|||
}
|
||||
|
||||
export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inputRef }: SearchMenuProps) {
|
||||
const { appsConfig } = useSystemManager();
|
||||
const windowsManager = useWindowsManager();
|
||||
const [apps, setApps] = useState<App[] | null>(null);
|
||||
const [tabIndex, setTabIndex] = useState(active ? 0 : -1);
|
||||
|
|
@ -32,7 +33,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp
|
|||
}, [inputRef]);
|
||||
|
||||
useEffect(() => {
|
||||
setApps(AppsManager.APPS.filter(({ name, id }) =>
|
||||
setApps(appsConfig.apps.filter(({ name, id }) =>
|
||||
name.toLowerCase().includes(searchQuery.toLowerCase().trim())
|
||||
|| id.toLowerCase().includes(searchQuery.toLowerCase().trim())
|
||||
).sort((a, b) =>
|
||||
|
|
@ -79,7 +80,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp
|
|||
windowsManager?.open(id);
|
||||
}}
|
||||
>
|
||||
<ReactSVG src={AppsManager.getAppIconUrl(id)}/>
|
||||
<ReactSVG src={appsConfig.getAppById(id)?.iconUrl ?? ""}/>
|
||||
<p>{name}</p>
|
||||
</button>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useAlert } from "../../hooks/modals/alert";
|
||||
import { AppsManager } from "../../features/apps/appsManager";
|
||||
import { Vector2 } from "../../features/math/vector2";
|
||||
import { App } from "../../features/apps/app";
|
||||
import { App } from "../../features/system/configs/app";
|
||||
import { useSystemManager } from "../../hooks";
|
||||
|
||||
export interface WindowFallbackViewProps {
|
||||
error?: Error;
|
||||
|
|
@ -13,6 +13,7 @@ export interface WindowFallbackViewProps {
|
|||
|
||||
// I don't know why this component's type needs to be ReactNode instead of FC, it has something to do with the way it's implemented
|
||||
export function WindowFallbackView({ error, resetErrorBoundary: _resetErrorBoundary, app, closeWindow }: WindowFallbackViewProps): undefined {
|
||||
const { appsConfig } = useSystemManager();
|
||||
const { alert } = useAlert();
|
||||
const [alerted, setAlerted] = useState(false);
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ export function WindowFallbackView({ error, resetErrorBoundary: _resetErrorBound
|
|||
alert({
|
||||
title: `${app.name} has stopped working`,
|
||||
text: `${error.name}: ${error.message}`,
|
||||
iconUrl: AppsManager.getAppIconUrl(app.id),
|
||||
iconUrl: appsConfig.getAppById(app.id)?.iconUrl as string | undefined,
|
||||
size: new Vector2(350, 150),
|
||||
single: true
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { Vector2 } from "../../features/math/vector2";
|
|||
import { faWindowMaximize } from "@fortawesome/free-regular-svg-icons";
|
||||
import utilStyles from "../../styles/utils.module.css";
|
||||
import { useContextMenu } from "../../hooks/modals/contextMenu";
|
||||
import { AppsManager } from "../../features/apps/appsManager";
|
||||
import { ClickAction } from "../actions/actions/ClickAction";
|
||||
import { Actions } from "../actions/Actions";
|
||||
import { useScreenDimensions } from "../../hooks/_utils/screen";
|
||||
|
|
@ -41,7 +40,7 @@ export interface WindowProps extends WindowOptions {
|
|||
}
|
||||
|
||||
export const WindowView: FC<WindowProps> = memo(({ id, app, size, position, onInteract, options, active, fullscreen, minimized, toggleMinimized, index }) => {
|
||||
const { systemName, windowsConfig } = useSystemManager();
|
||||
const { systemName, windowsConfig, appsConfig } = useSystemManager();
|
||||
const windowsManager = useWindowsManager();
|
||||
const nodeRef = useRef(null);
|
||||
const { openWindowedModal } = useWindowedModal();
|
||||
|
|
@ -50,7 +49,7 @@ export const WindowView: FC<WindowProps> = memo(({ id, app, size, position, onIn
|
|||
const [maximized, setMaximized] = useState(fullscreen ?? false);
|
||||
const [screenWidth, screenHeight] = useScreenDimensions();
|
||||
const [title, setTitle] = useState(app?.name ?? "");
|
||||
const [iconUrl, setIconUrl] = useState(app ? AppsManager.getAppIconUrl(app?.id) : "");
|
||||
const [iconUrl, setIconUrl] = useState<string>(app ? appsConfig.getAppById(app?.id)?.iconUrl ?? "" : "");
|
||||
const zIndex = useZIndex({ groupIndex: ZIndexManager.GROUPS.WINDOWS, index: index ?? 0 });
|
||||
|
||||
const { onContextMenu, ShortcutsListener } = useContextMenu({ Actions: (props) =>
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
export const APPS = {
|
||||
TERMINAL: "terminal",
|
||||
SETTINGS: "settings",
|
||||
MEDIA_VIEWER: "media-viewer",
|
||||
TEXT_EDITOR: "text-editor",
|
||||
FILE_EXPLORER: "file-explorer",
|
||||
CALCULATOR: "calculator",
|
||||
BROWSER: "browser",
|
||||
LOGIC_SIM: "logic-sim",
|
||||
};
|
||||
|
||||
export type AppKey = keyof typeof APPS;
|
||||
|
||||
export const APP_NAMES: Record<AppKey, string> = {
|
||||
TERMINAL: "Commands",
|
||||
SETTINGS: "Settings",
|
||||
MEDIA_VIEWER: "Photos",
|
||||
TEXT_EDITOR: "Notes",
|
||||
FILE_EXPLORER: "Files",
|
||||
CALCULATOR: "Maths",
|
||||
BROWSER: "Browser",
|
||||
LOGIC_SIM: "Logic Sim (WIP)"
|
||||
};
|
||||
|
||||
export const APP_DESCRIPTIONS: Record<AppKey, string | null> = {
|
||||
TERMINAL: "A command line tool inspired by the Unix shell that runs entirely in your browser and uses a virtual file system.",
|
||||
SETTINGS: "Configure ProzillaOS' settings and customize your experience.",
|
||||
TEXT_EDITOR: "Simple text editor for reading and writing text documents.",
|
||||
FILE_EXPLORER: "Browse and manage your virtual files.",
|
||||
CALCULATOR: "Simple calculator app.",
|
||||
BROWSER: "Browse the internet.",
|
||||
LOGIC_SIM: "Create digital logic circuits using the online simulator.",
|
||||
MEDIA_VIEWER: null,
|
||||
};
|
||||
|
||||
export const APP_ICONS = {
|
||||
TERMINAL: `/assets/apps/icons/${APPS.TERMINAL}.svg`,
|
||||
SETTINGS: `/assets/apps/icons/${APPS.SETTINGS}.svg`,
|
||||
MEDIA_VIEWER: `/assets/apps/icons/${APPS.MEDIA_VIEWER}.svg`,
|
||||
TEXT_EDITOR: `/assets/apps/icons/${APPS.TEXT_EDITOR}.svg`,
|
||||
FILE_EXPLORER: `/assets/apps/icons/${APPS.FILE_EXPLORER}.svg`,
|
||||
CALCULATOR: `/assets/apps/icons/${APPS.CALCULATOR}.svg`,
|
||||
};
|
||||
3
packages/core/src/constants/index.ts
Normal file
3
packages/core/src/constants/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { DIALOG_CONTENT_TYPES } from "./modals.const";
|
||||
export { CODE_EXTENSIONS } from "./virtualDrive.const";
|
||||
export { ANSI } from "./utils.const";
|
||||
19
packages/core/src/constants/utils.const.ts
Normal file
19
packages/core/src/constants/utils.const.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
export const ANSI = {
|
||||
fg: {
|
||||
black: "\u001b[30m",
|
||||
red: "\u001b[31m",
|
||||
green: "\u001b[32m",
|
||||
yellow: "\u001b[33m",
|
||||
blue: "\u001b[34m",
|
||||
magenta: "\u001b[35m",
|
||||
cyan: "\u001b[36m",
|
||||
white: "\u001b[37m",
|
||||
},
|
||||
bg: {
|
||||
|
||||
},
|
||||
decoration: {
|
||||
dim: "\u001b[2m",
|
||||
},
|
||||
reset: "\u001b[0m",
|
||||
};
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import { Vector2 } from "../math/vector2";
|
||||
import { WindowProps } from "../../components/windows/WindowView";
|
||||
import { FC } from "react";
|
||||
|
||||
export class App {
|
||||
name: string = "App";
|
||||
id: string = "app";
|
||||
windowContent?: FC<JSX.IntrinsicAttributes & WindowProps>;
|
||||
windowOptions?: {
|
||||
size: Vector2;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
isActive: boolean = false;
|
||||
isPinned?: boolean;
|
||||
|
||||
/**
|
||||
* @param windowOptions - Default window options
|
||||
*/
|
||||
constructor(name: App["name"], id: App["id"], windowContent: App["windowContent"], windowOptions?: App["windowOptions"]) {
|
||||
Object.assign(this, { name, id, windowContent, windowOptions });
|
||||
|
||||
if (this.windowContent == null)
|
||||
console.warn(`${this.name} (${this.id}) is missing the windowContent property.`);
|
||||
}
|
||||
|
||||
WindowContent = (props: JSX.IntrinsicAttributes & WindowProps) => {
|
||||
props = { ...props, ...this.windowOptions };
|
||||
|
||||
if (this.windowContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <this.windowContent {...props}/>;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
import { App } from "./app";
|
||||
|
||||
export class AppsManager {
|
||||
static APPS: App[] = [];
|
||||
|
||||
static getAppById(id: string): App | null {
|
||||
let application: App | null = null;
|
||||
|
||||
this.APPS.forEach((app) => {
|
||||
if (app.id === id) {
|
||||
application = app;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the app associated with a file extension
|
||||
*/
|
||||
static getAppByFileExtension(fileExtension: string): App | null {
|
||||
return null;
|
||||
|
||||
// let app: App | null = null;
|
||||
|
||||
// if (IMAGE_FORMATS.includes(fileExtension))
|
||||
// return this.getAppById(APPS.MEDIA_VIEWER);
|
||||
|
||||
// switch (fileExtension) {
|
||||
// default:
|
||||
// app = this.getAppById(APPS.TEXT_EDITOR);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url of an icon inside the icons folder or the default icon of an app
|
||||
*/
|
||||
static getAppIconUrl(appId: string, iconName?: string): string {
|
||||
if (iconName == null) {
|
||||
return `/assets/apps/icons/${appId}.svg`;
|
||||
} else {
|
||||
return `/assets/apps/${appId}/icons/${iconName}.svg`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { AppsManager } from "./appsManager";
|
||||
export { App } from "./app";
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
export * from "./system/configs";
|
||||
export * from "./virtual-drive";
|
||||
export * from "./_utils";
|
||||
|
||||
export { ModalsManager } from "./modals/modalsManager";
|
||||
export { SettingsManager } from "./settings/settingsManager";
|
||||
export { StorageManager } from "./storage/storageManager";
|
||||
export { TrackingManager } from "./tracking/trackingManager";
|
||||
export { WindowsManager } from "./windows/windowsManager";
|
||||
export { ZIndexManager } from "./z-index/zIndexManager";
|
||||
export * from "./system/configs";
|
||||
export * from "./_utils";
|
||||
export * from "./apps";
|
||||
export * from "./virtual-drive";
|
||||
|
||||
export { Vector2 } from "./math/vector2";
|
||||
60
packages/core/src/features/system/configs/app.tsx
Normal file
60
packages/core/src/features/system/configs/app.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { Vector2 } from "../../math/vector2";
|
||||
import { WindowProps } from "../../../components/windows/WindowView";
|
||||
import { FC } from "react";
|
||||
|
||||
const validIdRegex = /^[a-zA-Z0-9-]+$/;
|
||||
|
||||
export class App<AppProps extends WindowProps = WindowProps> {
|
||||
name: string = "App";
|
||||
id: string = "app";
|
||||
windowContent: FC<AppProps>;
|
||||
windowOptions?: {
|
||||
size: Vector2;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
description: string | null = null;
|
||||
iconUrl: string | null = null;
|
||||
|
||||
isActive: boolean = false;
|
||||
isPinned?: boolean;
|
||||
|
||||
/**
|
||||
* @param windowOptions - Default window options
|
||||
*/
|
||||
constructor(name: App["name"], id: App["id"], windowContent: App<AppProps>["windowContent"], windowOptions?: App["windowOptions"]) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.windowContent = windowContent;
|
||||
this.windowOptions = windowOptions;
|
||||
|
||||
if (this.id.match(validIdRegex) == null)
|
||||
throw new Error(`Invalid app ID found: ${this.id}`
|
||||
+ "\nApp IDs may only contain letters (a-zA-Z), numbers (0-9) and dashes (-).");
|
||||
}
|
||||
|
||||
WindowContent = (props: AppProps) => {
|
||||
props = { ...props, ...this.windowOptions };
|
||||
|
||||
if (this.windowContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <this.windowContent {...props}/>;
|
||||
};
|
||||
|
||||
setDescription(description: App["description"]): this {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
setIconUrl(iconUrl: App["iconUrl"]): this {
|
||||
this.iconUrl = iconUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
setName(name: string): this {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,58 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { App } from "../../apps";
|
||||
import { App } from ".";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface AppsConfigOptions {
|
||||
apps: App[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
apps: App<any>[];
|
||||
}
|
||||
|
||||
export class AppsConfig {
|
||||
apps: AppsConfigOptions["apps"];
|
||||
apps: AppsConfigOptions["apps"] = [];
|
||||
|
||||
constructor(options?: OptionalInterface<AppsConfigOptions>) {
|
||||
constructor(options: OptionalInterface<AppsConfigOptions> = {}) {
|
||||
const { apps } = options as AppsConfigOptions;
|
||||
this.apps = apps ?? [];
|
||||
|
||||
const appIds: string[] = [];
|
||||
apps.forEach((app) => {
|
||||
if (appIds.includes(app.id))
|
||||
throw new Error(`Duplicate app ID found: ${app.id}`
|
||||
+ "\nApp IDs must be unique.");
|
||||
|
||||
this.apps.push(app);
|
||||
appIds.push(app.id);
|
||||
});
|
||||
}
|
||||
|
||||
getAppById(id: string): App | null {
|
||||
let resultApp: App | null = null;
|
||||
|
||||
this.apps.forEach((app) => {
|
||||
if (app.id === id) {
|
||||
resultApp = app;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return resultApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the app associated with a file extension
|
||||
*/
|
||||
getAppByFileExtension(fileExtension: string): App | null {
|
||||
return null;
|
||||
|
||||
// let app: App | null = null;
|
||||
|
||||
// if (IMAGE_FORMATS.includes(fileExtension))
|
||||
// return this.getAppById(APPS.MEDIA_VIEWER);
|
||||
|
||||
// switch (fileExtension) {
|
||||
// default:
|
||||
// app = this.getAppById(APPS.TEXT_EDITOR);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// return app;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface DesktopConfigOptions {
|
||||
/** Array of URLs of wallpaper images */
|
||||
|
|
@ -25,7 +25,7 @@ export class DesktopConfig {
|
|||
defaultIconSize: DesktopConfigOptions["defaultIconSize"];
|
||||
defaultIconDirection: DesktopConfigOptions["defaultIconDirection"];
|
||||
|
||||
constructor(options?: OptionalInterface<DesktopConfigOptions>) {
|
||||
constructor(options: OptionalInterface<DesktopConfigOptions> = {}) {
|
||||
const { wallpapers, defaultWallpaper, defaultIconSize, defaultIconDirection } = options as DesktopConfigOptions;
|
||||
|
||||
this.wallpapers = wallpapers ?? [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
export { App } from "./app";
|
||||
export { AppsConfig } from "./appsConfig";
|
||||
export { DesktopConfig } from "./desktopConfig";
|
||||
export { MiscConfig } from "./miscConfig";
|
||||
export { ModalsConfig } from "./modalsConfig";
|
||||
export { TaskbarConfig } from "./taskbarConfig";
|
||||
export { TrackingConfig } from "./trackingConfig";
|
||||
export { WindowsConfig } from "./windowsConfig";
|
||||
export { WindowsConfig } from "./windowsConfig";
|
||||
export { VirtualDriveConfig } from "./virtualDriveConfig";
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface MiscConfigOptions {
|
||||
/**
|
||||
|
|
@ -11,8 +11,9 @@ export interface MiscConfigOptions {
|
|||
export class MiscConfig {
|
||||
doubleClickDelay: MiscConfigOptions["doubleClickDelay"];
|
||||
|
||||
constructor(options?: OptionalInterface<MiscConfigOptions>) {
|
||||
constructor(options: OptionalInterface<MiscConfigOptions> = {}) {
|
||||
const { doubleClickDelay } = options as MiscConfigOptions;
|
||||
|
||||
this.doubleClickDelay = doubleClickDelay ?? 250;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
import { Vector2 } from "../../math/vector2";
|
||||
|
||||
export interface ModalsConfigOptions {
|
||||
|
|
@ -19,8 +19,9 @@ export class ModalsConfig {
|
|||
defaultDialogSize: ModalsConfigOptions["defaultDialogSize"];
|
||||
defaultFileSelectorSize: ModalsConfigOptions["defaultFileSelectorSize"];
|
||||
|
||||
constructor(options?: OptionalInterface<ModalsConfigOptions>) {
|
||||
constructor(options: OptionalInterface<ModalsConfigOptions> = {}) {
|
||||
const { defaultDialogSize, defaultFileSelectorSize } = options as ModalsConfigOptions;
|
||||
|
||||
this.defaultDialogSize = defaultDialogSize ?? new Vector2(400, 200);
|
||||
this.defaultFileSelectorSize = defaultFileSelectorSize ?? new Vector2(700, 400);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface TaskbarConfigOptions {
|
||||
/**
|
||||
|
|
@ -11,8 +11,9 @@ export interface TaskbarConfigOptions {
|
|||
export class TaskbarConfig {
|
||||
height: TaskbarConfigOptions["height"];
|
||||
|
||||
constructor(options?: OptionalInterface<TaskbarConfigOptions>) {
|
||||
constructor(options: OptionalInterface<TaskbarConfigOptions> = {}) {
|
||||
const { height } = options as TaskbarConfigOptions;
|
||||
|
||||
this.height = height ?? 3 * 16;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface TrackingConfigOptions {
|
||||
/**
|
||||
|
|
@ -15,8 +15,9 @@ export class TrackingConfig {
|
|||
enabled: TrackingConfigOptions["enabled"];
|
||||
GAMeasurementId: TrackingConfigOptions["GAMeasurementId"];
|
||||
|
||||
constructor(options?: OptionalInterface<TrackingConfigOptions>) {
|
||||
constructor(options: OptionalInterface<TrackingConfigOptions> = {}) {
|
||||
const { enabled, GAMeasurementId } = options as TrackingConfigOptions;
|
||||
|
||||
this.enabled = enabled ?? true;
|
||||
this.GAMeasurementId = GAMeasurementId ?? "G-ZFQRR9DP3C";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import { OptionalInterface } from "../../../types/util";
|
||||
|
||||
export interface VirtualDriveConfigOptions {
|
||||
fileIcon: string;
|
||||
infoFileIcon: string;
|
||||
textFileIcon: string;
|
||||
codeFileIcon: string;
|
||||
|
||||
folderIcon: string;
|
||||
imagesFolderIcon: string;
|
||||
textFolderIcon: string;
|
||||
folderLinkIcon: string;
|
||||
}
|
||||
|
||||
export class VirtualDriveConfig {
|
||||
fileIcon: VirtualDriveConfigOptions["fileIcon"];
|
||||
infoFileIcon: VirtualDriveConfigOptions["infoFileIcon"];
|
||||
textFileIcon: VirtualDriveConfigOptions["textFileIcon"];
|
||||
codeFileIcon: VirtualDriveConfigOptions["codeFileIcon"];
|
||||
|
||||
folderIcon: VirtualDriveConfigOptions["folderIcon"];
|
||||
imagesFolderIcon: VirtualDriveConfigOptions["imagesFolderIcon"];
|
||||
textFolderIcon: VirtualDriveConfigOptions["textFolderIcon"];
|
||||
folderLinkIcon: VirtualDriveConfigOptions["folderLinkIcon"];
|
||||
|
||||
constructor(options: OptionalInterface<VirtualDriveConfigOptions> = {}) {
|
||||
const { fileIcon, infoFileIcon, textFileIcon, codeFileIcon, folderIcon, imagesFolderIcon, textFolderIcon, folderLinkIcon } = options as VirtualDriveConfigOptions;
|
||||
|
||||
this.fileIcon = fileIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/file.svg";
|
||||
this.infoFileIcon = infoFileIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/file-info.svg";
|
||||
this.textFileIcon = textFileIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/file-text.svg";
|
||||
this.codeFileIcon = codeFileIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/file-code.svg";
|
||||
|
||||
this.folderIcon = folderIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/folder.svg";
|
||||
this.imagesFolderIcon = imagesFolderIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/folder-images.svg";
|
||||
this.textFolderIcon = textFolderIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/folder-text.svg";
|
||||
this.folderLinkIcon = folderLinkIcon ?? "https://os.prozilla.dev/assets/apps/file-explorer/icons/folder-link.svg";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { OptionalInterface } from "../../../types/global";
|
||||
import { OptionalInterface } from "../../../types/util";
|
||||
import { Vector2 } from "../../math/vector2";
|
||||
|
||||
export interface WindowsConfigOptions {
|
||||
|
|
@ -24,8 +24,9 @@ export class WindowsConfig {
|
|||
titleSeparator: WindowsConfigOptions["titleSeparator"];
|
||||
minScreenSize: WindowsConfigOptions["minScreenSize"];
|
||||
|
||||
constructor(options?: OptionalInterface<WindowsConfigOptions>) {
|
||||
constructor(options: OptionalInterface<WindowsConfigOptions> = {}) {
|
||||
const { screenMargin, titleSeparator, minScreenSize } = options as WindowsConfigOptions;
|
||||
|
||||
this.screenMargin = screenMargin ?? 32;
|
||||
this.titleSeparator = titleSeparator ?? "-";
|
||||
this.minScreenSize = minScreenSize ?? new Vector2(350, 350);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { formatRelativeTime } from "../_utils";
|
||||
import { VirtualDriveConfig } from "./configs";
|
||||
import { AppsConfig } from "./configs/appsConfig";
|
||||
import { DesktopConfig } from "./configs/desktopConfig";
|
||||
import { MiscConfig } from "./configs/miscConfig";
|
||||
|
|
@ -17,6 +18,7 @@ export interface SystemManagerParams {
|
|||
taskbarConfig: TaskbarConfig;
|
||||
trackingConfig: TrackingConfig;
|
||||
windowsConfig: WindowsConfig;
|
||||
virtualDriveConfig: VirtualDriveConfig;
|
||||
};
|
||||
|
||||
export class SystemManager {
|
||||
|
|
@ -31,6 +33,7 @@ export class SystemManager {
|
|||
taskbarConfig: TaskbarConfig;
|
||||
trackingConfig: TrackingConfig;
|
||||
windowsConfig: WindowsConfig;
|
||||
virtualDriveConfig: VirtualDriveConfig;
|
||||
|
||||
constructor({
|
||||
systemName,
|
||||
|
|
@ -41,7 +44,8 @@ export class SystemManager {
|
|||
modalsConfig,
|
||||
taskbarConfig,
|
||||
trackingConfig,
|
||||
windowsConfig
|
||||
windowsConfig,
|
||||
virtualDriveConfig
|
||||
}: SystemManagerParams) {
|
||||
this.systemName = systemName ?? "ProzillaOS";
|
||||
this.tagLine = tagLine ?? "Web-based Operating System";
|
||||
|
|
@ -53,6 +57,7 @@ export class SystemManager {
|
|||
this.taskbarConfig = taskbarConfig;
|
||||
this.trackingConfig = trackingConfig;
|
||||
this.windowsConfig = windowsConfig;
|
||||
this.virtualDriveConfig = virtualDriveConfig;
|
||||
|
||||
this.#startDate = new Date();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { APPS } from "../../../constants/apps.const";
|
||||
import { IMAGE_FORMATS } from "../../../../../apps/media-viewer/config/mediaViewer.config";
|
||||
import { AppsManager } from "../../apps/appsManager";
|
||||
import { WindowsManager } from "../../windows/windowsManager";
|
||||
import { VirtualBase, VirtualBaseJson } from "../virtualBase";
|
||||
|
||||
|
|
@ -107,7 +105,7 @@ export class VirtualFile extends VirtualBase {
|
|||
return await fetch(this.source).then((response) =>
|
||||
response.text()
|
||||
).catch((error) => {
|
||||
console.error(`Error while reading file with id "${this.id}":`, error);
|
||||
console.error(`Error while reading file with ID: ${this.id}\n`, error);
|
||||
return null;
|
||||
}) as string;
|
||||
}
|
||||
|
|
@ -125,10 +123,12 @@ export class VirtualFile extends VirtualBase {
|
|||
if (this.source != null && this.extension != null && IMAGE_FORMATS.includes(this.extension))
|
||||
return this.source;
|
||||
|
||||
const { virtualDriveConfig } = this.getRoot().systemManager;
|
||||
|
||||
switch (this.extension) {
|
||||
case "txt":
|
||||
case "md":
|
||||
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-text");
|
||||
iconUrl = virtualDriveConfig.textFileIcon;
|
||||
break;
|
||||
case "xml":
|
||||
case "js":
|
||||
|
|
@ -139,10 +139,10 @@ export class VirtualFile extends VirtualBase {
|
|||
case "css":
|
||||
case "html":
|
||||
case "yml":
|
||||
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file-code");
|
||||
iconUrl = virtualDriveConfig.codeFileIcon;
|
||||
break;
|
||||
default:
|
||||
iconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file");
|
||||
iconUrl = virtualDriveConfig.fileIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { VirtualFile } from ".";
|
||||
import { APPS } from "../../../constants/apps.const";
|
||||
import { AppsManager } from "../../apps/appsManager";
|
||||
import { VirtualFileJson } from "./virtualFile";
|
||||
|
||||
export interface VirtualFileLinkJson extends VirtualFileJson {
|
||||
|
|
@ -101,7 +99,9 @@ export class VirtualFileLink extends VirtualFile {
|
|||
}
|
||||
|
||||
getIconUrl(...args: Parameters<VirtualFile["getIconUrl"]>): ReturnType<VirtualFile["getIconUrl"]> {
|
||||
const defaultIconUrl = AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file");
|
||||
const { virtualDriveConfig } = this.getRoot().systemManager;
|
||||
const defaultIconUrl = virtualDriveConfig.fileIcon;
|
||||
|
||||
if (this.isValid()) {
|
||||
return this.iconUrl ?? this.linkedFile?.getIconUrl(...args) ?? defaultIconUrl;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import { APPS } from "../../../constants/apps.const";
|
||||
import { AppsManager } from "../../apps/appsManager";
|
||||
import { removeFromArray } from "../../_utils/array.utils";
|
||||
import { WindowsManager } from "../../windows/windowsManager";
|
||||
import { VirtualFileJson } from "../file/virtualFile";
|
||||
import { VirtualBase, VirtualBaseJson } from "../virtualBase";
|
||||
import { VirtualFolderLink } from ".";
|
||||
import { VirtualFile, VirtualFileLink } from "../file";
|
||||
import { fileExplorer } from "@prozilla-os/file-explorer";
|
||||
|
||||
export interface VirtualFolderJson extends VirtualBaseJson {
|
||||
fls?: VirtualFileJson[];
|
||||
|
|
@ -289,7 +288,7 @@ export class VirtualFolder extends VirtualBase {
|
|||
* Opens this folder in file explorer
|
||||
*/
|
||||
open(windowsManager: WindowsManager) {
|
||||
return windowsManager.open(APPS.FILE_EXPLORER, { path: this.path });
|
||||
return windowsManager.open(fileExplorer.id, { path: this.path });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -353,7 +352,8 @@ export class VirtualFolder extends VirtualBase {
|
|||
if (this.iconUrl != null)
|
||||
return this.iconUrl;
|
||||
|
||||
return AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder");
|
||||
const { virtualDriveConfig } = this.getRoot().systemManager;
|
||||
return virtualDriveConfig.folderIcon;
|
||||
}
|
||||
|
||||
toJSON(): VirtualFolderJson | null {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { APPS } from "../../../constants/apps.const";
|
||||
import { AppsManager } from "../../apps/appsManager";
|
||||
import { VirtualFolder } from ".";
|
||||
import { VirtualFolderJson } from "./virtualFolder";
|
||||
|
||||
|
|
@ -60,7 +58,8 @@ export class VirtualFolderLink extends VirtualFolder {
|
|||
if (this.isValid() && this.linkedFolder?.iconUrl)
|
||||
return this.linkedFolder.iconUrl;
|
||||
|
||||
return AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-link");
|
||||
const { virtualDriveConfig } = this.getRoot().systemManager;
|
||||
return virtualDriveConfig.folderLinkIcon;
|
||||
}
|
||||
|
||||
toJSON(): VirtualFolderLinkJson | null {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { APPS } from "../../../constants/apps.const";
|
||||
import { AppsManager } from "../../apps/appsManager";
|
||||
import { SystemManager } from "../../system/systemManager";
|
||||
import { VirtualFile, VirtualFileLink } from "../file";
|
||||
import { VirtualFolder, VirtualFolderLink } from "../folder";
|
||||
|
|
@ -9,7 +7,7 @@ import { VirtualRoot } from "./virtualRoot";
|
|||
* Loads default data on the virtual root
|
||||
*/
|
||||
export function loadDefaultData(systemManager: SystemManager, virtualRoot: VirtualRoot) {
|
||||
const { desktopConfig } = systemManager;
|
||||
const { desktopConfig, virtualDriveConfig } = systemManager;
|
||||
const linkedPaths: Record<string, string> = {};
|
||||
|
||||
virtualRoot.createFolder("home", (folder) => {
|
||||
|
|
@ -27,7 +25,7 @@ export function loadDefaultData(systemManager: SystemManager, virtualRoot: Virtu
|
|||
});
|
||||
})
|
||||
.createFolder("Pictures", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-images"));
|
||||
folder.setIconUrl(virtualDriveConfig.imagesFolderIcon);
|
||||
folder.createFolder("Wallpapers", (folder) => {
|
||||
folder.setProtected(true);
|
||||
for (let i = 0; i < desktopConfig.wallpapers.length; i++) {
|
||||
|
|
@ -52,13 +50,13 @@ export function loadDefaultData(systemManager: SystemManager, virtualRoot: Virtu
|
|||
linkedPaths.images = folder.path;
|
||||
})
|
||||
.createFolder("Documents", (folder) => {
|
||||
folder.setIconUrl(AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-text"));
|
||||
folder.setIconUrl(virtualDriveConfig.textFolderIcon);
|
||||
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"));
|
||||
.setIconUrl(virtualDriveConfig.infoFileIcon);
|
||||
linkedPaths.info = file.path;
|
||||
}).createFile("Prozilla", "md", (file) => {
|
||||
file.setProtected(true)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class VirtualRoot extends VirtualFolder {
|
|||
shortcuts: Record<string, VirtualFile | VirtualFileLink | VirtualFolder | VirtualFolderLink>;
|
||||
initiated: boolean = false;
|
||||
loadedDefaultData: boolean = false;
|
||||
#systemManager: SystemManager;
|
||||
systemManager: SystemManager;
|
||||
|
||||
static EVENT_NAMES = {
|
||||
ERROR: "error"
|
||||
|
|
@ -28,13 +28,13 @@ export class VirtualRoot extends VirtualFolder {
|
|||
constructor(systemManager: SystemManager) {
|
||||
super("root");
|
||||
this.root = this;
|
||||
this.#systemManager = systemManager;
|
||||
this.systemManager = systemManager;
|
||||
this.isRoot = true;
|
||||
this.shortcuts = {};
|
||||
}
|
||||
|
||||
loadDefaultData() {
|
||||
loadDefaultData(this.#systemManager, this);
|
||||
loadDefaultData(this.systemManager, this);
|
||||
}
|
||||
|
||||
loadData() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { APPS } from "../../constants/apps.const";
|
||||
import { AppsManager } from "../apps/appsManager";
|
||||
import { EventEmitter, EventNamesMap } from "../_utils/event.utils";
|
||||
import { VirtualRoot } from "./root/virtualRoot";
|
||||
import { VirtualFile } from "./file";
|
||||
|
|
@ -81,10 +79,12 @@ export class VirtualBase extends EventEmitter<EventNamesMap> {
|
|||
}
|
||||
|
||||
getIconUrl(): string {
|
||||
return this.iconUrl
|
||||
?? this.linkedFile?.iconUrl
|
||||
?? this.linkedFolder?.iconUrl
|
||||
?? AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file");
|
||||
if (this.iconUrl != null) return this.iconUrl;
|
||||
if (this.linkedFile?.iconUrl != null) return this.linkedFile.iconUrl;
|
||||
if (this.linkedFolder?.iconUrl != null) return this.linkedFolder.iconUrl;
|
||||
|
||||
const { virtualDriveConfig } = this.getRoot().systemManager;
|
||||
return virtualDriveConfig.fileIcon;
|
||||
}
|
||||
|
||||
getType(): string {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { randomRange } from "../_utils/math.utils";
|
||||
import { App } from "../apps/app";
|
||||
import { AppsManager } from "../apps/appsManager";
|
||||
import { App } from "../system/configs/app";
|
||||
import { Vector2 } from "../math/vector2";
|
||||
import { SystemManager } from "../system/systemManager";
|
||||
import { TrackingManager } from "../tracking/trackingManager";
|
||||
|
|
@ -36,7 +35,8 @@ export class WindowsManager {
|
|||
}
|
||||
|
||||
open(appId: string, options?: WindowOptions | null): object | null {
|
||||
const app = AppsManager.getAppById(appId);
|
||||
const { appsConfig, windowsConfig, taskbarConfig } = this.#systemManager;
|
||||
const app = appsConfig.getAppById(appId);
|
||||
|
||||
if (app == null) {
|
||||
console.warn(`Failed to open app ${appId}: app not found`);
|
||||
|
|
@ -44,8 +44,7 @@ export class WindowsManager {
|
|||
}
|
||||
|
||||
const size = options?.size ?? app.windowOptions?.size ?? new Vector2(700, 400);
|
||||
|
||||
const { windowsConfig, taskbarConfig } = this.#systemManager;
|
||||
|
||||
const availableScreenSpace = new Vector2(
|
||||
window.innerWidth - windowsConfig.screenMargin * 2,
|
||||
window.innerHeight - windowsConfig.screenMargin * 2 - taskbarConfig.height
|
||||
|
|
@ -112,7 +111,8 @@ export class WindowsManager {
|
|||
openFile(file: VirtualFile, options: object = {}): object | null {
|
||||
if (file.extension == null) return null;
|
||||
|
||||
const app = AppsManager.getAppByFileExtension(file?.extension);
|
||||
const { appsConfig } = this.#systemManager;
|
||||
const app = appsConfig.getAppByFileExtension(file?.extension);
|
||||
if (app != null) {
|
||||
return this.open(app.id, { file, ...options });
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { App } from "../../features/apps/app";
|
||||
import { App } from "../../features/system/configs/app";
|
||||
import { VirtualFolder } from "../../features/virtual-drive/folder";
|
||||
import { useVirtualRoot } from "../virtual-drive/virtualRootContext";
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ interface SystemManagerProviderProps {
|
|||
taskbarConfig: SystemManagerParams["taskbarConfig"];
|
||||
trackingConfig: SystemManagerParams["trackingConfig"];
|
||||
windowsConfig: SystemManagerParams["windowsConfig"];
|
||||
virtualDriveConfig: SystemManagerParams["virtualDriveConfig"];
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
export * from "./components";
|
||||
export * from "./features";
|
||||
export * from "./styles";
|
||||
export * from "./components";
|
||||
export * from "./hooks";
|
||||
export { default as utilStyles } from "./src/styles/utils.module.css";
|
||||
export { DIALOG_CONTENT_TYPES } from "./constants/modals.const";
|
||||
export { CODE_EXTENSIONS } from "./constants/virtualDrive.const";
|
||||
export * from "./constants";
|
||||
|
|
|
|||
3
packages/core/src/styles/index.ts
Normal file
3
packages/core/src/styles/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import "./global.css";
|
||||
|
||||
export { default as utilStyles } from "./utils.module.css";
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { ANSI } from "../../src/config/apps/terminal.config";
|
||||
import { ANSI } from "@prozilla-os/core";
|
||||
|
||||
export type status = "error" | "info" | "file" | "success" | "start";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import fs from "node:fs";
|
||||
import { ANSI } from "../src/config/apps/terminal.config";
|
||||
import { REPO } from "../src/config/deploy.config";
|
||||
import { ANSI } from "@prozilla-os/core";
|
||||
|
||||
const API_URL = "https://api.github.com/";
|
||||
const TREE_PATH = "public/config/tree.json";
|
||||
|
|
|
|||
11
src/Main.tsx
11
src/Main.tsx
|
|
@ -2,13 +2,20 @@ import { ReactElement } from "react";
|
|||
import { Router } from "./router/Router";
|
||||
import { ProzillaOS } from "@prozilla-os/core";
|
||||
import { desktopConfig } from "./config/desktop.config";
|
||||
import { NAME, TAG_LINE } from "./config/branding.config";
|
||||
import { appsConfig } from "./config/apps.config";
|
||||
import { virtualDriveConfig } from "./config/virtualDrive.config";
|
||||
|
||||
export function Main(): ReactElement {
|
||||
return <ProzillaOS
|
||||
systemName={NAME}
|
||||
tagLine={TAG_LINE}
|
||||
config={{
|
||||
desktop: desktopConfig
|
||||
desktop: desktopConfig,
|
||||
apps: appsConfig,
|
||||
virtualDrive: virtualDriveConfig,
|
||||
}}
|
||||
>
|
||||
<Router/>
|
||||
</ProzillaOS>;
|
||||
};
|
||||
}
|
||||
8
src/config/apps.config.ts
Normal file
8
src/config/apps.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { AppsConfig } from "@prozilla-os/core";
|
||||
import { fileExplorer } from "@prozilla-os/file-explorer";
|
||||
|
||||
export const appsConfig = new AppsConfig({
|
||||
apps: [
|
||||
fileExplorer.setName("Files"),
|
||||
],
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { ANSI } from "./apps/terminal.config";
|
||||
import { ANSI } from "@prozilla-os/core";
|
||||
|
||||
export const NAME = "ProzillaOS";
|
||||
export const TAG_LINE = "Web-based Operating System";
|
||||
|
|
|
|||
12
src/config/virtualDrive.config.ts
Normal file
12
src/config/virtualDrive.config.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { VirtualDriveConfig } from "@prozilla-os/core";
|
||||
|
||||
export const virtualDriveConfig = new VirtualDriveConfig({
|
||||
fileIcon: "/assets/apps/file-explorer/icons/file.svg",
|
||||
infoFileIcon: "/assets/apps/file-explorer/icons/file-info.svg",
|
||||
textFileIcon: "/assets/apps/file-explorer/icons/file-text.svg",
|
||||
codeFileIcon: "/assets/apps/file-explorer/icons/file-code.svg",
|
||||
folderIcon: "/assets/apps/file-explorer/icons/folder.svg",
|
||||
imagesFolderIcon: "/assets/apps/file-explorer/icons/folder-images.svg",
|
||||
textFolderIcon: "/assets/apps/file-explorer/icons/folder-text.svg",
|
||||
folderLinkIcon: "/assets/apps/file-explorer/icons/folder-link.svg",
|
||||
});
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./styles/global.css";
|
||||
import { Main } from "./Main";
|
||||
import { ASCII_LOGO, NAME } from "./config/branding.config";
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ import { BrowserRouter, Route, Routes } from "react-router-dom";
|
|||
import { DefaultRoute } from "./routes/DefaultRoute";
|
||||
import { StandaloneRoute } from "./routes/StandaloneRoute";
|
||||
import { NoRoute } from "./routes/NoRoute";
|
||||
import { App, AppsManager } from "@prozilla-os/core";
|
||||
import { useSystemManager } from "@prozilla-os/core";
|
||||
|
||||
export function Router() {
|
||||
const { appsConfig } = useSystemManager();
|
||||
|
||||
return <BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/">
|
||||
<Route index element={<DefaultRoute/>}/>
|
||||
{AppsManager.APPS.map((app: App) =>
|
||||
{appsConfig.apps.map((app) =>
|
||||
<Route path={app.id} key={app.id} element={<StandaloneRoute app={app}/>}/>
|
||||
)}
|
||||
<Route path="*" element={<NoRoute/>}/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
import styles from "./StandaloneRoute.module.css";
|
||||
import { NAME } from "../../config/branding.config";
|
||||
import { App, AppsManager, generateUrl, getViewportParams, ModalsView, openUrl, setViewportIcon, setViewportTitle } from "@prozilla-os/core";
|
||||
import { StandaloneHeader } from "../../components/standalone-header/StandaloneHeader";
|
||||
import { App, generateUrl, getViewportParams, ModalsView, openUrl, setViewportIcon, setViewportTitle } from "@prozilla-os/core";
|
||||
import { StandaloneHeader } from "../../components/standalone/StandaloneHeader";
|
||||
|
||||
interface StandaloneRouteProps {
|
||||
app: App;
|
||||
|
|
@ -10,7 +10,7 @@ interface StandaloneRouteProps {
|
|||
|
||||
export function StandaloneRoute({ app }: StandaloneRouteProps) {
|
||||
const [title, setTitle] = useState(app.name);
|
||||
const [iconUrl, setIconUrl] = useState(AppsManager.getAppIconUrl(app.id));
|
||||
const [iconUrl, setIconUrl] = useState(app.iconUrl ?? "");
|
||||
|
||||
useEffect(() => {
|
||||
// TO DO: don't overwrite metadata in production
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
"include": [
|
||||
"src/**/*",
|
||||
"vite.config.ts",
|
||||
"scripts/**/*",
|
||||
// "scripts/**/*", // TO DO: uncomment this line
|
||||
],
|
||||
"exclude": [
|
||||
"./node_modules",
|
||||
|
|
|
|||
Loading…
Reference in a new issue