diff --git a/docs/README.md b/docs/README.md
index 586b143..a28d906 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -60,7 +60,7 @@ See [docs/configuration](configuration/README.md) for more information.
Contains the static build files after [building](#building--deploying) the application. This directory is not included in the GitHub repository.
-### Coding style
+### Code style
Type | Case | Example
--- | --- | ---
@@ -75,6 +75,7 @@ Global constant variables | MACRO_CASE | ```export const NAME = "Prozilla OS";``
Classes | PascalCase | ```class WindowsManager { }```
React components | PascalCase | ```export function WindowsView({ }) { }```
Functions | camelCase | ```function focusWindow() { }```
+Types | PascalCase | ```type FooBar = boolean;```
### External files
diff --git a/docs/features/README.md b/docs/features/README.md
index 228a887..07de1ec 100644
--- a/docs/features/README.md
+++ b/docs/features/README.md
@@ -10,7 +10,7 @@ To see the status and to-do's of each feature, check the [task board](https://pr
## Table of Contents
-- [Actions](storage/README.md)
+- [Actions](actions/README.md)
- [Apps](apps/README.md)
- [Modals](modals/README.md)
- [Settings](settings/README.md)
diff --git a/docs/features/apps/README.md b/docs/features/apps/README.md
index a70129a..31d8758 100644
--- a/docs/features/apps/README.md
+++ b/docs/features/apps/README.md
@@ -62,7 +62,7 @@ The webview template can be used to turn a webpage into an application by simply
```js
// features/apps/apps.js
-import { WebView } from "../../components/apps/templates/WebView.jsx";
+import { WebView } from "../../components/apps/templates/WebView";
export default class AppsManager {
static APPLICATIONS = [
@@ -91,7 +91,7 @@ export function Example() {
```js
// features/apps/apps.js
-import { Example } from "../../components/apps/example/Example.jsx";
+import { Example } from "../../components/apps/example/Example";
export default class AppsManager {
static APPLICATIONS = [
diff --git a/package-lock.json b/package-lock.json
index 5c608eb..361f234 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -133,7 +133,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/eslint-parser": {
@@ -166,7 +166,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/generator": {
@@ -228,7 +228,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
@@ -258,7 +258,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/helper-create-regexp-features-plugin": {
@@ -282,7 +282,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/helper-define-polyfill-provider": {
@@ -523,7 +523,7 @@
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
"integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
"bin": {
- "parser": "bin/babel-parser.js"
+ "parser": "bin/babel-parser"
},
"engines": {
"node": ">=6.0.0"
@@ -1678,7 +1678,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/plugin-transform-shorthand-properties": {
@@ -1937,7 +1937,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@babel/preset-modules": {
@@ -2414,7 +2414,7 @@
"argparse": "^2.0.1"
},
"bin": {
- "js-yaml": "bin/js-yaml.js"
+ "js-yaml": "bin/js-yaml"
}
},
"node_modules/@eslint/eslintrc/node_modules/type-fest": {
@@ -3300,7 +3300,7 @@
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
"integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/@nodelib/fs.scandir": {
@@ -5806,7 +5806,7 @@
"dependencies": {
"browserslist": "^4.21.5",
"caniuse-lite": "^1.0.30001464",
- "fraction.js": "^4.2.0",
+ "fraction": "^4.2.0",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.0",
"postcss-value-parser": "^4.2.0"
@@ -6147,7 +6147,7 @@
"node": ">= 8.0.0"
}
},
- "node_modules/big.js": {
+ "node_modules/big": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
@@ -6289,7 +6289,7 @@
"update-browserslist-db": "^1.0.11"
},
"bin": {
- "browserslist": "cli.js"
+ "browserslist": "cli"
},
"engines": {
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
@@ -7329,7 +7329,7 @@
}
}
},
- "node_modules/decimal.js": {
+ "node_modules/decimal": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
@@ -7677,7 +7677,7 @@
"jake": "^10.8.5"
},
"bin": {
- "ejs": "bin/cli.js"
+ "ejs": "bin/cli"
},
"engines": {
"node": ">=0.10.0"
@@ -7977,8 +7977,8 @@
"esutils": "^2.0.2"
},
"bin": {
- "escodegen": "bin/escodegen.js",
- "esgenerate": "bin/esgenerate.js"
+ "escodegen": "bin/escodegen",
+ "esgenerate": "bin/esgenerate"
},
"engines": {
"node": ">=6.0"
@@ -8041,7 +8041,7 @@
"text-table": "^0.2.0"
},
"bin": {
- "eslint": "bin/eslint.js"
+ "eslint": "bin/eslint"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -8296,7 +8296,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/eslint-plugin-jsdoc": {
@@ -8368,7 +8368,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/eslint-plugin-react": {
@@ -8445,7 +8445,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/eslint-plugin-testing-library": {
@@ -8687,7 +8687,7 @@
"argparse": "^2.0.1"
},
"bin": {
- "js-yaml": "bin/js-yaml.js"
+ "js-yaml": "bin/js-yaml"
}
},
"node_modules/eslint/node_modules/supports-color": {
@@ -8733,8 +8733,8 @@
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
+ "esparse": "bin/esparse",
+ "esvalidate": "bin/esvalidate"
},
"engines": {
"node": ">=4"
@@ -9379,7 +9379,7 @@
"node": ">= 0.6"
}
},
- "node_modules/fraction.js": {
+ "node_modules/fraction": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
@@ -9557,8 +9557,8 @@
"globby": "^6.1.0"
},
"bin": {
- "gh-pages": "bin/gh-pages.js",
- "gh-pages-clean": "bin/gh-pages-clean.js"
+ "gh-pages": "bin/gh-pages",
+ "gh-pages-clean": "bin/gh-pages-clean"
},
"engines": {
"node": ">=10"
@@ -9904,7 +9904,7 @@
"he": "bin/he"
}
},
- "node_modules/highlight.js": {
+ "node_modules/highlight": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
@@ -9920,7 +9920,7 @@
"node": ">= 6.0.0"
}
},
- "node_modules/hpack.js": {
+ "node_modules/hpack": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
"integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
@@ -10008,7 +10008,7 @@
"terser": "^5.10.0"
},
"bin": {
- "html-minifier-terser": "cli.js"
+ "html-minifier-terser": "cli"
},
"engines": {
"node": ">=12"
@@ -10235,7 +10235,7 @@
"resolve-cwd": "^3.0.0"
},
"bin": {
- "import-local-fixture": "fixtures/cli.js"
+ "import-local-fixture": "fixtures/cli"
},
"engines": {
"node": ">=8"
@@ -10292,7 +10292,7 @@
"node": ">= 0.4"
}
},
- "node_modules/ipaddr.js": {
+ "node_modules/ipaddr": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",
"integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",
@@ -10487,7 +10487,7 @@
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
"bin": {
- "is-docker": "cli.js"
+ "is-docker": "cli"
},
"engines": {
"node": ">=8"
@@ -10834,7 +10834,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/istanbul-lib-report": {
@@ -10925,7 +10925,7 @@
"minimatch": "^3.1.2"
},
"bin": {
- "jake": "bin/cli.js"
+ "jake": "bin/cli"
},
"engines": {
"node": ">=10"
@@ -11005,7 +11005,7 @@
"jest-cli": "^27.5.1"
},
"bin": {
- "jest": "bin/jest.js"
+ "jest": "bin/jest"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
@@ -11144,7 +11144,7 @@
"yargs": "^16.2.0"
},
"bin": {
- "jest": "bin/jest.js"
+ "jest": "bin/jest"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
@@ -12877,7 +12877,7 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
"bin": {
- "jiti": "bin/jiti.js"
+ "jiti": "bin/jiti"
}
},
"node_modules/js-tokens": {
@@ -12894,7 +12894,7 @@
"esprima": "^4.0.0"
},
"bin": {
- "js-yaml": "bin/js-yaml.js"
+ "js-yaml": "bin/js-yaml"
}
},
"node_modules/jsdoc-type-pratt-parser": {
@@ -12917,7 +12917,7 @@
"cssom": "^0.4.4",
"cssstyle": "^2.3.0",
"data-urls": "^2.0.0",
- "decimal.js": "^10.2.1",
+ "decimal": "^10.2.1",
"domexception": "^2.0.1",
"escodegen": "^2.0.0",
"form-data": "^3.0.0",
@@ -12987,7 +12987,7 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"bin": {
- "json5": "lib/cli.js"
+ "json5": "lib/cli"
},
"engines": {
"node": ">=6"
@@ -13118,7 +13118,7 @@
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dependencies": {
- "big.js": "^5.2.2",
+ "big": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
},
@@ -13178,7 +13178,7 @@
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
- "loose-envify": "cli.js"
+ "loose-envify": "cli"
}
},
"node_modules/lower-case": {
@@ -13195,7 +13195,7 @@
"integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==",
"dependencies": {
"fault": "^1.0.0",
- "highlight.js": "~10.7.0"
+ "highlight": "~10.7.0"
},
"funding": {
"type": "github",
@@ -13215,7 +13215,7 @@
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"bin": {
- "lz-string": "bin/bin.js"
+ "lz-string": "bin/bin"
}
},
"node_modules/magic-string": {
@@ -13245,7 +13245,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
}
},
"node_modules/makeerror": {
@@ -13334,7 +13334,7 @@
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"bin": {
- "mime": "cli.js"
+ "mime": "cli"
},
"engines": {
"node": ">=4"
@@ -13474,7 +13474,7 @@
"minimist": "^1.2.6"
},
"bin": {
- "mkdirp": "bin/cmd.js"
+ "mkdirp": "bin/cmd"
}
},
"node_modules/ms": {
@@ -13491,7 +13491,7 @@
"thunky": "^1.0.2"
},
"bin": {
- "multicast-dns": "cli.js"
+ "multicast-dns": "cli"
}
},
"node_modules/mz": {
@@ -15502,13 +15502,13 @@
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"dependencies": {
"forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
+ "ipaddr": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
- "node_modules/proxy-addr/node_modules/ipaddr.js": {
+ "node_modules/proxy-addr/node_modules/ipaddr": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
@@ -15890,7 +15890,7 @@
"workbox-webpack-plugin": "^6.4.1"
},
"bin": {
- "react-scripts": "bin/react-scripts.js"
+ "react-scripts": "bin/react-scripts"
},
"engines": {
"node": ">=14.0.0"
@@ -15937,7 +15937,7 @@
"integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==",
"dependencies": {
"@babel/runtime": "^7.3.1",
- "highlight.js": "^10.4.1",
+ "highlight": "^10.4.1",
"lowlight": "^1.17.0",
"prismjs": "^1.27.0",
"refractor": "^3.6.0"
@@ -16314,7 +16314,7 @@
"glob": "^7.1.3"
},
"bin": {
- "rimraf": "bin.js"
+ "rimraf": "bin"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -16575,7 +16575,7 @@
"lru-cache": "^6.0.0"
},
"bin": {
- "semver": "bin/semver.js"
+ "semver": "bin/semver"
},
"engines": {
"node": ">=10"
@@ -16954,7 +16954,7 @@
"dependencies": {
"debug": "^4.1.0",
"detect-node": "^2.0.4",
- "hpack.js": "^2.1.6",
+ "hpack": "^2.1.6",
"obuf": "^1.1.2",
"readable-stream": "^3.0.6",
"wbuf": "^1.7.3"
@@ -17460,8 +17460,8 @@
"sucrase": "^3.32.0"
},
"bin": {
- "tailwind": "lib/cli.js",
- "tailwindcss": "lib/cli.js"
+ "tailwind": "lib/cli",
+ "tailwindcss": "lib/cli"
},
"engines": {
"node": ">=14.0.0"
@@ -17746,7 +17746,7 @@
"minimist": "^1.2.0"
},
"bin": {
- "json5": "lib/cli.js"
+ "json5": "lib/cli"
}
},
"node_modules/tsconfig-paths/node_modules/strip-bom": {
@@ -18031,7 +18031,7 @@
"picocolors": "^1.0.0"
},
"bin": {
- "update-browserslist-db": "cli.js"
+ "update-browserslist-db": "cli"
},
"peerDependencies": {
"browserslist": ">= 4.21.0"
@@ -18207,7 +18207,7 @@
"webpack-sources": "^3.2.3"
},
"bin": {
- "webpack": "bin/webpack.js"
+ "webpack": "bin/webpack"
},
"engines": {
"node": ">=10.13.0"
@@ -18316,7 +18316,7 @@
"graceful-fs": "^4.2.6",
"html-entities": "^2.3.2",
"http-proxy-middleware": "^2.0.3",
- "ipaddr.js": "^2.0.1",
+ "ipaddr": "^2.0.1",
"launch-editor": "^2.6.0",
"open": "^8.0.9",
"p-retry": "^4.5.0",
@@ -18330,7 +18330,7 @@
"ws": "^8.13.0"
},
"bin": {
- "webpack-dev-server": "bin/webpack-dev-server.js"
+ "webpack-dev-server": "bin/webpack-dev-server"
},
"engines": {
"node": ">= 12.13.0"
diff --git a/package.json b/package.json
index d079e0c..0224073 100644
--- a/package.json
+++ b/package.json
@@ -95,8 +95,6 @@
],
"jsdoc/check-values": "warn",
"jsdoc/empty-tags": "warn",
- "jsdoc/check-param-names": "warn",
- "jsdoc/check-property-names": "warn",
"jsdoc/check-access": "warn",
"jsdoc/check-alignment": "warn",
"jsdoc/multiline-blocks": "warn",
diff --git a/src/App.tsx b/src/App.tsx
index 70ee040..c1c98ad 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,14 +1,14 @@
import styles from "./App.module.css";
-import { Taskbar } from "./components/taskbar/Taskbar.jsx";
+import { Taskbar } from "./components/taskbar/Taskbar";
import { WindowsManagerProvider } from "./hooks/windows/windowsManagerContext";
-import { WindowsView } from "./components/windows/WindowsView.jsx";
+import { WindowsView } from "./components/windows/WindowsView";
import { VirtualRootProvider } from "./hooks/virtual-drive/virtualRootContext";
-import { Desktop } from "./components/desktop/Desktop.jsx";
+import { Desktop } from "./components/desktop/Desktop";
import { SettingsManagerProvider } from "./hooks/settings/settingsManagerContext";
-import { ModalsView } from "./components/modals/ModalsView.jsx";
-import React, { FC, useEffect } from "react";
+import { ModalsView } from "./components/modals/ModalsView";
+import { FC, useEffect } from "react";
import { ZIndexManagerProvider } from "./hooks/z-index/zIndexManagerContext";
-import { TrackingManager } from "./features/tracking/trackingManager.js";
+import { TrackingManager } from "./features/tracking/trackingManager";
import { ModalsManagerProvider } from "./hooks/modals/modalsManagerContext";
TrackingManager.initialize();
diff --git a/src/components/_utils/button/Button.jsx b/src/components/_utils/button/Button.tsx
similarity index 78%
rename from src/components/_utils/button/Button.jsx
rename to src/components/_utils/button/Button.tsx
index 3270d28..789c044 100644
--- a/src/components/_utils/button/Button.jsx
+++ b/src/components/_utils/button/Button.tsx
@@ -1,13 +1,16 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import styles from "./Button.module.css";
import { faExternalLink } from "@fortawesome/free-solid-svg-icons";
+import { ReactNode } from "react";
-/**
- * @param {object} props
- * @param {string} props.className
- * @param {string} props.href
- */
-export function Button(props) {
+interface ButtonProps {
+ className?: string;
+ href?: string;
+ children?: ReactNode;
+ [key: string]: any;
+}
+
+export function Button(props: ButtonProps) {
let { className = "" } = props;
const { href, children } = props;
diff --git a/src/components/_utils/dropdown-button/DropdownButton.jsx b/src/components/_utils/dropdown-button/DropdownButton.tsx
similarity index 92%
rename from src/components/_utils/dropdown-button/DropdownButton.jsx
rename to src/components/_utils/dropdown-button/DropdownButton.tsx
index 139ea01..521d02e 100644
--- a/src/components/_utils/dropdown-button/DropdownButton.jsx
+++ b/src/components/_utils/dropdown-button/DropdownButton.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import styles from "./DropdownButton.module.css";
-import OutsideClickListener from "../../../hooks/_utils/outsideClick.js";
-import { formatShortcut } from "../../../features/_utils/string.utils.js";
+import OutsideClickListener from "../../../hooks/_utils/outsideClick";
+import { formatShortcut } from "../../../features/_utils/string.utils";
/**
* @param {object} props
@@ -25,7 +25,7 @@ export function DropdownButton({ label, options, shortcuts }) {
{open && options
? (
- {Object.entries(options).map(([label, callback]) =>
+ {Object.entries(options).map(([label, callback]: [label: string, callback: Function]) =>
;
}
\ No newline at end of file
diff --git a/src/components/actions/actions/RadioAction.jsx b/src/components/actions/actions/RadioAction.tsx
similarity index 79%
rename from src/components/actions/actions/RadioAction.jsx
rename to src/components/actions/actions/RadioAction.tsx
index 472b7fb..5e75f59 100644
--- a/src/components/actions/actions/RadioAction.jsx
+++ b/src/components/actions/actions/RadioAction.tsx
@@ -1,9 +1,10 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { formatShortcut } from "../../../features/_utils/string.utils.js";
+import { formatShortcut } from "../../../features/_utils/string.utils";
import styles from "../Actions.module.css";
import { faCircleDot } from "@fortawesome/free-solid-svg-icons";
-import { useState } from "react";
+import { ReactNode, useState } from "react";
import { faCircle } from "@fortawesome/free-regular-svg-icons";
+import { ActionProps } from "../Actions";
/**
* @param {object} props
@@ -15,14 +16,23 @@ import { faCircle } from "@fortawesome/free-regular-svg-icons";
* @param {number} props.initialIndex
* @param {Function} props.onTrigger
*/
-export function RadioAction({ actionId, options, initialIndex, onTrigger }) {
+
+interface RadioActionProps extends ActionProps {
+ options: {
+ label: string;
+ shortcut?: string[]
+ }[];
+ initialIndex: number;
+}
+
+export function RadioAction({ actionId, options, initialIndex, onTrigger }: RadioActionProps): ReactNode {
const [activeIndex, setActiveIndex] = useState(initialIndex ?? 0);
return (
{options.map(({ label, shortcut }, index) =>
{
setActiveIndex(index);
- onTrigger(event, index);
+ onTrigger(event as unknown as Event, index);
}}>
diff --git a/src/components/actions/actions/ToggleAction.jsx b/src/components/actions/actions/ToggleAction.tsx
similarity index 73%
rename from src/components/actions/actions/ToggleAction.jsx
rename to src/components/actions/actions/ToggleAction.tsx
index 3a27d6e..b1ce191 100644
--- a/src/components/actions/actions/ToggleAction.jsx
+++ b/src/components/actions/actions/ToggleAction.tsx
@@ -1,23 +1,20 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { formatShortcut } from "../../../features/_utils/string.utils.js";
+import { formatShortcut } from "../../../features/_utils/string.utils";
import styles from "../Actions.module.css";
-import { useState } from "react";
+import { ReactNode, useState } from "react";
import { faSquare } from "@fortawesome/free-regular-svg-icons";
import { faSquareCheck } from "@fortawesome/free-solid-svg-icons";
+import { ActionProps } from "../Actions";
-/**
- * @param {object} props
- * @param {string} props.actionId
- * @param {string} props.label
- * @param {string[]} props.shortcut
- * @param {Function} props.onTrigger
- * @param {boolean} props.initialValue
- */
-export function ToggleAction({ actionId, label, shortcut, initialValue, onTrigger }) {
+interface ToggleActionProps extends ActionProps {
+ initialValue: boolean;
+}
+
+export function ToggleAction({ actionId, label, shortcut, initialValue, onTrigger }: ToggleActionProps): ReactNode {
const [active, setActive] = useState(initialValue ?? false);
return (
{
- onTrigger(event, !active);
+ onTrigger(event as unknown as Event, !active);
setActive(!active);
}}>
diff --git a/src/components/apps/_utils/header-menu/HeaderMenu.jsx b/src/components/apps/_utils/header-menu/HeaderMenu.tsx
similarity index 50%
rename from src/components/apps/_utils/header-menu/HeaderMenu.jsx
rename to src/components/apps/_utils/header-menu/HeaderMenu.tsx
index e62e47f..2a873bc 100644
--- a/src/components/apps/_utils/header-menu/HeaderMenu.jsx
+++ b/src/components/apps/_utils/header-menu/HeaderMenu.tsx
@@ -1,13 +1,13 @@
-import { useShortcuts } from "../../../../hooks/_utils/keyboard.js";
-import { DropdownButton } from "../../../_utils/dropdown-button/DropdownButton.jsx";
+import { useShortcuts } from "../../../../hooks/_utils/keyboard";
+import { DropdownButton } from "../../../_utils/dropdown-button/DropdownButton";
import styles from "./HeaderMenu.module.css";
-/**
- * @param {object} props
- * @param {Object>} props.options
- * @param {Object>} props.shortcuts
- */
-export function HeaderMenu({ options, shortcuts }) {
+interface HeaderMenuProps {
+ options: Record> | Record;
+ shortcuts: Record> | Record;
+}
+
+export function HeaderMenu({ options, shortcuts }: HeaderMenuProps) {
useShortcuts({ options, shortcuts });
return (
diff --git a/src/components/apps/_utils/web-view/WebView.jsx b/src/components/apps/_utils/web-view/WebView.jsx
deleted file mode 100644
index 2cc5e60..0000000
--- a/src/components/apps/_utils/web-view/WebView.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { forwardRef, useEffect, useState } from "react";
-import styles from "./WebView.module.css";
-
-/**
- * @param {object} props
- * @param {string} props.source
- */
-export const WebView = forwardRef(({ source, focus, ...props }, ref) => {
- const [hovered, setHovered] = useState(false);
-
- useEffect(() => {
- window.focus();
-
- const onBlur = (event) => {
- if (hovered) {
- focus?.(event);
- }
- };
-
- window.addEventListener("blur", onBlur);
-
- return () => {
- window.removeEventListener("blur", onBlur);
- };
- }, [focus, hovered]);
-
- const onMouseOver = () => {
- setHovered(true);
- };
-
- const onMouseOut = () => {
- window.focus();
- setHovered(false);
- };
-
- return (
-
-
-
-
- );
-});
\ No newline at end of file
diff --git a/src/components/apps/_utils/web-view/WebView.tsx b/src/components/apps/_utils/web-view/WebView.tsx
new file mode 100644
index 0000000..cea90a3
--- /dev/null
+++ b/src/components/apps/_utils/web-view/WebView.tsx
@@ -0,0 +1,48 @@
+import { FC, forwardRef, useEffect, useState } from "react";
+import styles from "./WebView.module.css";
+import { WindowProps } from "../../../windows/WindowView";
+
+interface WebViewProps extends WindowProps {
+ source: string;
+}
+
+export const WebView: FC = forwardRef(({ source, focus, ...props }: WebViewProps, ref) => {
+ const [hovered, setHovered] = useState(false);
+
+ useEffect(() => {
+ window.focus();
+
+ const onBlur = (event) => {
+ if (hovered) {
+ focus?.(event);
+ }
+ };
+
+ window.addEventListener("blur", onBlur);
+
+ return () => {
+ window.removeEventListener("blur", onBlur);
+ };
+ }, [focus, hovered]);
+
+ const onMouseOver = () => {
+ setHovered(true);
+ };
+
+ const onMouseOut = () => {
+ window.focus();
+ setHovered(false);
+ };
+
+ return
+
+
;
+}) as FC;
\ No newline at end of file
diff --git a/src/components/apps/browser/Browser.jsx b/src/components/apps/browser/Browser.tsx
similarity index 94%
rename from src/components/apps/browser/Browser.jsx
rename to src/components/apps/browser/Browser.tsx
index 06f8d49..89dc1b2 100644
--- a/src/components/apps/browser/Browser.jsx
+++ b/src/components/apps/browser/Browser.tsx
@@ -1,11 +1,11 @@
import { useEffect, useRef, useState } from "react";
import styles from "./Browser.module.css";
-import { WebView } from "../_utils/web-view/WebView.jsx";
+import { WebView } from "../_utils/web-view/WebView";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCaretLeft, faCaretRight, faHome, faRotateRight } from "@fortawesome/free-solid-svg-icons";
-import { HOME_URL, SEARCH_URL } from "../../../config/apps/browser.config.js";
-import { isValidUrl } from "../../../features/_utils/browser.utils.js";
-import { useHistory } from "../../../hooks/_utils/history.js";
+import { HOME_URL, SEARCH_URL } from "../../../config/apps/browser.config";
+import { isValidUrl } from "../../../features/_utils/browser.utils";
+import { useHistory } from "../../../hooks/_utils/history";
/** @type {import("../../windows/WindowView.jsx").windowProps} */
export function Browser({ startUrl, focus }) {
diff --git a/src/components/apps/calculator/Calculator.jsx b/src/components/apps/calculator/Calculator.tsx
similarity index 98%
rename from src/components/apps/calculator/Calculator.jsx
rename to src/components/apps/calculator/Calculator.tsx
index 1e3b455..746581c 100644
--- a/src/components/apps/calculator/Calculator.jsx
+++ b/src/components/apps/calculator/Calculator.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
-import { Button } from "../../_utils/button/Button.jsx";
+import { Button } from "../../_utils/button/Button";
import styles from "./Calculator.module.css";
/** @type {import("../../windows/WindowView.jsx").windowProps} */
diff --git a/src/components/apps/file-explorer/FileExplorer.jsx b/src/components/apps/file-explorer/FileExplorer.tsx
similarity index 80%
rename from src/components/apps/file-explorer/FileExplorer.jsx
rename to src/components/apps/file-explorer/FileExplorer.tsx
index a422780..3a430bc 100644
--- a/src/components/apps/file-explorer/FileExplorer.jsx
+++ b/src/components/apps/file-explorer/FileExplorer.tsx
@@ -1,41 +1,45 @@
-import { useCallback, useEffect, useState } from "react";
+import { FC, useCallback, useEffect, useState } from "react";
import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext";
import styles from "./FileExplorer.module.css";
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 { useWindowsManager } from "../../../hooks/windows/windowsManagerContext";
-import { useContextMenu } from "../../../hooks/modals/contextMenu.js";
-import { QuickAccessButton } from "./QuickAccessButton.jsx";
-import { useWindowedModal } from "../../../hooks/modals/windowedModal.js";
-import Vector2 from "../../../features/math/vector2.js";
-import { DIALOG_CONTENT_TYPES } from "../../../config/modals.config.js";
-import { DirectoryList } from "./directory-list/DirectoryList.jsx";
-import { Actions } from "../../actions/Actions.jsx";
-import { ClickAction } from "../../actions/actions/ClickAction.jsx";
+import { useContextMenu } from "../../../hooks/modals/contextMenu";
+import { QuickAccessButton } from "./QuickAccessButton";
+import { useWindowedModal } from "../../../hooks/modals/windowedModal";
+import Vector2 from "../../../features/math/vector2";
+import { DIALOG_CONTENT_TYPES } from "../../../config/modals.config";
+import { DirectoryList, OnSelectionChangeParams } from "./directory-list/DirectoryList";
+import { Actions } from "../../actions/Actions";
+import { ClickAction } from "../../actions/actions/ClickAction";
import utilStyles from "../../../styles/utils.module.css";
-import { DialogBox } from "../../modals/dialog-box/DialogBox.jsx";
-import AppsManager from "../../../features/apps/appsManager.js";
-import { APPS, APP_ICONS, APP_NAMES } from "../../../config/apps.config.js";
-import { TITLE_SEPARATOR } from "../../../config/windows.config.js";
-import { FileProperties } from "../../modals/file-properties/FileProperties.jsx";
-import { useHistory } from "../../../hooks/_utils/history.js";
-import { Divider } from "../../actions/actions/Divider.jsx";
-import { CODE_FORMATS } from "../../../config/apps/textEditor.config.js";
-import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config.js";
+import { DialogBox } from "../../modals/dialog-box/DialogBox";
+import AppsManager from "../../../features/apps/appsManager";
+import { APPS, APP_ICONS, APP_NAMES } from "../../../config/apps.config";
+import { TITLE_SEPARATOR } from "../../../config/windows.config";
+import { FileProperties } from "../../modals/file-properties/FileProperties";
+import { useHistory } from "../../../hooks/_utils/history";
+import { Divider } from "../../actions/actions/Divider";
+import { CODE_FORMATS } from "../../../config/apps/textEditor.config";
+import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config";
+import { WindowProps } from "../../windows/WindowView";
+import { VirtualFolder } from "../../../features/virtual-drive/folder/virtualFolder";
+import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile";
+import { VirtualFolderLink } from "../../../features/virtual-drive/folder/virtualFolderLink";
-/**
- * @param {import("../../windows/WindowView.jsx").windowProps} props
- * @param {string} props.startPath
- * @param {*} props.Footer
- * @param {number} props.selectorMode
- * @param {import("./directory-list/DirectoryList.jsx").onSelectionChange} props.onSelectionChange
- * @param {Function} props.onSelectionFinish
- */
-export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChange, onSelectionFinish }) {
+interface FileExplorerProps extends WindowProps {
+ startPath?: string;
+ selectorMode?: number;
+ Footer: FC;
+ onSelectionChange: (params: OnSelectionChangeParams) => void;
+ onSelectionFinish: Function;
+}
+
+export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChange, onSelectionFinish }: FileExplorerProps) {
const isSelector = (Footer != null && selectorMode != null && selectorMode !== SELECTOR_MODE.NONE);
const virtualRoot = useVirtualRoot();
- const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~"));
+ const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~") as VirtualFolder);
const [path, setPath] = useState(currentDirectory?.path ?? "");
const windowsManager = useWindowsManager();
const [showHidden] = useState(true);
@@ -44,7 +48,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
const { openWindowedModal } = useWindowedModal();
const { onContextMenu: onContextMenuFile } = useContextMenu({ Actions: (props) =>
- {
+ {
if (isSelector) {
onSelectionChange?.({ files: [file.id], directory: currentDirectory });
onSelectionFinish?.();
@@ -97,7 +101,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
const directory = absolute ? virtualRoot.navigate(path) : currentDirectory.navigate(path);
if (directory != null) {
- setCurrentDirectory(directory);
+ setCurrentDirectory(directory as VirtualFolder);
setPath(directory.root ? "/" : directory.path);
pushState(directory.path);
}
@@ -110,7 +114,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
const path = history[stateIndex];
const directory = virtualRoot.navigate(path);
if (directory != null) {
- setCurrentDirectory(directory);
+ setCurrentDirectory(directory as VirtualFolder);
setPath(directory.root ? "/" : directory.path);
}
}, [history, stateIndex, virtualRoot]);
@@ -142,7 +146,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
return;
}
- setCurrentDirectory(directory);
+ setCurrentDirectory(directory as VirtualFolder);
setPath(directory.root ? "/" : directory.path);
}
};
@@ -175,7 +179,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
tabIndex={0}
className={styles["Icon-button"]}
onClick={() => { changeDirectory(".."); }}
- disabled={currentDirectory.root}
+ disabled={currentDirectory.isRoot}
>
@@ -235,16 +239,16 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
className={styles.Main}
showHidden={showHidden}
onOpenFile={(event, file) => {
- event.preventDefault();
+ (event as Event).preventDefault();
if (isSelector)
return onSelectionFinish?.();
- const options = {};
+ const options: Record
= {};
if (file.extension === "md" || CODE_FORMATS.includes(file.extension))
options.mode = "view";
windowsManager.openFile(file, options);
}}
onOpenFolder={(event, folder) => {
- changeDirectory(folder.linkedPath ?? folder.name);
+ changeDirectory((folder as VirtualFolderLink).linkedPath ?? folder.name);
}}
onContextMenuFile={onContextMenuFile}
onContextMenuFolder={onContextMenuFolder}
diff --git a/src/components/apps/file-explorer/QuickAccessButton.jsx b/src/components/apps/file-explorer/QuickAccessButton.tsx
similarity index 100%
rename from src/components/apps/file-explorer/QuickAccessButton.jsx
rename to src/components/apps/file-explorer/QuickAccessButton.tsx
diff --git a/src/components/apps/file-explorer/directory-list/DirectoryList.jsx b/src/components/apps/file-explorer/directory-list/DirectoryList.tsx
similarity index 82%
rename from src/components/apps/file-explorer/directory-list/DirectoryList.jsx
rename to src/components/apps/file-explorer/directory-list/DirectoryList.tsx
index 7e1bf8e..586694f 100644
--- a/src/components/apps/file-explorer/directory-list/DirectoryList.jsx
+++ b/src/components/apps/file-explorer/directory-list/DirectoryList.tsx
@@ -1,45 +1,36 @@
-import { useEffect, useRef, useState } from "react";
-import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile.js";
-import { VirtualFolder } from "../../../../features/virtual-drive/folder/virtualFolder.js";
-import { Interactable } from "../../../_utils/interactable/Interactable.jsx";
+import { ReactNode, useEffect, useRef, useState } from "react";
+import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile";
+import { VirtualFolder } from "../../../../features/virtual-drive/folder/virtualFolder";
+import { Interactable } from "../../../_utils/interactable/Interactable";
import styles from "./DirectoryList.module.css";
-import { ImagePreview } from "./ImagePreview.jsx";
+import { ImagePreview } from "./ImagePreview";
-/**
- * @callback fileEvent
- * @param {object} event
- * @param {VirtualFile} file
- */
+export interface OnSelectionChangeParams {
+ files?: string[];
+ folders?: string[];
+ directory?: VirtualFolder;
+};
-/**
- * @callback folderEvent
- * @param {object} event
- * @param {VirtualFolder} folder
- */
+type FileEventHandler = (event: object, file: VirtualFile) => void;
+type FolderEventHandler = (event: object, folder: VirtualFolder) => void;
-/**
- * @callback onSelectionChange
- * @param {object} selection
- * @param {string[]} selection.files
- * @param {string[]} selection.folders
- */
+interface DirectoryListProps {
+ directory: VirtualFolder;
+ showHidden?: boolean;
+ folderClassName?: string;
+ fileClassName?: string;
+ className?: string;
+ onContextMenuFile?: FileEventHandler;
+ onContextMenuFolder?: FolderEventHandler;
+ onOpenFile?: FileEventHandler;
+ onOpenFolder?: FolderEventHandler;
+ allowMultiSelect?: boolean;
+ onSelectionChange?: (params: OnSelectionChangeParams) => void;
+ [key: string]: any;
+}
-/**
- * @param {object} props
- * @param {VirtualFolder} props.directory
- * @param {boolean} props.showHidden
- * @param {string} props.folderClassName
- * @param {string} props.fileClassName
- * @param {string} props.className
- * @param {fileEvent} props.onContextMenuFile
- * @param {folderEvent} props.onContextMenuFolder
- * @param {fileEvent} props.onOpenFile
- * @param {folderEvent} props.onOpenFolder
- * @param {boolean} props.allowMultiSelect
- * @param {onSelectionChange} props.onSelectionChange
- */
export function DirectoryList({ directory, showHidden = false, folderClassName, fileClassName, className,
- onContextMenuFile, onContextMenuFolder, onOpenFile, onOpenFolder, allowMultiSelect = true, onSelectionChange, ...props }) {
+ onContextMenuFile, onContextMenuFolder, onOpenFile, onOpenFolder, allowMultiSelect = true, onSelectionChange, ...props }: DirectoryListProps): ReactNode {
const [selectedFolders, setSelectedFolders] = useState([]);
const [selectedFiles, setSelectedFiles] = useState([]);
diff --git a/src/components/apps/file-explorer/directory-list/ImagePreview.jsx b/src/components/apps/file-explorer/directory-list/ImagePreview.tsx
similarity index 76%
rename from src/components/apps/file-explorer/directory-list/ImagePreview.jsx
rename to src/components/apps/file-explorer/directory-list/ImagePreview.tsx
index 42df32a..488f0a0 100644
--- a/src/components/apps/file-explorer/directory-list/ImagePreview.jsx
+++ b/src/components/apps/file-explorer/directory-list/ImagePreview.tsx
@@ -1,10 +1,16 @@
import { useState } from "react";
import styles from "./ImagePreview.module.css";
import { ReactSVG } from "react-svg";
-import AppsManager from "../../../../features/apps/appsManager.js";
-import { APPS } from "../../../../config/apps.config.js";
+import AppsManager from "../../../../features/apps/appsManager";
+import { APPS } from "../../../../config/apps.config";
-export function ImagePreview({ source, className, onError, ...props }) {
+interface ImagePreviewProps {
+ source: string;
+ className?: string;
+ onError?: Function;
+}
+
+export function ImagePreview({ source, className, onError, ...props }: ImagePreviewProps) {
const [loadingFailed, setLoadingFailed] = useState(false);
const onLoadingError = () => {
diff --git a/src/components/apps/media-viewer/MediaViewer.jsx b/src/components/apps/media-viewer/MediaViewer.tsx
similarity index 93%
rename from src/components/apps/media-viewer/MediaViewer.jsx
rename to src/components/apps/media-viewer/MediaViewer.tsx
index 7f9fcd3..b27e062 100644
--- a/src/components/apps/media-viewer/MediaViewer.jsx
+++ b/src/components/apps/media-viewer/MediaViewer.tsx
@@ -2,8 +2,8 @@
import { useEffect } from "react";
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext";
import styles from "./MediaViewer.module.css";
-import { APPS } from "../../../config/apps.config.js";
-import { IMAGE_FORMATS } from "../../../config/apps/mediaViewer.config.js";
+import { APPS } from "../../../config/apps.config";
+import { IMAGE_FORMATS } from "../../../config/apps/mediaViewer.config";
/**
* @param {import("../../windows/WindowView.jsx").windowProps} props
diff --git a/src/components/apps/settings/Settings.jsx b/src/components/apps/settings/Settings.tsx
similarity index 82%
rename from src/components/apps/settings/Settings.jsx
rename to src/components/apps/settings/Settings.tsx
index c361b06..183eff8 100644
--- a/src/components/apps/settings/Settings.jsx
+++ b/src/components/apps/settings/Settings.tsx
@@ -3,10 +3,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleInfo, faHardDrive, faPalette, faShapes } from "@fortawesome/free-solid-svg-icons";
import utilStyles from "../../../styles/utils.module.css";
import { Tab, TabList, TabPanel, Tabs } from "react-tabs";
-import { AppearanceSettings } from "./tabs/AppearanceSettings.jsx";
-import { AboutSettings } from "./tabs/AboutSettings.jsx";
-import { StorageTab } from "./tabs/StorageSettings.jsx";
-import { AppsSettings } from "./tabs/AppsSettings.jsx";
+import { AppearanceSettings } from "./tabs/AppearanceSettings";
+import { AboutSettings } from "./tabs/AboutSettings";
+import { StorageTab } from "./tabs/StorageSettings";
+import { AppsSettings } from "./tabs/AppsSettings";
/**
* @param {import("../../windows/WindowView.jsx").windowProps} props
@@ -38,10 +38,10 @@ export function Settings({ tab, modalsManager }) {
-
+
-
+
diff --git a/src/components/apps/settings/tabs/AboutSettings.jsx b/src/components/apps/settings/tabs/AboutSettings.tsx
similarity index 87%
rename from src/components/apps/settings/tabs/AboutSettings.jsx
rename to src/components/apps/settings/tabs/AboutSettings.tsx
index 9ff19e5..d3e223e 100644
--- a/src/components/apps/settings/tabs/AboutSettings.jsx
+++ b/src/components/apps/settings/tabs/AboutSettings.tsx
@@ -1,10 +1,10 @@
-import { Button } from "../../../_utils/button/Button.jsx";
+import { Button } from "../../../_utils/button/Button";
import styles from "../Settings.module.css";
import utilStyles from "../../../../styles/utils.module.css";
-import Vector2 from "../../../../features/math/vector2.js";
+import Vector2 from "../../../../features/math/vector2";
import { useWindowsManager } from "../../../../hooks/windows/windowsManagerContext";
import { useVirtualRoot } from "../../../../hooks/virtual-drive/virtualRootContext";
-import { NAME } from "../../../../config/branding.config.js";
+import { NAME } from "../../../../config/branding.config";
export function AboutSettings() {
const windowsManager = useWindowsManager();
diff --git a/src/components/apps/settings/tabs/AppOption.jsx b/src/components/apps/settings/tabs/AppOption.tsx
similarity index 93%
rename from src/components/apps/settings/tabs/AppOption.jsx
rename to src/components/apps/settings/tabs/AppOption.tsx
index 765f2e5..c518aa2 100644
--- a/src/components/apps/settings/tabs/AppOption.jsx
+++ b/src/components/apps/settings/tabs/AppOption.tsx
@@ -1,15 +1,15 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import AppsManager from "../../../../features/apps/appsManager.js";
-import { ImagePreview } from "../../file-explorer/directory-list/ImagePreview.jsx";
+import AppsManager from "../../../../features/apps/appsManager";
+import { ImagePreview } from "../../file-explorer/directory-list/ImagePreview";
import styles from "../Settings.module.css";
import { faEllipsisVertical, faThumbTack } from "@fortawesome/free-solid-svg-icons";
import { useWindowsManager } from "../../../../hooks/windows/windowsManagerContext";
-import { useContextMenu } from "../../../../hooks/modals/contextMenu.js";
-import { Actions } from "../../../actions/Actions.jsx";
-import { ClickAction } from "../../../actions/actions/ClickAction.jsx";
-import { removeFromArray } from "../../../../features/_utils/array.utils.js";
+import { useContextMenu } from "../../../../hooks/modals/contextMenu";
+import { Actions } from "../../../actions/Actions";
+import { ClickAction } from "../../../actions/actions/ClickAction";
+import { removeFromArray } from "../../../../features/_utils/array.utils";
import { useSettingsManager } from "../../../../hooks/settings/settingsManagerContext";
-import { SettingsManager } from "../../../../features/settings/settingsManager.js";
+import { SettingsManager } from "../../../../features/settings/settingsManager";
export function AppOption({ app, pins, setPins }) {
const isPinned = pins.includes(app.id);
diff --git a/src/components/apps/settings/tabs/AppearanceSettings.jsx b/src/components/apps/settings/tabs/AppearanceSettings.tsx
similarity index 78%
rename from src/components/apps/settings/tabs/AppearanceSettings.jsx
rename to src/components/apps/settings/tabs/AppearanceSettings.tsx
index 3f80416..cfea298 100644
--- a/src/components/apps/settings/tabs/AppearanceSettings.jsx
+++ b/src/components/apps/settings/tabs/AppearanceSettings.tsx
@@ -1,23 +1,20 @@
import { useEffect, useState } from "react";
-import { SettingsManager } from "../../../../features/settings/settingsManager.js";
+import { SettingsManager } from "../../../../features/settings/settingsManager";
import styles from "../Settings.module.css";
import utilStyles from "../../../../styles/utils.module.css";
import { useVirtualRoot } from "../../../../hooks/virtual-drive/virtualRootContext";
import { useSettingsManager } from "../../../../hooks/settings/settingsManagerContext";
-import { WALLPAPERS_PATH } from "../../../../config/apps/settings.config.js";
-import { useWindowedModal } from "../../../../hooks/modals/windowedModal.js";
-import ModalsManager from "../../../../features/modals/modalsManager.js";
-import { Button } from "../../../_utils/button/Button.jsx";
-import { FileSelector } from "../../../modals/file-selector/FileSelector.jsx";
-import { SELECTOR_MODE } from "../../../../config/apps/fileExplorer.config.js";
-import { DEFAULT_FILE_SELECTOR_SIZE } from "../../../../config/modals.config.js";
-import { IMAGE_FORMATS } from "../../../../config/apps/mediaViewer.config.js";
+import { WALLPAPERS_PATH } from "../../../../config/apps/settings.config";
+import { useWindowedModal } from "../../../../hooks/modals/windowedModal";
+import { Button } from "../../../_utils/button/Button";
+import { FileSelector } from "../../../modals/file-selector/FileSelector";
+import { SELECTOR_MODE } from "../../../../config/apps/fileExplorer.config";
+import { DEFAULT_FILE_SELECTOR_SIZE } from "../../../../config/modals.config";
+import { IMAGE_FORMATS } from "../../../../config/apps/mediaViewer.config";
+import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile";
+import { VirtualFolder } from "../../../../features/virtual-drive/folder/virtualFolder";
-/**
- * @param {object} props
- * @param {ModalsManager} props.modalsManager
- */
-export function AppearanceSettings({ modalsManager }) {
+export function AppearanceSettings() {
const virtualRoot = useVirtualRoot();
const settingsManager = useSettingsManager();
const [wallpaper, setWallpaper] = useState(null);
@@ -44,7 +41,7 @@ export function AppearanceSettings({ modalsManager }) {
Modal: (props) => {
+ onFinish={(file: VirtualFile) => {
settings.set("wallpaper", file.source);
}}
{...props}
@@ -55,13 +52,13 @@ export function AppearanceSettings({ modalsManager }) {
Browse
;
}
\ No newline at end of file
diff --git a/src/components/apps/settings/tabs/StorageSettings.jsx b/src/components/apps/settings/tabs/StorageSettings.tsx
similarity index 90%
rename from src/components/apps/settings/tabs/StorageSettings.jsx
rename to src/components/apps/settings/tabs/StorageSettings.tsx
index 23f248a..4202a3c 100644
--- a/src/components/apps/settings/tabs/StorageSettings.jsx
+++ b/src/components/apps/settings/tabs/StorageSettings.tsx
@@ -1,10 +1,10 @@
import styles from "../Settings.module.css";
import utilStyles from "../../../../styles/utils.module.css";
-import { round } from "../../../../features/math/round.js";
-import { ProgressBar } from "../../../_utils/progress-bar/ProgressBar.jsx";
-import { Button } from "../../../_utils/button/Button.jsx";
+import { round } from "../../../../features/math/round";
+import { ProgressBar } from "../../../_utils/progress-bar/ProgressBar";
+import { Button } from "../../../_utils/button/Button";
import { useVirtualRoot } from "../../../../hooks/virtual-drive/virtualRootContext";
-import { StorageManager } from "../../../../features/storage/storageManager.js";
+import { StorageManager } from "../../../../features/storage/storageManager";
export function StorageTab() {
const virtualRoot = useVirtualRoot();
diff --git a/src/components/apps/terminal/Ansi.jsx b/src/components/apps/terminal/Ansi.tsx
similarity index 99%
rename from src/components/apps/terminal/Ansi.jsx
rename to src/components/apps/terminal/Ansi.tsx
index 4899a5f..bc69cdf 100644
--- a/src/components/apps/terminal/Ansi.jsx
+++ b/src/components/apps/terminal/Ansi.tsx
@@ -57,7 +57,7 @@ function createClass(bundle) {
* @returns {object} returns the style object
*/
function createStyle(bundle) {
- const style = {};
+ const style: Record = {};
if (bundle.bg) {
style.backgroundColor = `rgb(${bundle.bg})`;
}
diff --git a/src/components/apps/terminal/InputLine.jsx b/src/components/apps/terminal/InputLine.tsx
similarity index 70%
rename from src/components/apps/terminal/InputLine.jsx
rename to src/components/apps/terminal/InputLine.tsx
index ec8cced..ce2d938 100644
--- a/src/components/apps/terminal/InputLine.jsx
+++ b/src/components/apps/terminal/InputLine.tsx
@@ -1,17 +1,18 @@
-import { useState } from "react";
+import { CSSProperties, MutableRefObject, useState } from "react";
import styles from "./Terminal.module.css";
-import Ansi from "./Ansi.jsx";
+import Ansi from "./Ansi";
-/**
- * @param {object} props
- * @param {string} props.value
- * @param {string} props.prefix
- * @param {Function} props.onChange
- * @param {Function} props.onKeyUp
- * @param {Function} props.onKeyDown
- * @param {import("react").MutableRefObject} props.inputRef
- */
-export function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown, inputRef }) {
+
+interface InputLineProps {
+ value: string;
+ prefix: string;
+ onChange: Function;
+ onKeyUp?: Function;
+ onKeyDown?: Function;
+ inputRef: MutableRefObject;
+}
+
+export function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown, inputRef }: InputLineProps) {
const [cursorPosition, setCursorPosition] = useState(0);
const checkCursorPosition = () => {
@@ -21,7 +22,7 @@ export function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown, inputRe
return (
{prefix && {prefix}}
-
+
{value}
{ onKeyUp?.(event); }}
onKeyDown={(event) => {
- onKeyDown(event);
+ onKeyDown?.(event);
checkCursorPosition();
}}
onClick={checkCursorPosition}
@@ -46,7 +47,6 @@ export function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown, inputRe
spellCheck={false}
autoComplete="off"
autoFocus
- size=""
/>
diff --git a/src/components/apps/terminal/OutputLine.jsx b/src/components/apps/terminal/OutputLine.jsx
deleted file mode 100644
index 587d3da..0000000
--- a/src/components/apps/terminal/OutputLine.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { forwardRef } from "react";
-import Ansi from "./Ansi.jsx";
-import styles from "./Terminal.module.css";
-
-/**
- * @param {object} props
- * @param {string} props.text
- * @param {*} props.ref
- */
-export const OutputLine = forwardRef(({ text }, ref) => {
- const lines = text?.split("\n");
-
- return (
- {lines.map((line, index) =>
-
{line === "" ? " " : line}
- )}
-
);
-});
\ No newline at end of file
diff --git a/src/components/apps/terminal/OutputLine.tsx b/src/components/apps/terminal/OutputLine.tsx
new file mode 100644
index 0000000..5c7ee60
--- /dev/null
+++ b/src/components/apps/terminal/OutputLine.tsx
@@ -0,0 +1,17 @@
+import { FC, forwardRef } from "react";
+import Ansi from "./Ansi";
+import styles from "./Terminal.module.css";
+
+interface OutputLineProps {
+ text: string;
+}
+
+export const OutputLine: FC = forwardRef(({ text }: OutputLineProps, ref) => {
+ const lines = text?.split("\n");
+
+ return
+ {lines.map((line, index) =>
+
{line === "" ? " " : line}
+ )}
+
;
+}) as FC;
\ No newline at end of file
diff --git a/src/components/apps/terminal/Terminal.jsx b/src/components/apps/terminal/Terminal.tsx
similarity index 92%
rename from src/components/apps/terminal/Terminal.jsx
rename to src/components/apps/terminal/Terminal.tsx
index 5754883..ccf0293 100644
--- a/src/components/apps/terminal/Terminal.jsx
+++ b/src/components/apps/terminal/Terminal.tsx
@@ -1,19 +1,23 @@
import { useEffect, useRef, useState } from "react";
import styles from "./Terminal.module.css";
import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext";
-import { clamp } from "../../../features/math/clamp.js";
-import { OutputLine } from "./OutputLine.jsx";
-import { InputLine } from "./InputLine.jsx";
-import { ANSI, HOSTNAME, USERNAME } from "../../../config/apps/terminal.config.js";
-import CommandsManager from "../../../features/apps/terminal/commands.js";
-import { removeFromArray } from "../../../features/_utils/array.utils.js";
-import Stream from "../../../features/apps/terminal/stream.js";
-import { formatError } from "../../../features/apps/terminal/_utils/terminal.utils.js";
+import { clamp } from "../../../features/math/clamp";
+import { OutputLine } from "./OutputLine";
+import { InputLine } from "./InputLine";
+import { ANSI, HOSTNAME, USERNAME } from "../../../config/apps/terminal.config";
+import CommandsManager from "../../../features/apps/terminal/commands";
+import { removeFromArray } from "../../../features/_utils/array.utils";
+import Stream from "../../../features/apps/terminal/stream";
+import { formatError } from "../../../features/apps/terminal/_utils/terminal.utils";
+import { WindowProps } from "../../windows/WindowView";
+import { VirtualFolder } from "../../../features/virtual-drive/folder/virtualFolder";
-/**
- * @param {import("../../windows/WindowView.jsx").windowProps} props
- */
-export function Terminal({ startPath, input, setTitle, close: exit, active }) {
+interface TerminalProps extends WindowProps {
+ startPath: string;
+ input: string;
+}
+
+export function Terminal({ startPath, input, setTitle, close: exit, active }: TerminalProps) {
const [inputKey, setInputKey] = useState(0);
const [inputValue, setInputValue] = useState(input ?? "");
const [history, setHistory] = useState([]);
@@ -73,7 +77,7 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
let lastOutput = null;
- stream.on(Stream.EVENT_NAMES.NEW, (text) => {
+ stream.on(Stream.EVENT_NAMES.new, (text) => {
let output = text;
pipes.forEach((pipe) => {
if (output instanceof Stream)
@@ -93,7 +97,7 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
setStreamOutput(output);
});
- stream.on(Stream.EVENT_NAMES.STOP, () => {
+ stream.on(Stream.EVENT_NAMES.stop, () => {
document.removeEventListener("keydown", onKeyDown);
promptOutput(lastOutput);
@@ -175,7 +179,7 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
promptOutput,
pushHistory,
virtualRoot,
- currentDirectory,
+ currentDirectory: currentDirectory as VirtualFolder,
setCurrentDirectory,
username: USERNAME,
hostname: HOSTNAME,
@@ -328,7 +332,6 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
onKeyDown={onKeyDown}
onChange={onChange}
inputRef={inputRef}
- history={history}
/>
:
}
diff --git a/src/components/apps/text-editor/TextEditor.jsx b/src/components/apps/text-editor/TextEditor.tsx
similarity index 91%
rename from src/components/apps/text-editor/TextEditor.jsx
rename to src/components/apps/text-editor/TextEditor.tsx
index 814bf63..668a029 100644
--- a/src/components/apps/text-editor/TextEditor.jsx
+++ b/src/components/apps/text-editor/TextEditor.tsx
@@ -1,18 +1,18 @@
import { useEffect, useRef, useState } from "react";
import styles from "./TextEditor.module.css";
-import { HeaderMenu } from "../_utils/header-menu/HeaderMenu.jsx";
+import { HeaderMenu } from "../_utils/header-menu/HeaderMenu";
import Markdown from "markdown-to-jsx";
-import { CODE_FORMATS, DEFAULT_ZOOM, EXTENSION_TO_LANGUAGE, ZOOM_FACTOR } from "../../../config/apps/textEditor.config.js";
-import AppsManager from "../../../features/apps/appsManager.js";
-import { TITLE_SEPARATOR } from "../../../config/windows.config.js";
-import { MarkdownLink } from "./overrides/MarkdownLink.jsx";
-import { MarkdownImage } from "./overrides/MarkdownImage.jsx";
+import { CODE_FORMATS, DEFAULT_ZOOM, EXTENSION_TO_LANGUAGE, ZOOM_FACTOR } from "../../../config/apps/textEditor.config";
+import AppsManager from "../../../features/apps/appsManager";
+import { TITLE_SEPARATOR } from "../../../config/windows.config";
+import { MarkdownLink } from "./overrides/MarkdownLink";
+import { MarkdownImage } from "./overrides/MarkdownImage";
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext";
import SyntaxHighlighter from "react-syntax-highlighter";
-import { useWindowedModal } from "../../../hooks/modals/windowedModal.js";
-import { DEFAULT_FILE_SELECTOR_SIZE } from "../../../config/modals.config.js";
-import { FileSelector } from "../../modals/file-selector/FileSelector.jsx";
-import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config.js";
+import { useWindowedModal } from "../../../hooks/modals/windowedModal";
+import { DEFAULT_FILE_SELECTOR_SIZE } from "../../../config/modals.config";
+import { FileSelector } from "../../modals/file-selector/FileSelector";
+import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config";
const OVERRIDES = {
a: MarkdownLink,
@@ -58,7 +58,7 @@ export function TextEditor({ file, setTitle, setIconUrl, close, mode, app, modal
setContent(newContent);
if (ref.current) {
- ref.current.scrollTo(0, 0);
+ (ref.current as HTMLElement).scrollTo(0, 0);
}
})();
}, [app.id, currentFile, setIconUrl]);
diff --git a/src/components/apps/text-editor/overrides/MarkdownImage.jsx b/src/components/apps/text-editor/overrides/MarkdownImage.tsx
similarity index 89%
rename from src/components/apps/text-editor/overrides/MarkdownImage.jsx
rename to src/components/apps/text-editor/overrides/MarkdownImage.tsx
index fcf25b0..9c73df4 100644
--- a/src/components/apps/text-editor/overrides/MarkdownImage.jsx
+++ b/src/components/apps/text-editor/overrides/MarkdownImage.tsx
@@ -1,8 +1,8 @@
import { useMemo } from "react";
-import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile.js";
-import ModalsManager from "../../../../features/modals/modalsManager.js";
-import App from "../../../../features/apps/app.js";
-import WindowsManager from "../../../../features/windows/windowsManager.js";
+import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile";
+import ModalsManager from "../../../../features/modals/modalsManager";
+import App from "../../../../features/apps/app";
+import WindowsManager from "../../../../features/windows/windowsManager";
/**
* @param {object} props
diff --git a/src/components/apps/text-editor/overrides/MarkdownLink.jsx b/src/components/apps/text-editor/overrides/MarkdownLink.tsx
similarity index 83%
rename from src/components/apps/text-editor/overrides/MarkdownLink.jsx
rename to src/components/apps/text-editor/overrides/MarkdownLink.tsx
index ad7e047..1ac4e3e 100644
--- a/src/components/apps/text-editor/overrides/MarkdownLink.jsx
+++ b/src/components/apps/text-editor/overrides/MarkdownLink.tsx
@@ -1,17 +1,17 @@
import { useMemo } from "react";
import { faExternalLink } from "@fortawesome/free-solid-svg-icons";
-import { useContextMenu } from "../../../../hooks/modals/contextMenu.js";
-import { Actions } from "../../../actions/Actions.jsx";
-import { ClickAction } from "../../../actions/actions/ClickAction.jsx";
-import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile.js";
-import { useWindowedModal } from "../../../../hooks/modals/windowedModal.js";
-import AppsManager from "../../../../features/apps/appsManager.js";
-import App from "../../../../features/apps/app.js";
-import { DialogBox } from "../../../modals/dialog-box/DialogBox.jsx";
-import { DIALOG_CONTENT_TYPES } from "../../../../config/modals.config.js";
-import Vector2 from "../../../../features/math/vector2.js";
-import WindowsManager from "../../../../features/windows/windowsManager.js";
-import { APPS } from "../../../../config/apps.config.js";
+import { useContextMenu } from "../../../../hooks/modals/contextMenu";
+import { Actions } from "../../../actions/Actions";
+import { ClickAction } from "../../../actions/actions/ClickAction";
+import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile";
+import { useWindowedModal } from "../../../../hooks/modals/windowedModal";
+import AppsManager from "../../../../features/apps/appsManager";
+import App from "../../../../features/apps/app";
+import { DialogBox } from "../../../modals/dialog-box/DialogBox";
+import { DIALOG_CONTENT_TYPES } from "../../../../config/modals.config";
+import Vector2 from "../../../../features/math/vector2";
+import WindowsManager from "../../../../features/windows/windowsManager";
+import { APPS } from "../../../../config/apps.config";
/**
* @param {object} props
diff --git a/src/components/desktop/Desktop.jsx b/src/components/desktop/Desktop.tsx
similarity index 82%
rename from src/components/desktop/Desktop.jsx
rename to src/components/desktop/Desktop.tsx
index bf9e3ae..39fbea3 100644
--- a/src/components/desktop/Desktop.jsx
+++ b/src/components/desktop/Desktop.tsx
@@ -1,47 +1,47 @@
import { memo, useState } from "react";
-import { SettingsManager } from "../../features/settings/settingsManager.js";
+import { SettingsManager } from "../../features/settings/settingsManager";
import { useSettingsManager } from "../../hooks/settings/settingsManagerContext";
import styles from "./Desktop.module.css";
import { useEffect } from "react";
import { useWindowsManager } from "../../hooks/windows/windowsManagerContext";
-import { useContextMenu } from "../../hooks/modals/contextMenu.js";
-import { FALLBACK_ICON_SIZE, FALLBACK_WALLPAPER } from "../../config/desktop.config.js";
-import { reloadViewport } from "../../features/_utils/browser.utils.js";
+import { useContextMenu } from "../../hooks/modals/contextMenu";
+import { FALLBACK_ICON_SIZE, FALLBACK_WALLPAPER } from "../../config/desktop.config";
+import { reloadViewport } from "../../features/_utils/browser.utils";
import { useVirtualRoot } from "../../hooks/virtual-drive/virtualRootContext";
-import { DirectoryList } from "../apps/file-explorer/directory-list/DirectoryList.jsx";
-import { APPS, APP_ICONS, APP_NAMES } from "../../config/apps.config.js";
-import Vector2 from "../../features/math/vector2.js";
-import { Actions } from "../actions/Actions.jsx";
-import { ClickAction } from "../actions/actions/ClickAction.jsx";
+import { DirectoryList } from "../apps/file-explorer/directory-list/DirectoryList";
+import { APPS, APP_ICONS, APP_NAMES } from "../../config/apps.config";
+import Vector2 from "../../features/math/vector2";
+import { Actions } from "../actions/Actions";
+import { ClickAction } from "../actions/actions/ClickAction";
import { faArrowsRotate, faEye, faFolder, faPaintBrush, faTerminal, faTrash } from "@fortawesome/free-solid-svg-icons";
-import { ToggleAction } from "../actions/actions/ToggleAction.jsx";
-import { DropdownAction } from "../actions/actions/DropdownAction.jsx";
-import { RadioAction } from "../actions/actions/RadioAction.jsx";
-import { Divider } from "../actions/actions/Divider.jsx";
-import { isValidInteger } from "../../features/_utils/number.utils.js";
-import { useWindowedModal } from "../../hooks/modals/windowedModal.js";
-import { Share } from "../modals/share/Share.jsx";
+import { ToggleAction } from "../actions/actions/ToggleAction";
+import { DropdownAction } from "../actions/actions/DropdownAction";
+import { RadioAction } from "../actions/actions/RadioAction";
+import { Divider } from "../actions/actions/Divider";
+import { isValidInteger } from "../../features/_utils/number.utils";
+import { useWindowedModal } from "../../hooks/modals/windowedModal";
+import { Share } from "../modals/share/Share";
import ModalsManager from "../../features/modals/modalsManager";
-import { useModalsManager } from "../../hooks/modals/modalsManagerContext";
+import { VirtualFolder } from "../../features/virtual-drive/folder/virtualFolder";
+import { VirtualFolderLink } from "../../features/virtual-drive/folder/virtualFolderLink";
export const Desktop = memo(() => {
const settingsManager = useSettingsManager();
const [wallpaper, setWallpaper] = useState(null);
- const modalsManager = useModalsManager();
const windowsManager = useWindowsManager();
const virtualRoot = useVirtualRoot();
const [showIcons, setShowIcons] = useState(false);
const [iconSize, setIconSize] = useState(FALLBACK_ICON_SIZE);
- const { openWindowedModal } = useWindowedModal({ modalsManager });
+ const { openWindowedModal } = useWindowedModal();
const directory = virtualRoot.navigate("~/Desktop");
- const { onContextMenu, ShortcutsListener } = useContextMenu({ modalsManager, Actions: (props) =>
+ const { onContextMenu, ShortcutsListener } = useContextMenu({ Actions: (props) =>
- {
+ {
const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
- settings.set("icon-size", parseInt(value));
+ settings.set("icon-size", value);
}} options={[
{ label: "Small icons" },
{ label: "Medium icons" },
@@ -75,7 +75,7 @@ export const Desktop = memo(() => {
}}/>
});
- const { onContextMenu: onContextMenuFile } = useContextMenu({ modalsManager, Actions: (props) =>
+ const { onContextMenu: onContextMenuFile } = useContextMenu({ Actions: (props) =>
{
file.open(windowsManager);
@@ -88,7 +88,7 @@ export const Desktop = memo(() => {
}}/>
});
- const { onContextMenu: onContextMenuFolder } = useContextMenu({ modalsManager, Actions: (props) =>
+ const { onContextMenu: onContextMenuFolder } = useContextMenu({ Actions: (props) =>
{
folder.open(windowsManager);
@@ -138,7 +138,7 @@ export const Desktop = memo(() => {
onContextMenu={onContextMenu}
>
{showIcons && {
fileClassName={styles["Item"]}
folderClassName={styles["Item"]}
onOpenFile={(event, file) => {
- event.preventDefault();
+ (event as Event).preventDefault();
- const options = {};
+ const options: Record = {};
if (file.name === "info.md")
options.size = new Vector2(575, 675);
if (file.extension === "md")
@@ -156,7 +156,7 @@ export const Desktop = memo(() => {
windowsManager.openFile(file, options);
}}
- onOpenFolder={(event, { linkedPath, path }) => {
+ onOpenFolder={(event, { linkedPath, path }: VirtualFolderLink & VirtualFolder) => {
windowsManager.open(APPS.FILE_EXPLORER, { startPath: linkedPath ?? path });
}}
onContextMenuFile={onContextMenuFile}
diff --git a/src/components/modals/ModalView.jsx b/src/components/modals/ModalView.tsx
similarity index 71%
rename from src/components/modals/ModalView.jsx
rename to src/components/modals/ModalView.tsx
index b6b9f1c..90aa38f 100644
--- a/src/components/modals/ModalView.jsx
+++ b/src/components/modals/ModalView.tsx
@@ -1,22 +1,25 @@
-import { memo } from "react";
-import { Modal as ModalType } from "../../features/modals/modal.js";
-import OutsideClickListener from "../../hooks/_utils/outsideClick.js";
+import { CSSProperties, FC, memo, ReactNode } from "react";
+import Modal from "../../features/modals/modal";
+import OutsideClickListener from "../../hooks/_utils/outsideClick";
import styles from "./ModalView.module.css";
import { useEffect } from "react";
/**
* @typedef {object} modalProps
* @param {object} props
- * @param {ModalType} props.modal
+ * @param {Modal} props.modal
* @param {*} props.params
* @param {Function} props.onFinish
*/
-/**
- * @param {object} root
- * @param {ModalType} root.modal
- */
-export const ModalView = memo(({ modal }) => {
+export interface ModalProps {
+ modal: Modal;
+ params?: Record;
+ children?: ReactNode;
+ [key: string]: any;
+}
+
+export const ModalView: FC = memo(({ modal }) => {
useEffect(() => {
const onDismiss = (event) => {
if (event.key === "Escape")
@@ -32,7 +35,7 @@ export const ModalView = memo(({ modal }) => {
const Container = () => (
);
diff --git a/src/components/modals/ModalsView.jsx b/src/components/modals/ModalsView.tsx
similarity index 94%
rename from src/components/modals/ModalsView.jsx
rename to src/components/modals/ModalsView.tsx
index 17235fc..8971776 100644
--- a/src/components/modals/ModalsView.jsx
+++ b/src/components/modals/ModalsView.tsx
@@ -1,5 +1,5 @@
import { memo, useEffect, useRef, useState } from "react";
-import { ModalView } from "./ModalView.jsx";
+import { ModalView } from "./ModalView";
import styles from "./ModalsView.module.css";
import { useModals } from "../../hooks/modals/modalsContext";
import { useModalsManager } from "../../hooks/modals/modalsManagerContext";
diff --git a/src/components/modals/_utils/WindowedModal.jsx b/src/components/modals/_utils/WindowedModal.tsx
similarity index 92%
rename from src/components/modals/_utils/WindowedModal.jsx
rename to src/components/modals/_utils/WindowedModal.tsx
index 77b2789..3cc3db3 100644
--- a/src/components/modals/_utils/WindowedModal.jsx
+++ b/src/components/modals/_utils/WindowedModal.tsx
@@ -1,13 +1,14 @@
import { useEffect, useRef, useState } from "react";
-import { useScreenDimensions } from "../../../hooks/_utils/screen.js";
-import Vector2 from "../../../features/math/vector2.js";
+import { useScreenDimensions } from "../../../hooks/_utils/screen";
+import Vector2 from "../../../features/math/vector2";
import styles from "./WindowedModal.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import Draggable from "react-draggable";
import { ReactSVG } from "react-svg";
import utilStyles from "../../../styles/utils.module.css";
-import Modal from "../../../features/modals/modal.js";
+import Modal from "../../../features/modals/modal";
+import { ModalProps } from "../ModalView";
/**
* @param {object} props
@@ -15,7 +16,7 @@ import Modal from "../../../features/modals/modal.js";
* @param {*} props.params
* @param {*} props.children
*/
-export function WindowedModal({ modal, params, children, ...props }) {
+export function WindowedModal({ modal, params, children, ...props }: ModalProps) {
const { iconUrl, title } = params;
const nodeRef = useRef(null);
diff --git a/src/components/modals/dialog-box/DialogBox.jsx b/src/components/modals/dialog-box/DialogBox.tsx
similarity index 56%
rename from src/components/modals/dialog-box/DialogBox.jsx
rename to src/components/modals/dialog-box/DialogBox.tsx
index f1767b1..87b3dea 100644
--- a/src/components/modals/dialog-box/DialogBox.jsx
+++ b/src/components/modals/dialog-box/DialogBox.tsx
@@ -1,11 +1,12 @@
-import { DIALOG_CONTENT_TYPES } from "../../../config/modals.config.js";
-import { WindowedModal } from "../_utils/WindowedModal.jsx";
+import { DIALOG_CONTENT_TYPES } from "../../../config/modals.config";
+import { WindowedModal } from "../_utils/WindowedModal";
+import { ModalProps } from "../ModalView";
import styles from "./DialogBox.module.css";
-export function DialogBox({ modal, params, children, ...props }) {
- const onClick = (event) => {
+export function DialogBox({ modal, params, children, ...props }: ModalProps) {
+ const onClick = (event: MouseEvent) => {
event.preventDefault();
- const type = parseInt(event.target.getAttribute("data-type"));
+ const type = parseInt((event.target as HTMLElement).getAttribute("data-type"));
switch (type) {
case DIALOG_CONTENT_TYPES.CloseButton:
diff --git a/src/components/modals/file-properties/FileProperties.jsx b/src/components/modals/file-properties/FileProperties.tsx
similarity index 81%
rename from src/components/modals/file-properties/FileProperties.jsx
rename to src/components/modals/file-properties/FileProperties.tsx
index 2380bb2..ab7ffcd 100644
--- a/src/components/modals/file-properties/FileProperties.jsx
+++ b/src/components/modals/file-properties/FileProperties.tsx
@@ -1,19 +1,17 @@
-import { ImagePreview } from "../../apps/file-explorer/directory-list/ImagePreview.jsx";
-import { WindowedModal } from "../_utils/WindowedModal.jsx";
+import { ImagePreview } from "../../apps/file-explorer/directory-list/ImagePreview";
+import { WindowedModal } from "../_utils/WindowedModal";
import styles from "./FileProperties.module.css";
import utilStyles from "../../../styles/utils.module.css";
-import Modal from "../../../features/modals/modal.js";
+import { StorageManager } from "../../../features/storage/storageManager";
+import AppsManager from "../../../features/apps/appsManager";
+import { ModalProps } from "../ModalView.js";
import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile.js";
-import { StorageManager } from "../../../features/storage/storageManager.js";
-import AppsManager from "../../../features/apps/appsManager.js";
-/**
- * @param {object} props
- * @param {Modal} props.modal
- * @param {object} props.params
- * @param {VirtualFile} props.file
- */
-export function FileProperties({ modal, params, file, ...props }) {
+interface FilePropetiesProps extends ModalProps {
+ file: VirtualFile;
+}
+
+export function FileProperties({ modal, params, file, ...props }: FilePropetiesProps) {
const associatedApp = AppsManager.getAppByFileExtension(file.extension);
return
diff --git a/src/components/modals/file-selector/FileSelector.jsx b/src/components/modals/file-selector/FileSelector.tsx
similarity index 72%
rename from src/components/modals/file-selector/FileSelector.jsx
rename to src/components/modals/file-selector/FileSelector.tsx
index df3bb50..ddee960 100644
--- a/src/components/modals/file-selector/FileSelector.jsx
+++ b/src/components/modals/file-selector/FileSelector.tsx
@@ -1,31 +1,22 @@
import { useState } from "react";
-import { APP_ICONS } from "../../../config/apps.config.js";
-import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config.js";
-import { Button } from "../../_utils/button/Button.jsx";
-import { FileExplorer } from "../../apps/file-explorer/FileExplorer.jsx";
-import { WindowedModal } from "../_utils/WindowedModal.jsx";
+import { APP_ICONS } from "../../../config/apps.config";
+import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config";
+import { Button } from "../../_utils/button/Button";
+import { FileExplorer } from "../../apps/file-explorer/FileExplorer";
+import { WindowedModal } from "../_utils/WindowedModal";
import styles from "./FileSelector.module.css";
-import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile.js";
-import Modal from "../../../features/modals/modal.js";
-import { useModalsManager } from "../../../hooks/modals/modalsManagerContext";
+import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile";
+import { ModalProps } from "../ModalView";
-/**
- * @callback onFinish
- * @param {VirtualFile|VirtualFile[]} result
- */
+interface FileSelectorProps extends ModalProps {
+ type: number;
+ allowedFormats?: string[];
+ onFinish: (result: VirtualFile | VirtualFile[]) => void;
+}
-/**
- * @param {object} props
- * @param {Modal} props.modal
- * @param {*} props.params
- * @param {number} props.type
- * @param {string[]=} props.allowedFormats
- * @param {onFinish} props.onFinish
- */
-export function FileSelector({ modal, params, type, allowedFormats, onFinish, ...props }) {
+export function FileSelector({ modal, params, type, allowedFormats, onFinish, ...props }: FileSelectorProps) {
const multi = (type === SELECTOR_MODE.MULTIPLE);
- const modalsManager = useModalsManager();
const [selection, setSelection] = useState(multi ? [] : null);
const [directory, setDirectory] = useState(null);
@@ -58,7 +49,6 @@ export function FileSelector({ modal, params, type, allowedFormats, onFinish, ..
...params,
}} {...props}>
diff --git a/src/components/modals/share/Option.jsx b/src/components/modals/share/Option.tsx
similarity index 100%
rename from src/components/modals/share/Option.jsx
rename to src/components/modals/share/Option.tsx
diff --git a/src/components/modals/share/Share.jsx b/src/components/modals/share/Share.tsx
similarity index 90%
rename from src/components/modals/share/Share.jsx
rename to src/components/modals/share/Share.tsx
index 2421aee..2d52fd2 100644
--- a/src/components/modals/share/Share.jsx
+++ b/src/components/modals/share/Share.tsx
@@ -1,16 +1,16 @@
import { useEffect, useState } from "react";
-import ModalsManager from "../../../features/modals/modalsManager.js";
-import { WindowedModal } from "../_utils/WindowedModal.jsx";
+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.js";
-import AppsManager from "../../../features/apps/appsManager.js";
+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.jsx";
-import Option from "./Option.jsx";
+import { Button } from "../../_utils/button/Button";
+import Option from "./Option";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSquare } from "@fortawesome/free-regular-svg-icons";
import { faSquareCheck } from "@fortawesome/free-solid-svg-icons";
-import { useAlert } from "../../../hooks/modals/alert.js";
+import { useAlert } from "../../../hooks/modals/alert";
const APP_OPTIONS = {
"terminal": [
@@ -39,7 +39,7 @@ export function Share({ modal, params, ...props }) {
const [fullscreen, setFullscreen] = useState(params.fullscreen ?? false);
const [options, setOptions] = useState({});
const [url, setUrl] = useState(null);
- const { alert } = useAlert({ modalsManager: modal.modalsManager });
+ const { alert } = useAlert();
useEffect(() => {
setUrl(generateUrl({
diff --git a/src/components/taskbar/Taskbar.jsx b/src/components/taskbar/Taskbar.tsx
similarity index 79%
rename from src/components/taskbar/Taskbar.jsx
rename to src/components/taskbar/Taskbar.tsx
index fbba7f3..3525770 100644
--- a/src/components/taskbar/Taskbar.jsx
+++ b/src/components/taskbar/Taskbar.tsx
@@ -1,30 +1,29 @@
-import { memo, useEffect, useMemo, useRef, useState } from "react";
+import { CSSProperties, memo, useEffect, useMemo, useRef, useState } from "react";
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.js";
+import AppsManager from "../../features/apps/appsManager";
import { ReactSVG } from "react-svg";
-import { HomeMenu } from "./menus/HomeMenu.jsx";
-import OutsideClickListener from "../../hooks/_utils/outsideClick.js";
-import { Battery } from "./indicators/Battery.jsx";
-import { Network } from "./indicators/Network.jsx";
-import { Volume } from "./indicators/Volume.jsx";
-import { SearchMenu } from "./menus/SearchMenu.jsx";
-import { Calendar } from "./indicators/Calendar.jsx";
-import { useScrollWithShadow } from "../../hooks/_utils/scrollWithShadows.js";
-import { AppButton } from "./app-icon/AppIcon.jsx";
-import { useContextMenu } from "../../hooks/modals/contextMenu.js";
-import { Actions } from "../actions/Actions.jsx";
-import { ClickAction } from "../actions/actions/ClickAction.jsx";
-import { APPS, APP_NAMES } from "../../config/apps.config.js";
+import { HomeMenu } from "./menus/HomeMenu";
+import OutsideClickListener from "../../hooks/_utils/outsideClick";
+import { Battery } from "./indicators/Battery";
+import { Network } from "./indicators/Network";
+import { Volume } from "./indicators/Volume";
+import { SearchMenu } from "./menus/SearchMenu";
+import { Calendar } from "./indicators/Calendar";
+import { useScrollWithShadow } from "../../hooks/_utils/scrollWithShadows";
+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 "../../config/apps.config";
import { useWindowsManager } from "../../hooks/windows/windowsManagerContext";
-import { TASKBAR_HEIGHT } from "../../config/taskbar.config.js";
+import { TASKBAR_HEIGHT } from "../../config/taskbar.config";
import { useSettingsManager } from "../../hooks/settings/settingsManagerContext";
-import { SettingsManager } from "../../features/settings/settingsManager.js";
+import { SettingsManager } from "../../features/settings/settingsManager";
import { useWindows } from "../../hooks/windows/windowsContext";
-import { ZIndexManager } from "../../features/z-index/zIndexManager.js";
-import { useZIndex } from "../../hooks/z-index/zIndex.js";
-import { useModalsManager } from "../../hooks/modals/modalsManagerContext";
+import { ZIndexManager } from "../../features/z-index/zIndexManager";
+import { useZIndex } from "../../hooks/z-index/zIndex";
export const Taskbar = memo(() => {
const ref = useRef(null);
@@ -40,10 +39,9 @@ export const Taskbar = memo(() => {
color: { a: 25 }
} });
const inputRef = useRef(null);
- const modalsManager = useModalsManager();
const windowsManager = useWindowsManager();
const windows = useWindows();
- const { onContextMenu } = useContextMenu({ modalsManager, Actions: (props) =>
+ const { onContextMenu } = useContextMenu({ Actions: (props) =>
{
windowsManager.open(APPS.SETTINGS);
@@ -70,14 +68,13 @@ export const Taskbar = memo(() => {
const shouldBeShown = (pins.includes(app.id) || isActive);
return ();
- }), [modalsManager, pins, windows, windowsManager]);
+ }), [pins, windows, windowsManager]);
useEffect(() => {
const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.taskbar);
@@ -131,11 +128,11 @@ export const Taskbar = memo(() => {
return (<>
{
- if (event.target.getAttribute("data-allow-context-menu"))
+ if ((event.target as HTMLElement).getAttribute("data-allow-context-menu"))
onContextMenu(event);
}}
>
@@ -193,4 +190,4 @@ export const Taskbar = memo(() => {
>);
-}, []);
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/src/components/taskbar/app-icon/AppIcon.jsx b/src/components/taskbar/app-icon/AppIcon.tsx
similarity index 73%
rename from src/components/taskbar/app-icon/AppIcon.jsx
rename to src/components/taskbar/app-icon/AppIcon.tsx
index 6f5efbc..c6df553 100644
--- a/src/components/taskbar/app-icon/AppIcon.jsx
+++ b/src/components/taskbar/app-icon/AppIcon.tsx
@@ -1,29 +1,30 @@
-import { memo } from "react";
-import App from "../../../features/apps/app.js";
+import { FC, memo } from "react";
+import App from "../../../features/apps/app";
import styles from "./AppIcon.module.css";
import { ReactSVG } from "react-svg";
import { useSettingsManager } from "../../../hooks/settings/settingsManagerContext";
-import { useContextMenu } from "../../../hooks/modals/contextMenu.js";
-import ModalsManager from "../../../features/modals/modalsManager.js";
-import { Actions } from "../../actions/Actions.jsx";
-import { ClickAction } from "../../actions/actions/ClickAction.jsx";
+import { useContextMenu } from "../../../hooks/modals/contextMenu";
+import { Actions } from "../../actions/Actions";
+import { ClickAction } from "../../actions/actions/ClickAction";
import { faThumbTack, faTimes } from "@fortawesome/free-solid-svg-icons";
-import { SettingsManager } from "../../../features/settings/settingsManager.js";
-import { removeFromArray } from "../../../features/_utils/array.utils.js";
-import AppsManager from "../../../features/apps/appsManager.js";
+import { SettingsManager } from "../../../features/settings/settingsManager";
+import { removeFromArray } from "../../../features/_utils/array.utils";
+import AppsManager from "../../../features/apps/appsManager";
+import WindowsManager from "../../../features/windows/windowsManager";
-/**
- * @param {object} props
- * @param {App} props.app
- * @param {ModalsManager} props.modalsManager
- * @param {string[]} props.pins
- * @param {boolean} props.focused
- */
-export const AppButton = memo(({ app, windowsManager, modalsManager, pins, active, visible }) => {
+interface AppButtonProps {
+ app: App;
+ windowsManager: WindowsManager;
+ pins: string[];
+ active: boolean;
+ visible: boolean;
+}
+
+export const AppButton: FC = memo(({ app, windowsManager, pins, active, visible }: AppButtonProps) => {
const isPinned = pins.includes(app.id);
const settingsManager = useSettingsManager();
- const { onContextMenu } = useContextMenu({ modalsManager, Actions: (props) =>
+ const { onContextMenu } = useContextMenu({ Actions: (props) =>
{
windowsManager.open(app.id);
diff --git a/src/components/taskbar/indicators/Battery.jsx b/src/components/taskbar/indicators/Battery.tsx
similarity index 91%
rename from src/components/taskbar/indicators/Battery.jsx
rename to src/components/taskbar/indicators/Battery.tsx
index bfa58bf..151a6bf 100644
--- a/src/components/taskbar/indicators/Battery.jsx
+++ b/src/components/taskbar/indicators/Battery.tsx
@@ -2,15 +2,15 @@ import { faBatteryEmpty, faBatteryFull, faBatteryHalf, faBatteryQuarter, faBatte
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useEffect, useState } from "react";
import styles from "./Battery.module.css";
-import { UtilMenu } from "../menus/UtilMenu.jsx";
-import OutsideClickListener from "../../../hooks/_utils/outsideClick.js";
+import { UtilMenu } from "../menus/UtilMenu";
+import OutsideClickListener from "../../../hooks/_utils/outsideClick";
-/**
- * @param {object} props
- * @param {boolean} props.hideUtilMenus
- * @param {Function} props.showUtilMenu
- */
-export function Battery({ hideUtilMenus, showUtilMenu }) {
+interface BatteryProps {
+ hideUtilMenus: boolean;
+ showUtilMenu: Function;
+}
+
+export function Battery({ hideUtilMenus, showUtilMenu }: BatteryProps) {
const [isCharging, setIsCharging] = useState(true);
const [percentage, setPercentage] = useState(100);
const [showMenu, setShowMenu] = useState(false);
@@ -18,7 +18,7 @@ export function Battery({ hideUtilMenus, showUtilMenu }) {
// const [dischargingTime, setDischargingTime] = useState(0);
useEffect(() => {
- navigator.getBattery?.()?.then((battery) => {
+ (navigator as any).getBattery?.()?.then((battery) => {
const updateIsCharging = () => {
setIsCharging(battery.charging);
};
diff --git a/src/components/taskbar/indicators/Calendar.jsx b/src/components/taskbar/indicators/Calendar.tsx
similarity index 96%
rename from src/components/taskbar/indicators/Calendar.jsx
rename to src/components/taskbar/indicators/Calendar.tsx
index ca5d97b..c4e7ead 100644
--- a/src/components/taskbar/indicators/Calendar.jsx
+++ b/src/components/taskbar/indicators/Calendar.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import styles from "./Calendar.module.css";
-import OutsideClickListener from "../../../hooks/_utils/outsideClick.js";
-import { UtilMenu } from "../menus/UtilMenu.jsx";
+import OutsideClickListener from "../../../hooks/_utils/outsideClick";
+import { UtilMenu } from "../menus/UtilMenu";
/**
* @param {object} props
diff --git a/src/components/taskbar/indicators/Network.jsx b/src/components/taskbar/indicators/Network.tsx
similarity index 94%
rename from src/components/taskbar/indicators/Network.jsx
rename to src/components/taskbar/indicators/Network.tsx
index d8f18d5..4e6a794 100644
--- a/src/components/taskbar/indicators/Network.jsx
+++ b/src/components/taskbar/indicators/Network.tsx
@@ -1,8 +1,8 @@
import { faWifi } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useEffect, useState } from "react";
-import OutsideClickListener from "../../../hooks/_utils/outsideClick.js";
-import { UtilMenu } from "../menus/UtilMenu.jsx";
+import OutsideClickListener from "../../../hooks/_utils/outsideClick";
+import { UtilMenu } from "../menus/UtilMenu";
import styles from "./Network.module.css";
/**
diff --git a/src/components/taskbar/indicators/Volume.jsx b/src/components/taskbar/indicators/Volume.tsx
similarity index 94%
rename from src/components/taskbar/indicators/Volume.jsx
rename to src/components/taskbar/indicators/Volume.tsx
index 8489c41..74824ad 100644
--- a/src/components/taskbar/indicators/Volume.jsx
+++ b/src/components/taskbar/indicators/Volume.tsx
@@ -1,8 +1,8 @@
import { faVolumeHigh } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useEffect, useState } from "react";
-import OutsideClickListener from "../../../hooks/_utils/outsideClick.js";
-import { UtilMenu } from "../menus/UtilMenu.jsx";
+import OutsideClickListener from "../../../hooks/_utils/outsideClick";
+import { UtilMenu } from "../menus/UtilMenu";
import styles from "./Volume.module.css";
/**
diff --git a/src/components/taskbar/menus/HomeMenu.jsx b/src/components/taskbar/menus/HomeMenu.tsx
similarity index 93%
rename from src/components/taskbar/menus/HomeMenu.jsx
rename to src/components/taskbar/menus/HomeMenu.tsx
index 429dd0d..61feeae 100644
--- a/src/components/taskbar/menus/HomeMenu.jsx
+++ b/src/components/taskbar/menus/HomeMenu.tsx
@@ -3,16 +3,16 @@ 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";
-import AppsManager from "../../../features/apps/appsManager.js";
+import AppsManager from "../../../features/apps/appsManager";
import { ReactSVG } from "react-svg";
-import { closeViewport } from "../../../features/_utils/browser.utils.js";
-import { useKeyboardListener } from "../../../hooks/_utils/keyboard.js";
+import { closeViewport } from "../../../features/_utils/browser.utils";
+import { useKeyboardListener } from "../../../hooks/_utils/keyboard";
import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext";
import { useEffect, useState } from "react";
-import Vector2 from "../../../features/math/vector2.js";
+import Vector2 from "../../../features/math/vector2";
import utilStyles from "../../../styles/utils.module.css";
-import { APPS } from "../../../config/apps.config.js";
-import { NAME } from "../../../config/branding.config.js";
+import { APPS } from "../../../config/apps.config";
+import { NAME } from "../../../config/branding.config";
/**
* @param {object} props
diff --git a/src/components/taskbar/menus/SearchMenu.jsx b/src/components/taskbar/menus/SearchMenu.tsx
similarity index 97%
rename from src/components/taskbar/menus/SearchMenu.jsx
rename to src/components/taskbar/menus/SearchMenu.tsx
index 91a97ae..49d7793 100644
--- a/src/components/taskbar/menus/SearchMenu.jsx
+++ b/src/components/taskbar/menus/SearchMenu.tsx
@@ -1,10 +1,10 @@
import styles from "./SearchMenu.module.css";
import appStyles from "./AppList.module.css";
-import AppsManager from "../../../features/apps/appsManager.js";
+import AppsManager from "../../../features/apps/appsManager";
import { useWindowsManager } from "../../../hooks/windows/windowsManagerContext";
import { ReactSVG } from "react-svg";
import { useEffect, useState } from "react";
-import { useKeyboardListener } from "../../../hooks/_utils/keyboard.js";
+import { useKeyboardListener } from "../../../hooks/_utils/keyboard";
/**
* @param {object} props
diff --git a/src/components/taskbar/menus/UtilMenu.jsx b/src/components/taskbar/menus/UtilMenu.tsx
similarity index 100%
rename from src/components/taskbar/menus/UtilMenu.jsx
rename to src/components/taskbar/menus/UtilMenu.tsx
diff --git a/src/components/windows/WindowFallbackView.jsx b/src/components/windows/WindowFallbackView.jsx
deleted file mode 100644
index 737bb06..0000000
--- a/src/components/windows/WindowFallbackView.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { useEffect, useState } from "react";
-import { useModalsManager } from "../../hooks/modals/modalsManagerContext";
-import { useAlert } from "../../hooks/modals/alert.js";
-import AppsManager from "../../features/apps/appsManager.js";
-import Vector2 from "../../features/math/vector2.js";
-
-export default function WindowFallbackView({ error, resetErrorBoundary, app, closeWindow }) {
- const modalsManager = useModalsManager();
- const { alert } = useAlert({ modalsManager });
- const [alerted, setAlerted] = useState(false);
-
- useEffect(() => {
- if (alerted)
- return;
-
- setAlerted(true);
- closeWindow();
- alert({
- title: `${app.name} has stopped working`,
- text: `${error.name}: ${error.message}`,
- iconUrl: AppsManager.getAppIconUrl(app.id),
- size: new Vector2(350, 150),
- single: true
- });
- }, [alerted, alert, app.id, app.name, error.message, closeWindow, error.name]);
-
- return;
-}
\ No newline at end of file
diff --git a/src/components/windows/WindowFallbackView.tsx b/src/components/windows/WindowFallbackView.tsx
new file mode 100644
index 0000000..3f41716
--- /dev/null
+++ b/src/components/windows/WindowFallbackView.tsx
@@ -0,0 +1,35 @@
+import { ReactNode, 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";
+
+export interface WindowFallbackViewProps {
+ error?: Error;
+ resetErrorBoundary?: any;
+ app?: App;
+ closeWindow?: Function
+}
+
+// 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 default function WindowFallbackView({ error, resetErrorBoundary, app, closeWindow }: WindowFallbackViewProps): ReactNode {
+ const { alert } = useAlert();
+ const [alerted, setAlerted] = useState(false);
+
+ useEffect(() => {
+ if (alerted)
+ return;
+
+ setAlerted(true);
+ closeWindow();
+ alert({
+ title: `${app.name} has stopped working`,
+ text: `${error.name}: ${error.message}`,
+ iconUrl: AppsManager.getAppIconUrl(app.id),
+ size: new Vector2(350, 150),
+ single: true
+ });
+ }, [alerted, alert, app.id, app.name, error.message, closeWindow, error.name]);
+
+ return;
+}
\ No newline at end of file
diff --git a/src/components/windows/WindowView.jsx b/src/components/windows/WindowView.tsx
similarity index 76%
rename from src/components/windows/WindowView.jsx
rename to src/components/windows/WindowView.tsx
index b172b41..62993b1 100644
--- a/src/components/windows/WindowView.jsx
+++ b/src/components/windows/WindowView.tsx
@@ -4,52 +4,41 @@ import { faExpand, faMinus, faWindowMaximize as fasWindowMaximize, faTimes, faXm
import { ReactSVG } from "react-svg";
import { useWindowsManager } from "../../hooks/windows/windowsManagerContext";
import Draggable from "react-draggable";
-import { memo, useEffect, useRef, useState } from "react";
-import App from "../../features/apps/app.js";
-import Vector2 from "../../features/math/vector2.js";
+import { FC, memo, MouseEventHandler, useEffect, useRef, useState } from "react";
+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.js";
-import AppsManager from "../../features/apps/appsManager.js";
-import { ClickAction } from "../actions/actions/ClickAction.jsx";
-import { Actions } from "../actions/Actions.jsx";
-import { useScreenDimensions } from "../../hooks/_utils/screen.js";
-import { NAME } from "../../config/branding.config.js";
-import { setViewportIcon, setViewportTitle } from "../../features/_utils/browser.utils.js";
-import { ZIndexManager } from "../../features/z-index/zIndexManager.js";
+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";
+import { NAME } from "../../config/branding.config";
+import { setViewportIcon, setViewportTitle } from "../../features/_utils/browser.utils";
+import { ZIndexManager } from "../../features/z-index/zIndexManager";
import { useZIndex } from "../../hooks/z-index/zIndex";
-import { useWindowedModal } from "../../hooks/modals/windowedModal.js";
-import { Divider } from "../actions/actions/Divider.jsx";
-import ModalsManager from "../../features/modals/modalsManager.js";
-import { Share } from "../modals/share/Share.jsx";
+import { useWindowedModal } from "../../hooks/modals/windowedModal";
+import { Divider } from "../actions/actions/Divider";
+import ModalsManager from "../../features/modals/modalsManager";
+import { Share } from "../modals/share/Share";
import { ErrorBoundary } from "react-error-boundary";
-import WindowFallbackView from "./WindowFallbackView.jsx";
+import WindowFallbackView from "./WindowFallbackView";
+import { WindowOptions } from "../../features/windows/windowsManager";
-/**
- * @typedef {object} windowProps
- * @property {App} app
- * @property {Function} setTitle
- * @property {Function} setIconUrl
- * @property {Function} close
- * @property {Function} focus
- * @property {boolean} active
- * @property {import("../../features/modals/modalsManager.js").default} modalsManager
- */
+export interface WindowProps extends WindowOptions {
+ fullscreen?: boolean;
+ onInteract?: Function
+ setTitle?: Function;
+ setIconUrl?: Function;
+ close?: Function;
+ focus?: Function;
+ active?: boolean;
+ minimized?: boolean;
+ toggleMinimized?: Function;
+ index?: number;
+}
-/**
- * @param {object} props
- * @param {string} props.id
- * @param {App} props.app
- * @param {Vector2} props.size
- * @param {Vector2} props.position
- * @param {boolean} props.focused
- * @param {Function} props.onInteract
- * @param {object} props.options
- * @param {boolean} props.active
- * @param {boolean} props.minimized
- * @param {Function} props.toggleMinimized
- */
-export const WindowView = memo(({ id, app, size, position, onInteract, options, active, fullscreen, minimized, toggleMinimized, index }) => {
+export const WindowView: FC = memo(({ id, app, size, position, onInteract, options, active, fullscreen, minimized, toggleMinimized, index }) => {
const windowsManager = useWindowsManager();
const nodeRef = useRef(null);
const { openWindowedModal } = useWindowedModal();
@@ -64,7 +53,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,
const { onContextMenu, ShortcutsListener } = useContextMenu({ Actions: (props) =>
-
+ { toggleMinimized(); }}/>
{
setMaximized(!maximized);
}}/>
@@ -117,7 +106,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,
};
}, [active, minimized, iconUrl, title]);
- const close = (event) => {
+ const close = (event?: Event) => {
event?.preventDefault();
windowsManager.close(id);
};
@@ -157,7 +146,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,
cancel="button"
nodeRef={nodeRef}
disabled={maximized}
- onStart={focus}
+ onStart={(event) => { focus(event); }}
grid={[1, 1]}
>
{title}
@@ -196,7 +185,7 @@ export const WindowView = memo(({ id, app, size, position, onInteract, options,
+ onClick={(event) => { close(event as unknown as Event); }}>
diff --git a/src/components/windows/WindowsView.jsx b/src/components/windows/WindowsView.tsx
similarity index 81%
rename from src/components/windows/WindowsView.jsx
rename to src/components/windows/WindowsView.tsx
index d6cb016..abbd3f5 100644
--- a/src/components/windows/WindowsView.jsx
+++ b/src/components/windows/WindowsView.tsx
@@ -1,23 +1,23 @@
import { useWindows } from "../../hooks/windows/windowsContext";
import { useWindowsManager } from "../../hooks/windows/windowsManagerContext";
-import { memo, useEffect, useState } from "react";
-import { WindowView } from "./WindowView.jsx";
+import { FC, memo, useEffect, useState } from "react";
+import { WindowProps, WindowView } from "./WindowView";
import { useSettingsManager } from "../../hooks/settings/settingsManagerContext";
import { SettingsManager } from "../../features/settings/settingsManager";
-import { NAME, TAG_LINE } from "../../config/branding.config.js";
-import { getViewportParams, setViewportIcon, setViewportTitle } from "../../features/_utils/browser.utils.js";
-import { removeDuplicatesFromArray } from "../../features/_utils/array.utils.js";
+import { NAME, TAG_LINE } from "../../config/branding.config";
+import { getViewportParams, setViewportIcon, setViewportTitle } from "../../features/_utils/browser.utils";
+import { removeDuplicatesFromArray } from "../../features/_utils/array.utils";
+import { WindowOptions } from "../../features/windows/windowsManager";
-export const WindowsView = memo(() => {
+export const WindowsView: FC = memo(() => {
const settingsManager = useSettingsManager();
const windows = useWindows();
const windowsManager = useWindowsManager();
- const [sortedWindows, setSortedWindows] = useState([]);
+ const [sortedWindows, setSortedWindows] = useState([]);
// Sort windows
useEffect(() => {
- setSortedWindows([...windows].sort((windowA, windowB) =>
- // @ts-ignore
+ setSortedWindows([...windows].sort((windowA: WindowOptions, windowB: WindowOptions) =>
windowA.lastInteraction - windowB.lastInteraction
));
}, [windows]);
@@ -65,7 +65,7 @@ export const WindowsView = memo(() => {
}, [settingsManager, windowsManager]);
return (
- {windows.map((window) => {
+ {windows.map((window: WindowProps) => {
const { id, app, size, position, options, minimized, fullscreen } = window;
const index = sortedWindows.indexOf(window);
return
array.indexOf(item) === index);
-}
\ No newline at end of file
diff --git a/src/features/_utils/array.utils.ts b/src/features/_utils/array.utils.ts
new file mode 100644
index 0000000..41a03ec
--- /dev/null
+++ b/src/features/_utils/array.utils.ts
@@ -0,0 +1,14 @@
+export function removeFromArray(item: any, array: any[]) {
+ const index = array.indexOf(item);
+ if (index !== -1) {
+ array.splice(index, 1);
+ }
+}
+
+export function randomFromArray(array: any[]): any {
+ return array[Math.floor(Math.random() * array.length)];
+}
+
+export function removeDuplicatesFromArray(array: any[]): any[] {
+ return array.filter((item, index) => array.indexOf(item) === index);
+}
\ No newline at end of file
diff --git a/src/features/_utils/browser.utils.js b/src/features/_utils/browser.utils.ts
similarity index 61%
rename from src/features/_utils/browser.utils.js
rename to src/features/_utils/browser.utils.ts
index 6a58f19..6ef637c 100644
--- a/src/features/_utils/browser.utils.js
+++ b/src/features/_utils/browser.utils.ts
@@ -1,10 +1,9 @@
-import { NAME } from "../../config/branding.config.js";
+import { NAME } from "../../config/branding.config";
/**
* Simulates closing the viewport by opening a blank page
- * @param {boolean} requireConfirmation
*/
-export function closeViewport(requireConfirmation = false) {
+export function closeViewport(requireConfirmation: boolean = false) {
if (requireConfirmation && window.confirm(`Are you sure you want to shut down ${NAME}?`)) {
console.info("Closing viewport");
window.open("about:blank", "_self");
@@ -13,18 +12,13 @@ export function closeViewport(requireConfirmation = false) {
/**
* Reloads the viewport
- * @param {boolean} bypassCache
*/
-export function reloadViewport(bypassCache = false) {
+export function reloadViewport() {
console.info("Reloading viewport");
- window.location.reload(bypassCache);
+ window.location.reload();
}
-/**
- * @param {string} string
- * @returns {boolean}
- */
-export function isValidUrl(string) {
+export function isValidUrl(string: string): boolean {
try {
new URL(string);
return true;
@@ -33,18 +27,12 @@ export function isValidUrl(string) {
}
}
-/**
- * @param {string} title
- */
-export function setViewportTitle(title) {
+export function setViewportTitle(title: string) {
document.title = title;
}
-/**
- * @param {string} url
- */
-export function setViewportIcon(url) {
- let link = document.querySelector("link[rel~='icon']");
+export function setViewportIcon(url: string) {
+ let link: HTMLLinkElement = document.querySelector("link[rel~='icon']");
if (!link) {
link = document.createElement("link");
link.rel = "icon";
@@ -53,10 +41,7 @@ export function setViewportIcon(url) {
link.href = url;
}
-/**
- * @returns {URLSearchParams}
- */
-export function getViewportParams() {
+export function getViewportParams(): Record {
const query = window.location.search.slice(1);
const params = {};
@@ -70,12 +55,7 @@ export function getViewportParams() {
return params;
}
-/**
- * @param {object} options
- * @param {string} options.appId
- * @param {boolean} options.fullscreen
- */
-export function generateUrl(options) {
+export function generateUrl(options: { appId: string; fullscreen: boolean; }) {
const baseUrl = window.location.origin + "/";
if (!options || Object.keys(options).length === 0)
@@ -92,7 +72,7 @@ export function generateUrl(options) {
if (extraOptions && Object.keys(extraOptions).length > 0) {
Object.entries(extraOptions).forEach(([key, value]) => {
if (key && value)
- params.set(key, encodeURIComponent(value));
+ params.set(key, encodeURIComponent(value as string));
});
}
@@ -103,11 +83,6 @@ export function generateUrl(options) {
return url;
}
-/**
- * @param {string} string
- * @param {Function} onSuccess
- * @param {Function} onFail
- */
-export function copyToClipboard(string, onSuccess, onFail) {
+export function copyToClipboard(string: string, onSuccess: (value: void) => void, onFail: (value: void) => void) {
navigator.clipboard.writeText(string).then(onSuccess, onFail);
}
\ No newline at end of file
diff --git a/src/features/_utils/date.utils.js b/src/features/_utils/date.utils.ts
similarity index 73%
rename from src/features/_utils/date.utils.js
rename to src/features/_utils/date.utils.ts
index 35d8f48..5941171 100644
--- a/src/features/_utils/date.utils.js
+++ b/src/features/_utils/date.utils.ts
@@ -11,12 +11,10 @@ const TIME_INDICATORS = {
/**
* Format a time
- * @param {number} time - Time in milliseconds
- * @param {number} maxLength - The maximum amount of units, e.g.: 3 => years, months, days
- * @param {boolean} allowAffixes
- * @returns {string}
+ * @param time - Time in milliseconds
+ * @param maxLength - The maximum amount of units, e.g.: 3 => years, months, days
*/
-export const formatTime = (time, maxLength = 3, allowAffixes) => {
+export function formatTime(time: number, maxLength: number = 3, allowAffixes: boolean): string {
const result = [];
const formatResult = (result, inPast) => {
@@ -83,12 +81,10 @@ export const formatTime = (time, maxLength = 3, allowAffixes) => {
/**
* Format a time relative to now
- * @param {Date} date - The date
- * @param {number} maxLength - The maximum amount of units, e.g.: 3 => years, months, days
- * @param {boolean} allowAffixes
- * @returns {string}
+ * @param date - The date
+ * @param maxLength - The maximum amount of units, e.g.: 3 => years, months, days
*/
-export const formatRelativeTime = (date, maxLength = 3, allowAffixes) => {
- const difference = date - new Date();
+export function formatRelativeTime(date: Date, maxLength: number = 3, allowAffixes: boolean): string {
+ const difference = date.valueOf() - Date.now();
return formatTime(difference, maxLength, allowAffixes);
};
\ No newline at end of file
diff --git a/src/features/_utils/event.utils.js b/src/features/_utils/event.utils.js
deleted file mode 100644
index 19be6e8..0000000
--- a/src/features/_utils/event.utils.js
+++ /dev/null
@@ -1,49 +0,0 @@
-export class EventEmitter {
- /**
- * @type {Object}
- */
- static EVENT_NAMES = {};
-
- /**
- * @type {Object>}
- */
- #events = {};
-
- /**
- * Add event listener for an event
- * @param {EventEmitter.EVENT_NAMES} eventName
- * @param {Function} callback
- */
- on(eventName, callback) {
- if (!this.#events[eventName]) {
- this.#events[eventName] = [];
- }
- this.#events[eventName].push(callback);
- }
-
- /**
- * Remove event listener for an event
- * @param {string} eventName
- * @param {Function} callback
- */
- off(eventName, callback) {
- if (this.#events[eventName]) {
- this.#events[eventName] = this.#events[eventName].filter(
- (listener) => listener !== callback
- );
- }
- }
-
- /**
- * Dispatch event
- * @param {string} eventName
- * @param {*} data
- */
- emit(eventName, data) {
- if (this.#events[eventName]) {
- this.#events[eventName].forEach((listener) => {
- listener(data);
- });
- }
- }
-}
\ No newline at end of file
diff --git a/src/features/_utils/event.utils.ts b/src/features/_utils/event.utils.ts
new file mode 100644
index 0000000..d64828e
--- /dev/null
+++ b/src/features/_utils/event.utils.ts
@@ -0,0 +1,39 @@
+export type EventNamesMap = Record;
+
+export class EventEmitter {
+ static EVENT_NAMES: EventNamesMap = {};
+
+ #events: Record> = {};
+
+ /**
+ * Add event listener for an event
+ */
+ on(eventName: Key, callback: (data: any) => void) {
+ if (!this.#events[eventName as string]) {
+ this.#events[eventName as string] = [];
+ }
+ this.#events[eventName as string].push(callback);
+ }
+
+ /**
+ * Remove event listener for an event
+ */
+ off(eventName: Key, callback: (data: any) => void) {
+ if (this.#events[eventName as string]) {
+ this.#events[eventName as string] = this.#events[eventName as string].filter(
+ (listener) => listener !== callback
+ );
+ }
+ }
+
+ /**
+ * Dispatch event
+ */
+ emit(eventName: Key, data?: any) {
+ if (this.#events[eventName as string]) {
+ this.#events[eventName as string].forEach((listener) => {
+ listener(data);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/features/_utils/number.utils.js b/src/features/_utils/number.utils.js
deleted file mode 100644
index b2015fb..0000000
--- a/src/features/_utils/number.utils.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export function isValidInteger(number) {
- return (parseInt(number) || parseInt(number) === 0);
-}
\ No newline at end of file
diff --git a/src/features/_utils/number.utils.ts b/src/features/_utils/number.utils.ts
new file mode 100644
index 0000000..cf1bea7
--- /dev/null
+++ b/src/features/_utils/number.utils.ts
@@ -0,0 +1,3 @@
+export function isValidInteger(number: number | string): number| boolean {
+ return (typeof number === "number" || parseInt(number) || parseInt(number) === 0);
+}
\ No newline at end of file
diff --git a/src/features/_utils/string.utils.js b/src/features/_utils/string.utils.ts
similarity index 83%
rename from src/features/_utils/string.utils.js
rename to src/features/_utils/string.utils.ts
index 007c02d..40a4265 100644
--- a/src/features/_utils/string.utils.js
+++ b/src/features/_utils/string.utils.ts
@@ -1,8 +1,4 @@
-/**
- * @param {string[]} shortcut
- * @returns {string}
- */
-export function formatShortcut(shortcut) {
+export function formatShortcut(shortcut: string[]): string {
const specialKeys = [];
const singleKeys = [];
diff --git a/src/features/apps/app.js b/src/features/apps/app.js
deleted file mode 100644
index b1fc8ae..0000000
--- a/src/features/apps/app.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "react";
-
-export default class App {
- /**
- * @param {string} name
- * @param {string} id
- * @param {React.ReactElement} windowContent
- * @param {object | null} windowOptions - Default window options
- */
- constructor(name, id, windowContent, windowOptions) {
- Object.assign(this, { name, id, windowContent, windowOptions });
-
- if (this.windowContent == null)
- console.warn(`App (${this.id}) is missing the windowContent property.`);
- }
-
- WindowContent = (props) => {
- props = { ...props, ...this.windowOptions };
-
- if (this.windowContent == null) {
- return null;
- }
-
- return ;
- };
-}
\ No newline at end of file
diff --git a/src/features/apps/app.tsx b/src/features/apps/app.tsx
new file mode 100644
index 0000000..2de2c52
--- /dev/null
+++ b/src/features/apps/app.tsx
@@ -0,0 +1,33 @@
+import React from "react";
+import Vector2 from "../math/vector2";
+import { WindowProps } from "../../components/windows/WindowView";
+
+export default class App {
+ name: string;
+ id: string;
+ windowContent: React.FC;
+ windowOptions?: {
+ size: Vector2
+ };
+ isActive: boolean = false;
+
+ /**
+ * @param windowOptions - Default window options
+ */
+ constructor(name: string, id: string, windowContent: React.FC, windowOptions?: object | null) {
+ Object.assign(this, { name, id, windowContent, windowOptions });
+
+ if (this.windowContent == null)
+ console.warn(`App (${this.id}) is missing the windowContent property.`);
+ }
+
+ WindowContent = (props: React.JSX.IntrinsicAttributes & WindowProps) => {
+ props = { ...props, ...this.windowOptions };
+
+ if (this.windowContent == null) {
+ return null;
+ }
+
+ return ;
+ };
+}
\ No newline at end of file
diff --git a/src/features/apps/appsManager.js b/src/features/apps/appsManager.ts
similarity index 76%
rename from src/features/apps/appsManager.js
rename to src/features/apps/appsManager.ts
index e24397e..65089be 100644
--- a/src/features/apps/appsManager.js
+++ b/src/features/apps/appsManager.ts
@@ -1,23 +1,21 @@
-import App from "./app.js";
-import { FileExplorer } from "../../components/apps/file-explorer/FileExplorer.jsx";
-import { MediaViewer } from "../../components/apps/media-viewer/MediaViewer.jsx";
-import { WebView } from "../../components/apps/_utils/web-view/WebView.jsx";
-import { Terminal } from "../../components/apps/terminal/Terminal.jsx";
-import { TextEditor } from "../../components/apps/text-editor/TextEditor.jsx";
-import { Settings } from "../../components/apps/settings/Settings.jsx";
-import { Calculator } from "../../components/apps/calculator/Calculator.jsx";
-import Vector2 from "../math/vector2.js";
-import { APPS, APP_NAMES } from "../../config/apps.config.js";
-import { Browser } from "../../components/apps/browser/Browser.jsx";
-import { IMAGE_FORMATS } from "../../config/apps/mediaViewer.config.js";
+import App from "./app";
+import { FileExplorer } from "../../components/apps/file-explorer/FileExplorer";
+import { MediaViewer } from "../../components/apps/media-viewer/MediaViewer";
+import { WebView } from "../../components/apps/_utils/web-view/WebView";
+import { Terminal } from "../../components/apps/terminal/Terminal";
+import { TextEditor } from "../../components/apps/text-editor/TextEditor";
+import { Settings } from "../../components/apps/settings/Settings";
+import { Calculator } from "../../components/apps/calculator/Calculator";
+import Vector2 from "../math/vector2";
+import { APPS, APP_NAMES } from "../../config/apps.config";
+import { Browser } from "../../components/apps/browser/Browser";
+import { IMAGE_FORMATS } from "../../config/apps/mediaViewer.config";
export default class AppsManager {
- /** @type {App[]} */
- static APPS = [
+ static APPS: App[] = [
new App(APP_NAMES.TERMINAL, APPS.TERMINAL, Terminal),
new App(APP_NAMES.SETTINGS, APPS.SETTINGS, Settings),
new App(APP_NAMES.MEDIA_VIEWER, APPS.MEDIA_VIEWER, MediaViewer),
- // new App("Browser", "browser"),
new App(APP_NAMES.CALCULATOR, APPS.CALCULATOR, Calculator, { size: new Vector2(400, 600) }),
new App(APP_NAMES.TEXT_EDITOR, APPS.TEXT_EDITOR, TextEditor),
// new App("Code Editor", "code-editor"),
@@ -39,11 +37,7 @@ export default class AppsManager {
}),
];
- /**
- * @param {string} id
- * @returns {App | null}
- */
- static getAppById(id) {
+ static getAppById(id: string): App | null {
let application = null;
this.APPS.forEach((app) => {
@@ -58,10 +52,8 @@ export default class AppsManager {
/**
* Get the app associated with a file extension
- * @param {string} fileExtension
- * @returns {App}
*/
- static getAppByFileExtension(fileExtension) {
+ static getAppByFileExtension(fileExtension: string): App {
let app = null;
if (IMAGE_FORMATS.includes(fileExtension))
@@ -78,11 +70,8 @@ export default class AppsManager {
/**
* 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) {
+ static getAppIconUrl(appId: string, iconName?: string): string {
if (iconName == null) {
return `${process.env.PUBLIC_URL}/assets/apps/icons/${appId}.svg`;
} else {
diff --git a/src/features/apps/terminal/_utils/terminal.utils.js b/src/features/apps/terminal/_utils/terminal.utils.js
deleted file mode 100644
index 24f2307..0000000
--- a/src/features/apps/terminal/_utils/terminal.utils.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-
-/**
- * @param {string} commandName
- * @param {string} error
- * @returns {string}
- */
-export function formatError(commandName, error) {
- return `${ANSI.fg.red}${commandName}: ${error}${ANSI.reset}`;
-}
-
-/**
- * @param {string} string
- * @returns {string}
- */
-export function removeAnsi(string) {
- // eslint-disable-next-line no-control-regex
- return string.replace(/\u001b\[([0-9]+)m/gm, "");
-}
\ No newline at end of file
diff --git a/src/features/apps/terminal/_utils/terminal.utils.ts b/src/features/apps/terminal/_utils/terminal.utils.ts
new file mode 100644
index 0000000..20b0990
--- /dev/null
+++ b/src/features/apps/terminal/_utils/terminal.utils.ts
@@ -0,0 +1,10 @@
+import { ANSI } from "../../../../config/apps/terminal.config";
+
+export function formatError(commandName: string, error: string): string {
+ return `${ANSI.fg.red}${commandName}: ${error}${ANSI.reset}`;
+}
+
+export function removeAnsi(string: string): string {
+ // eslint-disable-next-line no-control-regex
+ return string.replace(/\u001b\[([0-9]+)m/gm, "");
+}
\ No newline at end of file
diff --git a/src/features/apps/terminal/command.ts b/src/features/apps/terminal/command.ts
index 407ffd3..3f391be 100644
--- a/src/features/apps/terminal/command.ts
+++ b/src/features/apps/terminal/command.ts
@@ -1,5 +1,6 @@
-import { VirtualFolder } from "../../virtual-drive/folder/virtualFolder.js";
-import { VirtualRoot } from "../../virtual-drive/root/virtualRoot.js";
+import { VirtualFolder } from "../../virtual-drive/folder/virtualFolder";
+import { VirtualRoot } from "../../virtual-drive/root/virtualRoot";
+import Stream from "./stream";
type Option = {
long: string,
@@ -7,19 +8,20 @@ type Option = {
isInput: boolean
};
-type Execute = (args: string[], options: {
- promptOutput: void,
- pushHistory: void,
- virtualRoot: VirtualRoot,
- currentDirectory: VirtualFolder,
- setCurrentDirectory: void,
- username: string,
- hostname: string,
- rawInputValue: string,
- options: string[],
- exit: void,
- inputs: string[]
-}) => string | { blank: boolean } | void;
+type Execute = (args?: string[], options?: {
+ promptOutput?: Function,
+ pushHistory?: Function,
+ virtualRoot?: VirtualRoot,
+ currentDirectory?: VirtualFolder,
+ setCurrentDirectory?: Function,
+ username?: string,
+ hostname?: string,
+ rawInputValue?: string,
+ options?: string[],
+ exit?: Function,
+ inputs?: Record;
+ timestamp: number,
+}) => string | { blank: boolean } | void | Stream;
type Manual = {
purpose?: string,
diff --git a/src/features/apps/terminal/commands.js b/src/features/apps/terminal/commands.ts
similarity index 78%
rename from src/features/apps/terminal/commands.js
rename to src/features/apps/terminal/commands.ts
index 5ad0645..4bd0747 100644
--- a/src/features/apps/terminal/commands.js
+++ b/src/features/apps/terminal/commands.ts
@@ -7,7 +7,7 @@ let commands = [];
*/
const loadCommands = () => {
commands = [];
- const context = require.context("./commands", false, /\.js$/);
+ const context = require.context("./commands", false, /\.ts$/);
context.keys().forEach((key) => {
const commandModule = context(key);
const commandName = Object.keys(commandModule)[0];
@@ -24,11 +24,7 @@ loadCommands();
export default class CommandsManager {
static COMMANDS = commands;
- /**
- * @param {string} name
- * @returns {Command}
- */
- static find(name) {
+ static find(name: string): Command {
let matchCommand = null;
this.COMMANDS.forEach((command) => {
@@ -41,11 +37,7 @@ export default class CommandsManager {
return matchCommand;
}
- /**
- * @param {string} pattern
- * @returns {Command[]}
- */
- static search(pattern) {
+ static search(pattern: string): Command[] {
const matches = this.COMMANDS.filter((command) => command.name.match(pattern));
return matches;
}
diff --git a/src/features/apps/terminal/commands/cat.js b/src/features/apps/terminal/commands/cat.ts
similarity index 92%
rename from src/features/apps/terminal/commands/cat.js
rename to src/features/apps/terminal/commands/cat.ts
index 6e9740f..7d9ef67 100644
--- a/src/features/apps/terminal/commands/cat.js
+++ b/src/features/apps/terminal/commands/cat.ts
@@ -1,5 +1,5 @@
-import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { VirtualFile } from "../../../virtual-drive/file/virtualFile";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const cat = new Command()
diff --git a/src/features/apps/terminal/commands/cd.js b/src/features/apps/terminal/commands/cd.ts
similarity index 90%
rename from src/features/apps/terminal/commands/cd.js
rename to src/features/apps/terminal/commands/cd.ts
index 2953e3a..a5d6be3 100644
--- a/src/features/apps/terminal/commands/cd.js
+++ b/src/features/apps/terminal/commands/cd.ts
@@ -1,4 +1,4 @@
-import { formatError } from "../_utils/terminal.utils.js";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const cd = new Command()
diff --git a/src/features/apps/terminal/commands/clear.js b/src/features/apps/terminal/commands/clear.ts
similarity index 100%
rename from src/features/apps/terminal/commands/clear.js
rename to src/features/apps/terminal/commands/clear.ts
diff --git a/src/features/apps/terminal/commands/compgen.js b/src/features/apps/terminal/commands/compgen.ts
similarity index 87%
rename from src/features/apps/terminal/commands/compgen.js
rename to src/features/apps/terminal/commands/compgen.ts
index d1d95e8..f6a952e 100644
--- a/src/features/apps/terminal/commands/compgen.js
+++ b/src/features/apps/terminal/commands/compgen.ts
@@ -1,5 +1,5 @@
import Command from "../command";
-import CommandsManager from "../commands.js";
+import CommandsManager from "../commands";
export const compgen = new Command()
.setManual({
diff --git a/src/features/apps/terminal/commands/cowsay.js b/src/features/apps/terminal/commands/cowsay.ts
similarity index 98%
rename from src/features/apps/terminal/commands/cowsay.js
rename to src/features/apps/terminal/commands/cowsay.ts
index 62ed609..00a7fae 100644
--- a/src/features/apps/terminal/commands/cowsay.js
+++ b/src/features/apps/terminal/commands/cowsay.ts
@@ -1,4 +1,4 @@
-import { MAX_WIDTH } from "../../../../config/apps/terminal.config.js";
+import { MAX_WIDTH } from "../../../../config/apps/terminal.config";
import Command from "../command";
const COW = `
@@ -29,7 +29,7 @@ export const cowsay = new Command()
maxLineWidth = line.length;
};
- const nextLine = (word) => {
+ const nextLine = (word?: string) => {
addLine(currentLine);
if (word) {
diff --git a/src/features/apps/terminal/commands/dir.js b/src/features/apps/terminal/commands/dir.ts
similarity index 100%
rename from src/features/apps/terminal/commands/dir.js
rename to src/features/apps/terminal/commands/dir.ts
diff --git a/src/features/apps/terminal/commands/echo.js b/src/features/apps/terminal/commands/echo.ts
similarity index 100%
rename from src/features/apps/terminal/commands/echo.js
rename to src/features/apps/terminal/commands/echo.ts
diff --git a/src/features/apps/terminal/commands/exit.js b/src/features/apps/terminal/commands/exit.ts
similarity index 100%
rename from src/features/apps/terminal/commands/exit.js
rename to src/features/apps/terminal/commands/exit.ts
diff --git a/src/features/apps/terminal/commands/fortune.js b/src/features/apps/terminal/commands/fortune.ts
similarity index 97%
rename from src/features/apps/terminal/commands/fortune.js
rename to src/features/apps/terminal/commands/fortune.ts
index 25927a3..96dd98e 100644
--- a/src/features/apps/terminal/commands/fortune.js
+++ b/src/features/apps/terminal/commands/fortune.ts
@@ -1,4 +1,4 @@
-import { randomFromArray } from "../../../_utils/array.utils.js";
+import { randomFromArray } from "../../../_utils/array.utils";
import Command from "../command";
/**
diff --git a/src/features/apps/terminal/commands/help.js b/src/features/apps/terminal/commands/help.ts
similarity index 80%
rename from src/features/apps/terminal/commands/help.js
rename to src/features/apps/terminal/commands/help.ts
index f7a16b9..bbfa046 100644
--- a/src/features/apps/terminal/commands/help.js
+++ b/src/features/apps/terminal/commands/help.ts
@@ -1,7 +1,7 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
-import CommandsManager from "../commands.js";
+import CommandsManager from "../commands";
export const help = new Command()
.setExecute(function(args) {
diff --git a/src/features/apps/terminal/commands/hostname.js b/src/features/apps/terminal/commands/hostname.ts
similarity index 100%
rename from src/features/apps/terminal/commands/hostname.js
rename to src/features/apps/terminal/commands/hostname.ts
diff --git a/src/features/apps/terminal/commands/lolcat.js b/src/features/apps/terminal/commands/lolcat.ts
similarity index 90%
rename from src/features/apps/terminal/commands/lolcat.js
rename to src/features/apps/terminal/commands/lolcat.ts
index 37e1d8f..01aeec6 100644
--- a/src/features/apps/terminal/commands/lolcat.js
+++ b/src/features/apps/terminal/commands/lolcat.ts
@@ -1,5 +1,5 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { removeAnsi } from "../_utils/terminal.utils.js";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { removeAnsi } from "../_utils/terminal.utils";
import Command from "../command";
const COLUMN_WIDTH = 5;
diff --git a/src/features/apps/terminal/commands/ls.js b/src/features/apps/terminal/commands/ls.ts
similarity index 75%
rename from src/features/apps/terminal/commands/ls.js
rename to src/features/apps/terminal/commands/ls.ts
index 9423fec..2b76c49 100644
--- a/src/features/apps/terminal/commands/ls.js
+++ b/src/features/apps/terminal/commands/ls.ts
@@ -1,5 +1,6 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { VirtualFolder } from "../../../virtual-drive/folder/virtualFolder";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const ls = new Command()
@@ -12,7 +13,7 @@ export const ls = new Command()
let directory = currentDirectory;
if (args.length > 0) {
- directory = currentDirectory.navigate(args[0]);
+ directory = currentDirectory.navigate(args[0]) as VirtualFolder;
}
if (!directory)
diff --git a/src/features/apps/terminal/commands/make.js b/src/features/apps/terminal/commands/make.ts
similarity index 79%
rename from src/features/apps/terminal/commands/make.js
rename to src/features/apps/terminal/commands/make.ts
index ad0006e..4c846c9 100644
--- a/src/features/apps/terminal/commands/make.js
+++ b/src/features/apps/terminal/commands/make.ts
@@ -1,4 +1,4 @@
-import { formatError } from "../_utils/terminal.utils.js";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const make = new Command()
diff --git a/src/features/apps/terminal/commands/man.js b/src/features/apps/terminal/commands/man.ts
similarity index 92%
rename from src/features/apps/terminal/commands/man.js
rename to src/features/apps/terminal/commands/man.ts
index 47ab52d..cc26503 100644
--- a/src/features/apps/terminal/commands/man.js
+++ b/src/features/apps/terminal/commands/man.ts
@@ -1,7 +1,7 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
-import CommandsManager from "../commands.js";
+import CommandsManager from "../commands";
const MARGIN = 5;
diff --git a/src/features/apps/terminal/commands/mkdir.js b/src/features/apps/terminal/commands/mkdir.ts
similarity index 100%
rename from src/features/apps/terminal/commands/mkdir.js
rename to src/features/apps/terminal/commands/mkdir.ts
diff --git a/src/features/apps/terminal/commands/neofetch.js b/src/features/apps/terminal/commands/neofetch.ts
similarity index 88%
rename from src/features/apps/terminal/commands/neofetch.js
rename to src/features/apps/terminal/commands/neofetch.ts
index 5a2bf7b..1337fdc 100644
--- a/src/features/apps/terminal/commands/neofetch.js
+++ b/src/features/apps/terminal/commands/neofetch.ts
@@ -1,9 +1,9 @@
-import { APPS } from "../../../../config/apps.config.js";
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { ANSI_ASCII_LOGO, ANSI_LOGO_COLOR, NAME } from "../../../../config/branding.config.js";
+import { APPS } from "../../../../config/apps.config";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { ANSI_ASCII_LOGO, ANSI_LOGO_COLOR, NAME } from "../../../../config/branding.config";
import { START_DATE } from "../../../../index";
-import { formatRelativeTime } from "../../../_utils/date.utils.js";
-import AppsManager from "../../appsManager.js";
+import { formatRelativeTime } from "../../../_utils/date.utils";
+import AppsManager from "../../appsManager";
import Command from "../command";
export const neofetch = new Command()
diff --git a/src/features/apps/terminal/commands/pwd.js b/src/features/apps/terminal/commands/pwd.ts
similarity index 100%
rename from src/features/apps/terminal/commands/pwd.js
rename to src/features/apps/terminal/commands/pwd.ts
diff --git a/src/features/apps/terminal/commands/reboot.js b/src/features/apps/terminal/commands/reboot.ts
similarity index 74%
rename from src/features/apps/terminal/commands/reboot.js
rename to src/features/apps/terminal/commands/reboot.ts
index 60b508a..75e2cd8 100644
--- a/src/features/apps/terminal/commands/reboot.js
+++ b/src/features/apps/terminal/commands/reboot.ts
@@ -1,4 +1,4 @@
-import { reloadViewport } from "../../../_utils/browser.utils.js";
+import { reloadViewport } from "../../../_utils/browser.utils";
import Command from "../command";
export const reboot = new Command()
diff --git a/src/features/apps/terminal/commands/reload.js b/src/features/apps/terminal/commands/reload.ts
similarity index 81%
rename from src/features/apps/terminal/commands/reload.js
rename to src/features/apps/terminal/commands/reload.ts
index ddb1788..1217b98 100644
--- a/src/features/apps/terminal/commands/reload.js
+++ b/src/features/apps/terminal/commands/reload.ts
@@ -1,5 +1,5 @@
import Command from "../command";
-import CommandsManager from "../commands.js";
+import CommandsManager from "../commands";
export const reload = new Command()
.setManual({
diff --git a/src/features/apps/terminal/commands/rev.js b/src/features/apps/terminal/commands/rev.ts
similarity index 100%
rename from src/features/apps/terminal/commands/rev.js
rename to src/features/apps/terminal/commands/rev.ts
diff --git a/src/features/apps/terminal/commands/rm.js b/src/features/apps/terminal/commands/rm.ts
similarity index 87%
rename from src/features/apps/terminal/commands/rm.js
rename to src/features/apps/terminal/commands/rm.ts
index 2eb2518..e20a0a0 100644
--- a/src/features/apps/terminal/commands/rm.js
+++ b/src/features/apps/terminal/commands/rm.ts
@@ -1,5 +1,5 @@
-import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { VirtualFile } from "../../../virtual-drive/file/virtualFile";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const rm = new Command()
diff --git a/src/features/apps/terminal/commands/rmdir.js b/src/features/apps/terminal/commands/rmdir.ts
similarity index 87%
rename from src/features/apps/terminal/commands/rmdir.js
rename to src/features/apps/terminal/commands/rmdir.ts
index 49c6f56..9753cfe 100644
--- a/src/features/apps/terminal/commands/rmdir.js
+++ b/src/features/apps/terminal/commands/rmdir.ts
@@ -1,4 +1,4 @@
-import { formatError } from "../_utils/terminal.utils.js";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const rmdir = new Command()
diff --git a/src/features/apps/terminal/commands/sl.js b/src/features/apps/terminal/commands/sl.ts
similarity index 97%
rename from src/features/apps/terminal/commands/sl.js
rename to src/features/apps/terminal/commands/sl.ts
index 6fe7ee0..14e2c0c 100644
--- a/src/features/apps/terminal/commands/sl.js
+++ b/src/features/apps/terminal/commands/sl.ts
@@ -1,6 +1,6 @@
-import { formatError } from "../_utils/terminal.utils.js";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
-import Stream from "../stream.js";
+import Stream from "../stream";
const ANIMATION_SPEED = 1.25;
@@ -209,7 +209,7 @@ export const sl = new Command()
stream.stop();
}, 100 / ANIMATION_SPEED);
- stream.on(Stream.EVENT_NAMES.STOP, () => {
+ stream.on(Stream.EVENT_NAMES.stop, () => {
clearInterval(interval);
});
diff --git a/src/features/apps/terminal/commands/touch.js b/src/features/apps/terminal/commands/touch.ts
similarity index 92%
rename from src/features/apps/terminal/commands/touch.js
rename to src/features/apps/terminal/commands/touch.ts
index b527b38..aed077e 100644
--- a/src/features/apps/terminal/commands/touch.js
+++ b/src/features/apps/terminal/commands/touch.ts
@@ -1,5 +1,5 @@
-import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { VirtualFile } from "../../../virtual-drive/file/virtualFile";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
export const touch = new Command()
diff --git a/src/features/apps/terminal/commands/uptime.js b/src/features/apps/terminal/commands/uptime.ts
similarity index 80%
rename from src/features/apps/terminal/commands/uptime.js
rename to src/features/apps/terminal/commands/uptime.ts
index a753e23..4e7cee5 100644
--- a/src/features/apps/terminal/commands/uptime.js
+++ b/src/features/apps/terminal/commands/uptime.ts
@@ -1,5 +1,5 @@
import { START_DATE } from "../../../../index";
-import { formatRelativeTime } from "../../../_utils/date.utils.js";
+import { formatRelativeTime } from "../../../_utils/date.utils";
import Command from "../command";
diff --git a/src/features/apps/terminal/commands/whatis.js b/src/features/apps/terminal/commands/whatis.ts
similarity index 76%
rename from src/features/apps/terminal/commands/whatis.js
rename to src/features/apps/terminal/commands/whatis.ts
index d313693..0e3a895 100644
--- a/src/features/apps/terminal/commands/whatis.js
+++ b/src/features/apps/terminal/commands/whatis.ts
@@ -1,7 +1,7 @@
-import { ANSI } from "../../../../config/apps/terminal.config.js";
-import { formatError } from "../_utils/terminal.utils.js";
+import { ANSI } from "../../../../config/apps/terminal.config";
+import { formatError } from "../_utils/terminal.utils";
import Command from "../command";
-import CommandsManager from "../commands.js";
+import CommandsManager from "../commands";
export const whatis = new Command()
.setRequireArgs(true)
diff --git a/src/features/apps/terminal/commands/whoami.js b/src/features/apps/terminal/commands/whoami.ts
similarity index 100%
rename from src/features/apps/terminal/commands/whoami.js
rename to src/features/apps/terminal/commands/whoami.ts
diff --git a/src/features/apps/terminal/stream.js b/src/features/apps/terminal/stream.js
deleted file mode 100644
index 3902dc1..0000000
--- a/src/features/apps/terminal/stream.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { EventEmitter } from "../../_utils/event.utils.js";
-
-export default class Stream extends EventEmitter {
- static EVENT_NAMES = {
- NEW: "new",
- START: "start",
- STOP: "stop",
- };
-
- enabled = false;
-
- /**
- * @param {Function} callback
- * @returns {Stream}
- */
- start(callback) {
- if (this.enabled)
- return;
-
- callback?.(this);
- this.enabled = true;
- this.emit(Stream.EVENT_NAMES.START);
- return this;
- }
-
- /**
- * @returns {Stream}
- */
- stop() {
- if (!this.enabled)
- return;
-
- this.enabled = false;
- this.emit(Stream.EVENT_NAMES.STOP);
- return this;
- }
-
- /**
- * @param {string} text
- * @returns {Stream}
- */
- send(text) {
- if (this.enabled)
- this.emit(Stream.EVENT_NAMES.NEW, text);
- return this;
- }
-}
\ No newline at end of file
diff --git a/src/features/apps/terminal/stream.ts b/src/features/apps/terminal/stream.ts
new file mode 100644
index 0000000..2ee3cf1
--- /dev/null
+++ b/src/features/apps/terminal/stream.ts
@@ -0,0 +1,38 @@
+import { EventEmitter } from "../../_utils/event.utils";
+
+const StreamEvents = {
+ new: "new",
+ start: "start",
+ stop: "stop",
+} as const;
+
+export default class Stream extends EventEmitter {
+ static EVENT_NAMES = StreamEvents;
+
+ enabled: boolean = false;
+
+ start(callback?: Function): Stream {
+ if (this.enabled)
+ return;
+
+ callback?.(this);
+ this.enabled = true;
+ this.emit("start");
+ return this;
+ }
+
+ stop(): Stream {
+ if (!this.enabled)
+ return;
+
+ this.enabled = false;
+ this.emit("stop");
+ return this;
+ }
+
+ send(text: string): Stream {
+ if (this.enabled)
+ this.emit("new", text);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/src/features/math/clamp.js b/src/features/math/clamp.js
deleted file mode 100644
index f50371a..0000000
--- a/src/features/math/clamp.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * @param {number} value
- * @param {number} min
- * @param {number} max
- * @returns {number}
- */
-export function clamp(value, min, max) {
- if (value < min) {
- return min;
- } else if (value > max) {
- return max;
- } else {
- return value;
- }
-}
\ No newline at end of file
diff --git a/src/features/math/clamp.ts b/src/features/math/clamp.ts
new file mode 100644
index 0000000..6c14d58
--- /dev/null
+++ b/src/features/math/clamp.ts
@@ -0,0 +1,9 @@
+export function clamp(value: number, min: number, max: number): number {
+ if (value < min) {
+ return min;
+ } else if (value > max) {
+ return max;
+ } else {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/features/math/random.js b/src/features/math/random.js
deleted file mode 100644
index 5634ddb..0000000
--- a/src/features/math/random.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * @param {number} min
- * @param {number} max
- * @returns {number}
- */
-export function randomRange(min, max) {
- return Math.random() * (max - min) + min;
-}
\ No newline at end of file
diff --git a/src/features/math/random.ts b/src/features/math/random.ts
new file mode 100644
index 0000000..abc953e
--- /dev/null
+++ b/src/features/math/random.ts
@@ -0,0 +1,3 @@
+export function randomRange(min: number, max: number): number {
+ return Math.random() * (max - min) + min;
+}
\ No newline at end of file
diff --git a/src/features/math/round.js b/src/features/math/round.js
deleted file mode 100644
index 1daf692..0000000
--- a/src/features/math/round.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @param {number} value
- * @param {number} precision
- * @returns {number}
- */
-export function round(value, precision) {
- const multiplier = Math.pow(10, precision || 0);
- return Math.round(value * multiplier) / multiplier;
-}
\ No newline at end of file
diff --git a/src/features/math/round.ts b/src/features/math/round.ts
new file mode 100644
index 0000000..8c79d8d
--- /dev/null
+++ b/src/features/math/round.ts
@@ -0,0 +1,4 @@
+export function round(value: number, precision: number): number {
+ const multiplier = Math.pow(10, precision || 0);
+ return Math.round(value * multiplier) / multiplier;
+}
\ No newline at end of file
diff --git a/src/features/math/vector2.js b/src/features/math/vector2.ts
similarity index 69%
rename from src/features/math/vector2.js
rename to src/features/math/vector2.ts
index 402667c..2b896cd 100644
--- a/src/features/math/vector2.js
+++ b/src/features/math/vector2.ts
@@ -1,15 +1,15 @@
export default class Vector2 {
+ x: number;
+ y: number;
+
static ZERO = new Vector2(0, 0);
- constructor(x, y) {
+ constructor(x: number, y: number) {
this.x = x;
this.y = y ?? x;
}
- /**
- * @returns {Vector2}
- */
- round() {
+ round(): Vector2 {
this.x = Math.round(this.x);
this.y = Math.round(this.y);
return this;
diff --git a/src/features/modals/modal.js b/src/features/modals/modal.js
deleted file mode 100644
index 21ee71b..0000000
--- a/src/features/modals/modal.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import Vector2 from "../math/vector2.js";
-import ModalsManager from "./modalsManager.js";
-
-export default class Modal {
- /** @type {Vector2} */
- size = new Vector2(400, 200);
- /** @type {Vector2} */
- position = new Vector2(300, 300);
- /** @type {string | null} */
- icon = null;
- /** @type {title | null} */
- title = null;
- /** @type {ModalsManager} */
- modalsManager = null;
- /** @type {import("react").ReactElement | null} */
- element = null;
- /** @type {object} */
- props = {};
- /** @type {Function | null} */
- callback = null;
- /** @type {number | null} */
- id = null;
- /** @type {boolean} */
- dismissible = true;
-
- /**
- * @param {import("react").ReactElement} element
- * @param {Function} callback
- */
- constructor(element, callback) {
- this.element = element;
- this.callback = callback;
- this.focus();
- }
-
- /**
- * @param {string} icon
- * @returns {Modal}
- */
- setIcon(icon) {
- this.icon = icon;
- return this;
- }
-
- /**
- * @param {string} title
- * @returns {Modal}
- */
- setTitle(title) {
- this.title = title;
- return this;
- }
-
- /**
- * @param {Vector2} position
- * @returns {Modal}
- */
- setPosition(position) {
- this.position = position;
- return this;
- }
-
- /**
- * @param {Vector2} size
- * @returns {Modal}
- */
- setSize(size) {
- this.size = size;
- return this;
- }
-
- /**
- * @param {object} props
- * @returns {Modal}
- */
- setProps(props) {
- this.props = props;
- return this;
- }
-
- /**
- * @param {boolean} dismissible
- * @returns {Modal}
- */
- setDismissible(dismissible) {
- this.dismissible = dismissible;
- return this;
- }
-
- focus() {
- this.lastInteraction = new Date().valueOf();
- }
-
- /**
- * @param {...any} args
- */
- finish(...args) {
- if (this.modalsManager == null || this.id == null)
- return;
-
- this.modalsManager.close(this.id);
- this.callback?.(...args);
- }
-
- close() {
- this.finish();
- }
-}
\ No newline at end of file
diff --git a/src/features/modals/modal.ts b/src/features/modals/modal.ts
new file mode 100644
index 0000000..f8fe701
--- /dev/null
+++ b/src/features/modals/modal.ts
@@ -0,0 +1,74 @@
+import { FC } from "react";
+import Vector2 from "../math/vector2";
+import ModalsManager from "./modalsManager";
+import { ModalProps } from "../../components/modals/ModalView";
+
+export default class Modal {
+ size: Vector2 = new Vector2(400, 200);
+ position: Vector2 = new Vector2(300, 300);
+ icon: string | null = null;
+ title: string | null = null;
+ modalsManager: ModalsManager = null;
+ element: FC | null = null;
+ props: object = {};
+ callback: Function | null = null;
+ id: number | null = null;
+ dismissible: boolean = true;
+ lastInteraction: number;
+
+ constructor(element: FC, callback?: Function) {
+ this.element = element;
+ this.callback = callback;
+ this.focus();
+ }
+
+ setIcon(icon: string): Modal {
+ this.icon = icon;
+ return this;
+ }
+
+ setTitle(title: string): Modal {
+ this.title = title;
+ return this;
+ }
+
+ setPosition(position: Vector2): Modal {
+ this.position = position;
+ return this;
+ }
+
+ setSize(size: Vector2): Modal {
+ this.size = size;
+ return this;
+ }
+
+ setProps(props: object): Modal {
+ this.props = props;
+ return this;
+ }
+
+ /**
+ * @param {boolean} dismissible
+ * @returns {Modal}
+ */
+ setDismissible(dismissible: boolean): Modal {
+ this.dismissible = dismissible;
+ return this;
+ }
+
+ focus() {
+ this.lastInteraction = Date.now();
+ }
+
+ finish(...args: any[]) {
+ if (this.modalsManager == null || this.id == null)
+ return;
+
+ this.modalsManager.close(this.id);
+ this.callback?.(...args);
+ }
+
+ close() {
+ this.finish();
+ }
+}
\ No newline at end of file
diff --git a/src/features/modals/modalsManager.js b/src/features/modals/modalsManager.ts
similarity index 62%
rename from src/features/modals/modalsManager.js
rename to src/features/modals/modalsManager.ts
index 0137455..fec130a 100644
--- a/src/features/modals/modalsManager.js
+++ b/src/features/modals/modalsManager.ts
@@ -1,21 +1,15 @@
-import Modal from "./modal.js";
+import Modal from "./modal";
export default class ModalsManager {
- /**
- * @type {Modal}
- */
- modals = {};
+ modals: Record = {};
+ containerRef: { current: HTMLElement | null };
+
+ updateModals: Function = () => {};
/**
- * @type {Function}
+ * @param single - Set to false to preserve other open modals
*/
- updateModals = () => {};
-
- /**
- * @param {Modal} modal
- * @param {boolean} single - Set to false to preserve other open modals
- */
- open(modal, single = true) {
+ open(modal: Modal, single: boolean = true) {
if (single) {
this.modalIds.forEach((id) => {
this.close(id, false);
@@ -35,11 +29,7 @@ export default class ModalsManager {
this.updateModals(this.modals);
}
- /**
- * @param {string} modalId
- * @param {boolean} sendModalsUpdate
- */
- close(modalId, sendModalsUpdate = true) {
+ close(modalId: string | number, sendModalsUpdate: boolean = true) {
modalId = modalId.toString();
if (!this.modalIds.includes(modalId)) {
@@ -54,10 +44,7 @@ export default class ModalsManager {
this.updateModals(this.modals);
}
- /**
- * @param {string} modalId
- */
- focus(modalId) {
+ focus(modalId: string) {
modalId = modalId.toString();
if (!this.modalIds.includes(modalId)) {
@@ -71,25 +58,15 @@ export default class ModalsManager {
this.updateModals(this.modals);
}
- /**
- * @param {Function} updateModals
- */
- setUpdateModals(updateModals) {
+ setUpdateModals(updateModals: Function) {
this.updateModals = updateModals;
}
- /**
- * @returns {string[]}
- */
- get modalIds() {
+ get modalIds(): string[] {
return Object.keys(this.modals);
}
- /**
- * @param {string} name
- * @returns {string}
- */
- static getModalIconUrl(name) {
+ static getModalIconUrl(name: string): string {
return `${process.env.PUBLIC_URL}/assets/modals/icons/${name}.svg`;
}
}
\ No newline at end of file
diff --git a/src/features/settings/settings.js b/src/features/settings/settings.ts
similarity index 74%
rename from src/features/settings/settings.js
rename to src/features/settings/settings.ts
index 888ce87..7c1be29 100644
--- a/src/features/settings/settings.js
+++ b/src/features/settings/settings.ts
@@ -1,24 +1,18 @@
-import { VirtualFile } from "../virtual-drive/file/virtualFile.js";
-import { VirtualRoot } from "../virtual-drive/root/virtualRoot.js";
+import { VirtualFile } from "../virtual-drive/file/virtualFile";
+import { VirtualRoot } from "../virtual-drive/root/virtualRoot";
const PARENT_NODE = "options";
export class Settings {
- xmlDoc = null;
+ path: string;
+ file: VirtualFile;
+ xmlDoc: Document = null;
+ #virtualRoot: VirtualRoot = null;
- /**
- * @type {VirtualRoot}
- */
- #virtualRoot = null;
-
- /**
- * @param {VirtualRoot} virtualRoot
- * @param {string} path
- */
- constructor(virtualRoot, path) {
+ constructor(virtualRoot: VirtualRoot, path: string) {
this.#virtualRoot = virtualRoot;
this.path = path;
- this.file = this.#virtualRoot.navigate(this.path);
+ this.file = this.#virtualRoot.navigate(this.path) as VirtualFile;
if (this.file == null) {
console.warn(`Unable to read settings from path: ${this.path}\nNo such file or directory.`);
@@ -34,9 +28,8 @@ export class Settings {
/**
* Reads the xml doc from the given path and assigns it to itself
- * @returns {Promise}
*/
- async read() {
+ async read(): Promise {
if (!this.file)
return;
@@ -63,27 +56,18 @@ export class Settings {
/**
* Checks if xml doc is missing
- * @returns {Promise}
*/
- async isMissingXmlDoc() {
+ async isMissingXmlDoc(): Promise {
if (this.xmlDoc == null)
await this.read();
return (this.xmlDoc == null);
}
- /**
- * @callback valueCallback
- * @param {string} value
- */
-
/**
* Gets a value by a given key if it exists or calls a callback function whenever the value changes
- * @param {string} key
- * @param {valueCallback} callback
- * @returns {Promise}
*/
- async get(key, callback) {
+ async get(key: string, callback?: (value: string) => void): Promise {
if (await this.isMissingXmlDoc())
return null;
@@ -106,11 +90,7 @@ export class Settings {
return value;
}
- /**
- * @param {string} key
- * @param {string} value
- */
- async set(key, value) {
+ async set(key: string, value: string) {
if (await this.isMissingXmlDoc())
return;
diff --git a/src/features/settings/settingsManager.js b/src/features/settings/settingsManager.js
deleted file mode 100644
index 0e08a39..0000000
--- a/src/features/settings/settingsManager.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { VirtualRoot } from "../virtual-drive/root/virtualRoot.js";
-import { Settings } from "./settings.js";
-
-export class SettingsManager {
- /**
- * @type {Object}
- */
- static VIRTUAL_PATHS = {
- desktop: "~/.config/desktop.xml",
- taskbar: "~/.config/taskbar.xml",
- apps: "~/.config/apps.xml",
- };
-
- /**
- * @type {Object}
- */
- #pathToSettings = {};
-
- /**
- * @type {VirtualRoot}
- */
- #virtualRoot = null;
-
- /**
- * @param {VirtualRoot} virtualRoot
- */
- constructor(virtualRoot) {
- this.#virtualRoot = virtualRoot;
-
- Object.values(SettingsManager.VIRTUAL_PATHS).forEach((path) => {
- this.#pathToSettings[path] = new Settings(this.#virtualRoot, path);
- });
- }
-
- /**
- * @param {string} path
- * @returns {Settings}
- */
- get(path) {
- return this.#pathToSettings[path];
- }
-}
\ No newline at end of file
diff --git a/src/features/settings/settingsManager.ts b/src/features/settings/settingsManager.ts
new file mode 100644
index 0000000..6f34b5d
--- /dev/null
+++ b/src/features/settings/settingsManager.ts
@@ -0,0 +1,26 @@
+import { VirtualRoot } from "../virtual-drive/root/virtualRoot";
+import { Settings } from "./settings";
+
+export class SettingsManager {
+ static VIRTUAL_PATHS: { [s: string]: string; } = {
+ desktop: "~/.config/desktop.xml",
+ taskbar: "~/.config/taskbar.xml",
+ apps: "~/.config/apps.xml",
+ };
+
+ #pathToSettings: { [s: string]: Settings; } = {};
+
+ #virtualRoot: VirtualRoot = null;
+
+ constructor(virtualRoot: VirtualRoot) {
+ this.#virtualRoot = virtualRoot;
+
+ Object.values(SettingsManager.VIRTUAL_PATHS).forEach((path) => {
+ this.#pathToSettings[path] = new Settings(this.#virtualRoot, path);
+ });
+ }
+
+ get(path: string): Settings {
+ return this.#pathToSettings[path];
+ }
+}
\ No newline at end of file
diff --git a/src/features/storage/storageManager.js b/src/features/storage/storageManager.js
deleted file mode 100644
index d95e118..0000000
--- a/src/features/storage/storageManager.js
+++ /dev/null
@@ -1,45 +0,0 @@
-export class StorageManager {
- static MAX_BYTES = 5_000_000;
-
- /**
- * @param {string} key
- * @param {string} value
- */
- static store(key, value) {
- if (key == null || value == null)
- return;
-
- localStorage.setItem(key, value);
- }
-
- /**
- * @param {string} key
- * @returns {string | null}
- */
- static load(key) {
- if (key == null)
- return null;
-
- return localStorage.getItem(key);
- }
-
- static clear() {
- localStorage.clear();
- }
-
- /**
- * @param {string} string
- * @returns {number} bytes
- */
- static getByteSize(string) {
- return new Blob([string]).size;
- }
-
- /**
- * @param {number} bytes
- * @returns {number} kilobytes
- */
- static byteToKilobyte(bytes) {
- return bytes / 1000;
- }
-}
\ No newline at end of file
diff --git a/src/features/storage/storageManager.ts b/src/features/storage/storageManager.ts
new file mode 100644
index 0000000..7d229cc
--- /dev/null
+++ b/src/features/storage/storageManager.ts
@@ -0,0 +1,29 @@
+export class StorageManager {
+ static MAX_BYTES = 5_000_000;
+
+ static store(key: string, value: string) {
+ if (key == null || value == null)
+ return;
+
+ localStorage.setItem(key, value);
+ }
+
+ static load(key: string): string | null {
+ if (key == null)
+ return null;
+
+ return localStorage.getItem(key);
+ }
+
+ static clear() {
+ localStorage.clear();
+ }
+
+ static getByteSize(string: string): number {
+ return new Blob([string]).size;
+ }
+
+ static byteToKilobyte(bytes: number): number {
+ return bytes / 1000;
+ }
+}
\ No newline at end of file
diff --git a/src/features/tracking/trackingManager.js b/src/features/tracking/trackingManager.ts
similarity index 82%
rename from src/features/tracking/trackingManager.js
rename to src/features/tracking/trackingManager.ts
index 22f99b8..cd2ce4b 100644
--- a/src/features/tracking/trackingManager.js
+++ b/src/features/tracking/trackingManager.ts
@@ -1,5 +1,5 @@
import ReactGA from "react-ga4";
-import { GA_MEASUREMENT_ID } from "../../config/tracking.config.js";
+import { GA_MEASUREMENT_ID } from "../../config/tracking.config";
export class TrackingManager {
static initialize() {
diff --git a/src/features/virtual-drive/file/virtualFile.js b/src/features/virtual-drive/file/virtualFile.ts
similarity index 74%
rename from src/features/virtual-drive/file/virtualFile.js
rename to src/features/virtual-drive/file/virtualFile.ts
index 07d7c10..47244d4 100644
--- a/src/features/virtual-drive/file/virtualFile.js
+++ b/src/features/virtual-drive/file/virtualFile.ts
@@ -1,13 +1,23 @@
-import { APPS } from "../../../config/apps.config.js";
-import { IMAGE_FORMATS } from "../../../config/apps/mediaViewer.config.js";
-import AppsManager from "../../apps/appsManager.js";
-import WindowsManager from "../../windows/windowsManager.js";
-import { VirtualBase } from "../virtualBase.js";
+import { APPS } from "../../../config/apps.config";
+import { IMAGE_FORMATS } from "../../../config/apps/mediaViewer.config";
+import AppsManager from "../../apps/appsManager";
+import WindowsManager from "../../windows/windowsManager";
+import { VirtualBase, VirtualBaseJson } from "../virtualBase";
+
+export interface VirtualFileJson extends VirtualBaseJson {
+ ext?: string;
+ cnt?: string;
+ src?: string;
+}
/**
* A virtual file that can be stored inside a folder
*/
export class VirtualFile extends VirtualBase {
+ extension: string;
+ source: string;
+ content: string;
+
static NON_TEXT_EXTENSIONS = [
"png"
];
@@ -16,29 +26,19 @@ export class VirtualFile extends VirtualBase {
CONTENT_CHANGE: "contentchange"
};
- /**
- * @param {string} name
- * @param {string=} extension
- */
- constructor(name, extension) {
+ constructor(name: string, extension?: string | undefined) {
super(name);
this.extension = extension;
}
- /**
- * @param {string} alias
- * @returns {VirtualFile}
- */
- setAlias(alias) {
+ setAlias(alias: string) {
return super.setAlias(alias);
}
/**
* Sets the source of this file and removes the content
- * @param {string} source
- * @returns {VirtualFile}
*/
- setSource(source) {
+ setSource(source: string) {
if (this.source === source || !this.canBeEdited)
return;
@@ -53,10 +53,8 @@ export class VirtualFile extends VirtualBase {
/**
* Sets the content of this file and removes the source
- * @param {string | *} content
- * @returns {VirtualFile}
*/
- setContent(content) {
+ setContent(content: string | any) {
if (this.content === content || !this.canBeEdited)
return;
@@ -76,14 +74,10 @@ export class VirtualFile extends VirtualBase {
return `${this.name}.${this.extension}`;
}
- /**
- * @param {string} id
- * @returns {{
- * name: string,
- * extension: string
- * }}
- */
- static convertId(id) {
+ static convertId(id: string): {
+ name: string;
+ extension: string;
+ } {
const sections = id.split(".");
const extension = sections.pop();
const name = sections.join(".");
@@ -92,16 +86,12 @@ export class VirtualFile extends VirtualBase {
/**
* Opens this file in an app associated with its extension
- * @param {WindowsManager} windowsManager
*/
- open(windowsManager) {
+ open(windowsManager: WindowsManager) {
return windowsManager.openFile(this);
}
- /**
- * @returns {Promise}
- */
- async read() {
+ async read(): Promise {
if (this.content != null)
return this.content;
@@ -119,17 +109,11 @@ export class VirtualFile extends VirtualBase {
});
}
- /**
- * @returns {boolean}
- */
- isFile() {
+ isFile(): boolean {
return true;
}
- /**
- * @returns {string}
- */
- getIconUrl() {
+ getIconUrl(): string {
if (this.iconUrl != null)
return this.iconUrl;
@@ -160,10 +144,7 @@ export class VirtualFile extends VirtualBase {
return iconUrl;
}
- /**
- * @returns {string}
- */
- getType() {
+ getType(): string {
let type = "";
switch (this.extension) {
@@ -184,15 +165,12 @@ export class VirtualFile extends VirtualBase {
return `${type} file (.${this.extension.toLowerCase()})`.trim();
}
- /**
- * @returns {object | null}
- */
- toJSON() {
+ toJSON(): VirtualFileJson | null {
// Don't return file if it can't or hasn't been edited
if (!this.canBeEdited || (this.editedByUser == null || !this.editedByUser))
return null;
- const object = super.toJSON();
+ const object = super.toJSON() as VirtualFileJson;
if (object == null)
return null;
diff --git a/src/features/virtual-drive/file/virtualFileLink.js b/src/features/virtual-drive/file/virtualFileLink.ts
similarity index 51%
rename from src/features/virtual-drive/file/virtualFileLink.js
rename to src/features/virtual-drive/file/virtualFileLink.ts
index 0164254..d348401 100644
--- a/src/features/virtual-drive/file/virtualFileLink.js
+++ b/src/features/virtual-drive/file/virtualFileLink.ts
@@ -1,23 +1,21 @@
-import { VirtualFile } from "./virtualFile.js";
+import { VirtualFile, VirtualFileJson } from "./virtualFile";
+
+export interface VirtualFileLinkJson extends VirtualFileJson {
+ lnk: string;
+}
/**
* A link that points to a virtual file
*/
export class VirtualFileLink extends VirtualFile {
- /**
- * @param {string} name
- * @param {VirtualFile} linkedFile
- */
- constructor(name, linkedFile) {
+ linkedPath: string;
+
+ constructor(name: string, linkedFile?: VirtualFile) {
super(name);
this.linkedFile = linkedFile;
}
- /**
- * @param {VirtualFile} file
- * @returns {VirtualFileLink}
- */
- setLinkedFile(file) {
+ setLinkedFile(file: VirtualFile): VirtualFileLink {
this.linkedFile = file;
if (file) {
@@ -30,11 +28,7 @@ export class VirtualFileLink extends VirtualFile {
return this;
}
- /**
- * @param {string} path
- * @returns {VirtualFileLink}
- */
- setLinkedPath(path) {
+ setLinkedPath(path: string): VirtualFileLink {
if (this.linkedFile && this.linkedFile.path === path)
return;
@@ -49,10 +43,7 @@ export class VirtualFileLink extends VirtualFile {
return this;
}
- /**
- * @returns {boolean}
- */
- isValid() {
+ isValid(): boolean {
if (!this.linkedPath)
return false;
@@ -61,10 +52,7 @@ export class VirtualFileLink extends VirtualFile {
return (this.linkedFile != null);
}
- /**
- * @returns {object | null}
- */
- toJSON() {
+ toJSON(): VirtualFileLinkJson | null {
if (this.linkedPath == null)
return;
@@ -78,38 +66,37 @@ export class VirtualFileLink extends VirtualFile {
// Point certain methods to linked file
- /** @type {VirtualFile["setAlias"]} */
- setAlias(...args) {
- if (this.isValid()) return this.linkedFile.setAlias(...args);
+ setAlias(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFile.setAlias(...args);
+ return this;
}
- /** @type {VirtualFile["setSource"]} */
- setSource(...args) {
- if (this.isValid()) return this.linkedFile.setSource(...args);
+ setSource(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFile.setSource(...args);
+ return this;
}
- /** @type {VirtualFile["setContent"]} */
- setContent(...args) {
- if (this.isValid()) return this.linkedFile.setContent(...args);
+ setContent(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFile.setContent(...args);
+ return this;
}
- /** @type {VirtualFile["id"]} */
get id() {
return this.isValid() ? this.linkedFile.id : null;
}
- /** @type {VirtualFile["open"]} */
- open(...args) {
+ open(...args: Parameters): ReturnType | undefined {
if (this.isValid()) return this.linkedFile.open(...args);
}
- /** @type {VirtualFile["read"]} */
- read(...args) {
+ read(...args: Parameters): ReturnType | undefined {
if (this.isValid()) return this.linkedFile.read(...args);
}
- /** @type {VirtualFile["getIconUrl"]} */
- getIconUrl(...args) {
+ getIconUrl(...args: Parameters): ReturnType | undefined {
if (this.isValid()) return this.iconUrl ?? this.linkedFile.getIconUrl(...args);
}
}
\ No newline at end of file
diff --git a/src/features/virtual-drive/folder/index.ts b/src/features/virtual-drive/folder/index.ts
new file mode 100644
index 0000000..d55454a
--- /dev/null
+++ b/src/features/virtual-drive/folder/index.ts
@@ -0,0 +1,2 @@
+export { VirtualFolder } from "./virtualFolder";
+export { VirtualFolderLink } from "./virtualFolderLink";
\ No newline at end of file
diff --git a/src/features/virtual-drive/folder/virtualFolder.js b/src/features/virtual-drive/folder/virtualFolder.ts
similarity index 65%
rename from src/features/virtual-drive/folder/virtualFolder.js
rename to src/features/virtual-drive/folder/virtualFolder.ts
index 72ee961..a22fc23 100644
--- a/src/features/virtual-drive/folder/virtualFolder.js
+++ b/src/features/virtual-drive/folder/virtualFolder.ts
@@ -1,66 +1,59 @@
-import { APPS } from "../../../config/apps.config.js";
-import AppsManager from "../../apps/appsManager.js";
-import { removeFromArray } from "../../_utils/array.utils.js";
-import WindowsManager from "../../windows/windowsManager.js";
-import { VirtualFileLink } from "../file/virtualFileLink.js";
-import { VirtualFolderLink } from "./virtualFolderLink.js";
-import { VirtualBase } from "../virtualBase.js";
-import { VirtualFile } from "../file/virtualFile.js";
+import { APPS } from "../../../config/apps.config";
+import AppsManager from "../../apps/appsManager";
+import { removeFromArray } from "../../_utils/array.utils";
+import WindowsManager from "../../windows/windowsManager";
+import { VirtualFileLink } from "../file/virtualFileLink";
+import { VirtualBase, VirtualBaseJson } from "../virtualBase";
+import { VirtualFile, VirtualFileJson } from "../file/virtualFile";
+import { VirtualFolderLink } from ".";
+
+export interface VirtualFolderJson extends VirtualBaseJson {
+ fls?: VirtualFileJson[];
+ fds?: VirtualFolderJson[];
+}
/**
* A virtual folder that can contains files and sub-folders
*/
export class VirtualFolder extends VirtualBase {
+ subFolders: (VirtualFolder | VirtualFolderLink)[];
+ files: (VirtualFile | VirtualFileLink)[];
+ type: number | undefined;
+
static TYPE = {
GENERAL: 0,
MEDIA: 1,
};
- /**
- * @param {string} name
- * @param {number} type
- */
- constructor(name, type) {
+ constructor(name: string, type?: number) {
super(name);
this.subFolders = [];
this.files = [];
this.type = type ?? VirtualFolder.TYPE.GENERAL;
}
- /**
- * @param {string} alias
- * @returns {VirtualFolder}
- */
- setAlias(alias) {
+ setAlias(alias: string) {
return super.setAlias(alias);
}
/**
* Returns true if this folder contains a file matching a name and extension
- * @param {string} name
- * @param {string} extension
- * @returns {VirtualFolder}
*/
- hasFile(name, extension) {
+ hasFile(name: string, extension?: string) {
return this.findFile(name, extension) !== null;
}
/**
* Returns true if this folder contains a folder matching a name
- * @param {string} name
- * @returns {boolean}
*/
- hasFolder(name) {
+ hasFolder(name: string) {
return this.findSubFolder(name) !== null;
}
/**
* Finds and returns a file inside this folder matching a name and extension
- * @param {string} name
- * @param {string} extension
- * @returns {VirtualFile}
*/
- findFile(name, extension) {
+ findFile(name: string, extension?: string): VirtualFile | VirtualFileLink {
let resultFile = null;
this.files.forEach((file) => {
@@ -76,10 +69,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Finds and returns a folder inside this folder matching a name
- * @param {string} name
- * @returns {VirtualFolder}
*/
- findSubFolder(name) {
+ findSubFolder(name: string): VirtualFolder | VirtualFolderLink {
let resultFolder = null;
this.subFolders.forEach((folder) => {
@@ -91,21 +82,12 @@ export class VirtualFolder extends VirtualBase {
return resultFolder;
}
- /**
- * @callback createFileCallback
- * @param {VirtualFile} newFile
- */
-
/**
* Creates a file with a name and extension
- * @param {string} name
- * @param {string} extension
- * @param {createFileCallback} callback
- * @returns {VirtualFolder}
*/
- createFile(name, extension, callback) {
+ createFile(name: string, extension: string, callback?: (newFile: VirtualFile | VirtualFileLink) => void) {
if (!this.canBeEdited)
- return;
+ return this;
let newFile = this.findFile(name, extension);
if (newFile == null) {
@@ -121,14 +103,10 @@ export class VirtualFolder extends VirtualBase {
/**
* Creates files based on an array of objects with file names and extensions
- * @param {object[]} files
- * @param {string} files.name
- * @param {string} files.extension
- * @returns {VirtualFolder}
*/
- createFiles(files) {
+ createFiles(files: { name: string; extension: string; }[]) {
if (!this.canBeEdited)
- return;
+ return this;
files.forEach(({ name, extension }) => {
this.createFile(name, extension);
@@ -138,20 +116,12 @@ export class VirtualFolder extends VirtualBase {
return this;
}
- /**
- * @callback createFileLinkCallback
- * @param {VirtualFileLink} newFileLink
- */
-
/**
* Creates a file link with a name
- * @param {string} name
- * @param {createFileLinkCallback} callback
- * @returns {VirtualFolder}
*/
- createFileLink(name, callback) {
+ createFileLink(name: string, callback?: (newFileLink: VirtualFileLink | VirtualFile) => void) {
if (!this.canBeEdited)
- return;
+ return this;
let newFile = this.findFile(name);
if (newFile == null) {
@@ -167,11 +137,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Creates files based on an array of objects with file names and extensions
- * @param {object[]} files
- * @param {string} files.name
- * @returns {VirtualFolder}
*/
- createFileLinks(files) {
+ createFileLinks(files: { name: string; }[]): VirtualFolder {
if (!this.canBeEdited)
return;
@@ -183,18 +150,10 @@ export class VirtualFolder extends VirtualBase {
return this;
}
- /**
- * @callback createFolderCallback
- * @param {VirtualFolder} newFolder
- */
-
/**
* Creates a folder with a name
- * @param {string} name
- * @param {createFolderCallback} callback
- * @returns {VirtualFolder}
*/
- createFolder(name, callback) {
+ createFolder(name: string, callback?: (newFolder: VirtualFolder) => void): VirtualFolder {
if (!this.canBeEdited)
return;
@@ -212,10 +171,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Creates folders based on an array of folder names
- * @param {string[]} names
- * @returns {VirtualFolder}
*/
- createFolders(names) {
+ createFolders(names: string[]): VirtualFolder {
if (!this.canBeEdited)
return;
@@ -227,20 +184,12 @@ export class VirtualFolder extends VirtualBase {
return this;
}
- /**
- * @callback createFolderLinkCallback
- * @param {VirtualFolderLink} newFolderLink
- */
-
/**
* Creates a folder link with a name
- * @param {string} name
- * @param {createFolderLinkCallback} callback
- * @returns {VirtualFolderLink}
*/
- createFolderLink(name, callback) {
+ createFolderLink(name: string, callback?: (newFolderLink: VirtualFolderLink | VirtualFolder) => void) {
if (!this.canBeEdited)
- return;
+ return this;
let newFolder = this.findSubFolder(name);
if (newFolder == null) {
@@ -256,10 +205,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Creates folder links based on an array of folder names
- * @param {string[]} names
- * @returns {VirtualFolder}
*/
- createFolderLinks(names) {
+ createFolderLinks(names: string[]): VirtualFolder {
if (!this.canBeEdited)
return;
@@ -273,9 +220,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Removes a file or folder from this folder
- * @param {VirtualFile | VirtualFolder | VirtualFolderLink} child
*/
- remove(child) {
+ remove(child: VirtualFile | VirtualFolder | VirtualFolderLink) {
if (!this.canBeEdited)
return;
@@ -292,12 +238,10 @@ export class VirtualFolder extends VirtualBase {
/**
* Returns the file or folder at a relative path or null if it doesn't exist
- * @param {string} relativePath
- * @returns {VirtualFile | VirtualFolder | null}
*/
- navigate(relativePath) {
+ navigate(relativePath: string): VirtualFile | VirtualFolder | null {
const segments = relativePath.split("/");
- let currentDirectory = this;
+ let currentDirectory: VirtualFile | VirtualFolder = this;
const getDirectory = (path, isStart) => {
if (isStart && path === "") {
@@ -309,7 +253,7 @@ export class VirtualFolder extends VirtualBase {
} else if (path === "..") {
return currentDirectory?.parent;
} else {
- return currentDirectory?.findSubFolder(path);
+ return (currentDirectory as VirtualFolder)?.findSubFolder(path);
}
};
@@ -329,13 +273,13 @@ export class VirtualFolder extends VirtualBase {
if (lastSegment === "") {
return currentDirectory;
} else if (currentDirectory != null) {
- const folder = currentDirectory.findSubFolder(lastSegment);
+ const folder = (currentDirectory as VirtualFolder).findSubFolder(lastSegment);
if (folder != null)
return folder;
const { name, extension } = VirtualFile.convertId(lastSegment);
- return currentDirectory.findFile(name, extension);
+ return (currentDirectory as VirtualFolder).findFile(name, extension);
} else {
return null;
}
@@ -343,9 +287,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Opens this folder in file explorer
- * @param {WindowsManager} windowsManager
*/
- open(windowsManager) {
+ open(windowsManager: WindowsManager) {
return windowsManager.open(APPS.FILE_EXPLORER, { startPath: this.path });
}
@@ -358,7 +301,12 @@ export class VirtualFolder extends VirtualBase {
super.delete();
- this.files.concat(this.subFolders).forEach((item) => {
+ const items = [
+ ...this.files,
+ ...this.subFolders
+ ];
+
+ items.forEach((item) => {
item.delete();
});
@@ -367,10 +315,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Returns all files inside this folder
- * @param {Boolean=false} showHidden
- * @returns {VirtualFile[]}
*/
- getFiles(showHidden = false) {
+ getFiles(showHidden = false): VirtualFile[] {
if (showHidden)
return this.files;
@@ -381,10 +327,8 @@ export class VirtualFolder extends VirtualBase {
/**
* Returns all sub-folders inside this folder
- * @param {Boolean=false} showHidden
- * @returns {VirtualFolder[]}
*/
- getSubFolders(showHidden = false) {
+ getSubFolders(showHidden = false): VirtualFolder[] {
if (showHidden)
return this.subFolders;
@@ -395,38 +339,27 @@ export class VirtualFolder extends VirtualBase {
/**
* Returns the amount of files and sub-folders inside this folder
- * @param {Boolean=false} showHidden
- * @returns {number}
*/
- getItemCount(showHidden = false) {
+ getItemCount(showHidden = false): number {
const filesCount = this.getFiles(showHidden)?.length ?? 0;
const foldersCount = this.getSubFolders(showHidden)?.length ?? 0;
return filesCount + foldersCount;
}
- /**
- * @returns {boolean}
- */
- isFolder() {
+ isFolder(): boolean {
return true;
}
- /**
- * @returns {string}
- */
- getIconUrl() {
+ getIconUrl(): string {
if (this.iconUrl != null)
return this.iconUrl;
return AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder");
}
- /**
- * @returns {object | null}
- */
- toJSON() {
- const object = super.toJSON();
+ toJSON(): VirtualFolderJson | null {
+ const object = super.toJSON() as VirtualFolderJson;
if (object == null)
return null;
diff --git a/src/features/virtual-drive/folder/virtualFolderLink.js b/src/features/virtual-drive/folder/virtualFolderLink.js
deleted file mode 100644
index d1ae328..0000000
--- a/src/features/virtual-drive/folder/virtualFolderLink.js
+++ /dev/null
@@ -1,158 +0,0 @@
-import { APPS } from "../../../config/apps.config.js";
-import AppsManager from "../../apps/appsManager.js";
-import { VirtualFolder } from "./virtualFolder.js";
-
-/**
- * A link that points to a virtual folder
- */
-export class VirtualFolderLink extends VirtualFolder {
- /**
- * @param {string} name
- * @param {VirtualFolder} linkedFolder
- */
- constructor(name, linkedFolder) {
- super(name);
- this.linkedFolder = linkedFolder;
- }
-
- /**
- * @param {VirtualFolder} folder
- * @returns {VirtualFolderLink}
- */
- setLinkedFolder(folder) {
- this.linkedFolder = folder;
-
- if (folder) {
- this.linkedPath = folder.path;
- this.type = folder.type;
- }
-
- return this;
- }
-
- /**
- * @param {string} path
- * @returns {VirtualFolderLink}
- */
- setLinkedPath(path) {
- if (this.linkedFolder && this.linkedFolder.path === path)
- return;
-
- const target = this.navigate(path);
-
- if (target instanceof VirtualFolder) {
- this.setLinkedFolder(target);
- } else {
- this.linkedFolder = null;
- }
-
- return this;
- }
-
- /**
- * @returns {boolean}
- */
- isValid() {
- if (!this.linkedPath)
- return false;
-
- this.setLinkedPath(this.linkedPath);
-
- return (this.linkedFolder != null);
- }
-
- /**
- * @returns {string}
- */
- getIconUrl() {
- if (this.iconUrl != null)
- return this.iconUrl;
-
- if (this.isValid() && this.linkedFolder.iconUrl)
- return this.linkedFolder.iconUrl;
-
- return AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-link");
- }
-
- /**
- * @returns {object | null}
- */
- toJSON() {
- if (this.linkedPath == null)
- return;
-
- const object = {
- nam: this.name,
- lnk: this.linkedPath
- };
-
- return object;
- }
-
- // Point certain methods to linked folder
-
- /** @type {VirtualFolder["setAlias"]} */
- setAlias(...args) {
- if (this.isValid()) return this.linkedFolder.setAlias(...args);
- }
-
- /** @type {VirtualFolder["hasFile"]} */
- hasFile(...args) {
- if (this.isValid()) return this.linkedFolder.hasFile(...args);
- }
-
- /** @type {VirtualFolder["hasFolder"]} */
- hasFolder(...args) {
- if (this.isValid()) return this.linkedFolder.hasFolder(...args);
- }
-
- /** @type {VirtualFolder["findFile"]} */
- findFile(...args) {
- if (this.isValid()) return this.linkedFolder.findFile(...args);
- }
-
- /** @type {VirtualFolder["findSubFolder"]} */
- findSubFolder(...args) {
- if (this.isValid()) return this.linkedFolder.findSubFolder(...args);
- }
-
- /** @type {VirtualFolder["createFile"]} */
- createFile(...args) {
- if (this.isValid()) return this.linkedFolder.createFile(...args);
- }
-
- /** @type {VirtualFolder["createFile"]} */
- createFiles(...args) {
- if (this.isValid()) return this.linkedFolder.createFiles(...args);
- }
-
- /** @type {VirtualFolder["createFolder"]} */
- createFolder(...args) {
- if (this.isValid()) return this.linkedFolder.createFolder(...args);
- }
-
- /** @type {VirtualFolder["createFolders"]} */
- createFolders(...args) {
- if (this.isValid()) return this.linkedFolder.createFolders(...args);
- }
-
- /** @type {VirtualFolder["getFiles"]} */
- getFiles(...args) {
- if (this.isValid()) return this.linkedFolder.getFiles(...args);
- }
-
- /** @type {VirtualFolder["getSubFolders"]} */
- getSubFolders(...args) {
- if (this.isValid()) return this.linkedFolder.getSubFolders(...args);
- }
-
- /** @type {VirtualFolder["open"]} */
- open(...args) {
- if (this.isValid()) return this.linkedFolder.open(...args);
- }
-
- /** @type {VirtualFolder["getItemCount"]} */
- getItemCount(...args) {
- if (this.isValid()) return this.linkedFolder.getItemCount(...args);
- }
-}
\ No newline at end of file
diff --git a/src/features/virtual-drive/folder/virtualFolderLink.ts b/src/features/virtual-drive/folder/virtualFolderLink.ts
new file mode 100644
index 0000000..b21f7e3
--- /dev/null
+++ b/src/features/virtual-drive/folder/virtualFolderLink.ts
@@ -0,0 +1,141 @@
+import { APPS } from "../../../config/apps.config";
+import AppsManager from "../../apps/appsManager";
+import { VirtualFolder } from ".";
+import { VirtualFolderJson } from "./virtualFolder";
+
+export interface VirtualFolderLinkJson extends VirtualFolderJson {
+ lnk: string;
+}
+
+/**
+ * A link that points to a virtual folder
+ */
+export class VirtualFolderLink extends VirtualFolder {
+ linkedPath: string;
+
+ constructor(name: string, linkedFolder?: VirtualFolder) {
+ super(name);
+ this.linkedFolder = linkedFolder;
+ }
+
+ setLinkedFolder(folder: VirtualFolder): VirtualFolderLink {
+ this.linkedFolder = folder;
+
+ if (folder) {
+ this.linkedPath = folder.path;
+ this.type = folder.type;
+ }
+
+ return this;
+ }
+
+ setLinkedPath(path: string): VirtualFolderLink {
+ if (this.linkedFolder && this.linkedFolder.path === path)
+ return;
+
+ const target = this.navigate(path);
+
+ if (target instanceof VirtualFolder) {
+ this.setLinkedFolder(target);
+ } else {
+ this.linkedFolder = null;
+ }
+
+ return this;
+ }
+
+ isValid(): boolean {
+ if (!this.linkedPath)
+ return false;
+
+ this.setLinkedPath(this.linkedPath);
+
+ return (this.linkedFolder != null);
+ }
+
+ getIconUrl(): string {
+ if (this.iconUrl != null)
+ return this.iconUrl;
+
+ if (this.isValid() && this.linkedFolder.iconUrl)
+ return this.linkedFolder.iconUrl;
+
+ return AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "folder-link");
+ }
+
+ toJSON(): VirtualFolderLinkJson | null {
+ if (this.linkedPath == null)
+ return;
+
+ const object = {
+ nam: this.name,
+ lnk: this.linkedPath
+ };
+
+ return object;
+ }
+
+ // Point certain methods to linked folder
+
+ setAlias(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFolder.setAlias(...args);
+ return this;
+ }
+
+ createFile(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFolder.createFile(...args);
+ return this;
+ }
+
+ createFiles(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFolder.createFiles(...args);
+ return this;
+ }
+
+ createFolder(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFolder.createFolder(...args);
+ return this;
+ }
+
+ createFolders(...args: Parameters) {
+ if (this.isValid())
+ this.linkedFolder.createFolders(...args);
+ return this;
+ }
+
+ hasFile(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.hasFile(...args);
+ }
+
+ hasFolder(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.hasFolder(...args);
+ }
+
+ findFile(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.findFile(...args);
+ }
+
+ findSubFolder(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.findSubFolder(...args);
+ }
+
+ getFiles(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.getFiles(...args);
+ }
+
+ getSubFolders(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.getSubFolders(...args);
+ }
+
+ open(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.open(...args);
+ }
+
+ getItemCount(...args: Parameters): ReturnType | undefined {
+ if (this.isValid()) return this.linkedFolder.getItemCount(...args);
+ }
+}
\ No newline at end of file
diff --git a/src/features/virtual-drive/root/defaultData.js b/src/features/virtual-drive/root/defaultData.ts
similarity index 90%
rename from src/features/virtual-drive/root/defaultData.js
rename to src/features/virtual-drive/root/defaultData.ts
index 8a396b5..eb76669 100644
--- a/src/features/virtual-drive/root/defaultData.js
+++ b/src/features/virtual-drive/root/defaultData.ts
@@ -1,14 +1,15 @@
-import { APPS } from "../../../config/apps.config.js";
-import { WALLPAPERS } from "../../../config/desktop.config.js";
-import AppsManager from "../../apps/appsManager.js";
-import { VirtualRoot } from "./virtualRoot.js";
+import { APPS } from "../../../config/apps.config";
+import { WALLPAPERS } from "../../../config/desktop.config";
+import AppsManager from "../../apps/appsManager";
+import { VirtualFileLink } from "../file/virtualFileLink";
+import { VirtualFolderLink } from "../folder";
+import { VirtualRoot } from "./virtualRoot";
/**
* Loads default data on the virtual root
- * @param {VirtualRoot} virtualRoot
*/
-export function loadDefaultData(virtualRoot) {
- const linkedPaths = {};
+export function loadDefaultData(virtualRoot: VirtualRoot) {
+ const linkedPaths: Record = {};
virtualRoot.createFolder("home", (folder) => {
folder.createFolder("prozilla-os", (folder) => {
@@ -62,13 +63,13 @@ export function loadDefaultData(virtualRoot) {
linkedPaths.documents = folder.path;
})
.createFolder("Desktop", (folder) => {
- folder.createFileLink("info.md", (fileLink) => {
+ folder.createFileLink("info.md", (fileLink: VirtualFileLink) => {
fileLink.setLinkedPath(linkedPaths.info);
- }).createFileLink("links.md", (fileLink) => {
+ }).createFileLink("links.md", (fileLink: VirtualFileLink) => {
fileLink.setLinkedPath(linkedPaths.links);
- }).createFolderLink("Pictures", (folderLink) => {
+ }).createFolderLink("Pictures", (folderLink: VirtualFolderLink) => {
folderLink.setLinkedPath(linkedPaths.images);
- }).createFolderLink("Documents", (folderLink) => {
+ }).createFolderLink("Documents", (folderLink: VirtualFolderLink) => {
folderLink.setLinkedPath(linkedPaths.documents);
});
});
@@ -157,7 +158,7 @@ export function loadDefaultData(virtualRoot) {
.createFile("App", "jsx", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/Prozilla-OS/main/src/App.jsx");
}).createFile("index", "js", (file) => {
- file.setSource("https://raw.githubusercontent.com/Prozilla/Prozilla-OS/main/src/index.js");
+ file.setSource("https://raw.githubusercontent.com/Prozilla/Prozilla-OS/main/src/index");
});
});
diff --git a/src/features/virtual-drive/root/virtualRoot.js b/src/features/virtual-drive/root/virtualRoot.ts
similarity index 69%
rename from src/features/virtual-drive/root/virtualRoot.js
rename to src/features/virtual-drive/root/virtualRoot.ts
index 70d7213..aca4b96 100644
--- a/src/features/virtual-drive/root/virtualRoot.js
+++ b/src/features/virtual-drive/root/virtualRoot.ts
@@ -1,18 +1,22 @@
-import { StorageManager } from "../../storage/storageManager.js";
-import { VirtualFolderLink } from "../folder/virtualFolderLink.js";
-import { loadDefaultData } from "./defaultData.js";
-import { VirtualFile } from "../file/virtualFile.js";
-import { VirtualFolder } from "../folder/virtualFolder.js";
+import { StorageManager } from "../../storage/storageManager";
+import { VirtualFolderLink } from "../folder/virtualFolderLink";
+import { loadDefaultData } from "./defaultData";
+import { VirtualFile, VirtualFileJson } from "../file/virtualFile";
+import { VirtualFolder } from "../folder";
+import { VirtualFileLink } from "../file/virtualFileLink";
+import { VirtualFolderJson } from "../folder/virtualFolder";
+
+export interface VirtualRootJson extends VirtualFolderJson {
+ scs: Record;
+}
/**
* A virtual folder that serves as the root folder
*/
export class VirtualRoot extends VirtualFolder {
- /** @type {boolean} */
- initiated = false;
-
- /** @type {boolean} */
- loadedDefaultData = false;
+ shortcuts: Record;
+ initiated: boolean = false;
+ loadedDefaultData: boolean = false;
constructor() {
super("root");
@@ -48,9 +52,9 @@ export class VirtualRoot extends VirtualFolder {
cnt: content,
lnk: link,
ico: iconUrl,
- }, parent = this) => {
+ }: any, parent: VirtualFolder = this) => {
if (link) {
- parent.createFileLink(name, (fileLink) => {
+ parent.createFileLink(name, (fileLink: VirtualFileLink) => {
fileLink.setLinkedPath(link);
if (iconUrl != null) {
fileLink.setIconUrl(iconUrl);
@@ -59,7 +63,7 @@ export class VirtualRoot extends VirtualFolder {
return;
}
- parent.createFile(name, extension, (file) => {
+ parent.createFile(name, extension, (file: VirtualFile) => {
if (source != null) {
file.setSource(source);
} else if (content != null) {
@@ -77,9 +81,9 @@ export class VirtualRoot extends VirtualFolder {
fls: files,
lnk: link,
ico: iconUrl,
- }, parent = this) => {
+ }: any, parent: VirtualFolder = this) => {
if (link) {
- parent.createFolderLink(name, (folderLink) => {
+ parent.createFolderLink(name, (folderLink: VirtualFolderLink) => {
folderLink.setLinkedPath(link);
if (iconUrl != null) {
folderLink.setIconUrl(iconUrl);
@@ -88,7 +92,7 @@ export class VirtualRoot extends VirtualFolder {
return;
}
- parent.createFolder(name, (folder) => {
+ parent.createFolder(name, (folder: VirtualFolder) => {
if (Object.values(shortcuts).includes(folder.displayPath)) {
let alias;
for (const [key, value] of Object.entries(shortcuts)) {
@@ -98,12 +102,12 @@ export class VirtualRoot extends VirtualFolder {
folder.setAlias(alias);
}
if (folders != null) {
- folders.forEach((subFolder) => {
+ folders.forEach((subFolder: VirtualFolderJson) => {
addFolder(subFolder, folder);
});
}
if (files != null) {
- files.forEach((file) => {
+ files.forEach((file: VirtualFileJson) => {
addFile(file, folder);
});
}
@@ -114,12 +118,12 @@ export class VirtualRoot extends VirtualFolder {
};
if (object.fds != null) {
- object.fds.forEach((subFolder) => {
+ object.fds.forEach((subFolder: VirtualFolderJson) => {
addFolder(subFolder);
});
}
if (object.fls != null) {
- object.fls.forEach((file) => {
+ object.fls.forEach((file: VirtualFileJson) => {
addFile(file);
});
}
@@ -142,9 +146,8 @@ export class VirtualRoot extends VirtualFolder {
/**
* Initiates this root by loading the default data and then the user's data on top
- * @returns {VirtualRoot}
*/
- init() {
+ init(): VirtualRoot {
this.initiated = false;
// Load default data
@@ -162,11 +165,8 @@ export class VirtualRoot extends VirtualFolder {
/**
* Adds a shortcut to a file or folder
- * @param {string} name
- * @param {VirtualFile | VirtualFolder | VirtualFolderLink} destination
- * @returns {VirtualRoot}
*/
- addShortcut(name, destination) {
+ addShortcut(name: string, destination: VirtualFile | VirtualFileLink | VirtualFolder | VirtualFolderLink) {
this.shortcuts[name] = destination;
return this;
}
@@ -177,7 +177,7 @@ export class VirtualRoot extends VirtualFolder {
reset() {
if (window.confirm("Are you sure you want to reset all your data?")) {
StorageManager.clear();
- window.location.reload(false);
+ window.location.reload();
}
}
@@ -201,11 +201,8 @@ export class VirtualRoot extends VirtualFolder {
return "/";
}
- /**
- * @returns {object | null}
- */
- toJSON() {
- const object = super.toJSON();
+ toJSON(): VirtualRootJson | null {
+ const object = super.toJSON() as VirtualRootJson;
if (object == null)
return null;
@@ -225,7 +222,7 @@ export class VirtualRoot extends VirtualFolder {
/**
* @returns {string | null}
*/
- toString() {
+ toString(): string | null {
const json = this.toJSON();
if (json == null)
diff --git a/src/features/virtual-drive/virtualBase.js b/src/features/virtual-drive/virtualBase.ts
similarity index 59%
rename from src/features/virtual-drive/virtualBase.js
rename to src/features/virtual-drive/virtualBase.ts
index ef3fa02..625453f 100644
--- a/src/features/virtual-drive/virtualBase.js
+++ b/src/features/virtual-drive/virtualBase.ts
@@ -1,13 +1,28 @@
-import { APPS } from "../../config/apps.config.js";
-import AppsManager from "../apps/appsManager.js";
-import { EventEmitter } from "../_utils/event.utils.js";
-import { VirtualRoot } from "./root/virtualRoot.js";
+import { APPS } from "../../config/apps.config";
+import AppsManager from "../apps/appsManager";
+import { EventEmitter, EventNamesMap } from "../_utils/event.utils";
+import { VirtualRoot } from "./root/virtualRoot";
+import { VirtualFile } from "./file/virtualFile";
+import { VirtualFolder } from "./folder";
-export class VirtualBase extends EventEmitter {
- /**
- * @param {string} name
- */
- constructor(name) {
+export interface VirtualBaseJson {
+ nam: string;
+ ico?: string;
+}
+
+export class VirtualBase extends EventEmitter {
+ name: string;
+ alias: string;
+ parent: VirtualFolder | undefined;
+ isProtected: boolean;
+ iconUrl: string;
+ linkedFile: VirtualFile | undefined;
+ linkedFolder: VirtualFolder | undefined;
+ editedByUser: boolean;
+ isRoot: boolean;
+ root: VirtualRoot | undefined;
+
+ constructor(name: string) {
super();
this.name = name;
}
@@ -16,13 +31,9 @@ export class VirtualBase extends EventEmitter {
return this.name;
}
- /**
- * @param {string} name
- * @returns {VirtualBase}
- */
- setName(name) {
+ setName(name: string) {
if (this.name === name || !this.canBeEdited)
- return;
+ return this;
this.name = name;
@@ -30,28 +41,20 @@ export class VirtualBase extends EventEmitter {
return this;
}
- /**
- * @param {string} alias
- * @returns {VirtualBase}
- */
- setAlias(alias) {
+ setAlias(alias: string) {
if (this.alias === alias || !this.canBeEdited)
- return;
+ return this;;
this.alias = alias;
- this.getRoot().addShortcut(alias, this);
+ this.getRoot().addShortcut(alias, this as any);
this.confirmChanges();
return this;
}
- /**
- * @param {VirtualBase} parent
- * @returns {VirtualBase}
- */
- setParent(parent) {
+ setParent(parent: VirtualFolder) {
if (this.parent === parent || !this.canBeEdited)
- return;
+ return this;
this.parent = parent;
@@ -59,25 +62,17 @@ export class VirtualBase extends EventEmitter {
return this;
}
- /**
- * @param {boolean} value
- * @returns {VirtualBase}
- */
- setProtected(value) {
+ setProtected(value: boolean) {
if (!this.canBeEdited)
- return;
+ return this;
this.isProtected = value;
return this;
}
- /**
- * @param {string} iconUrl
- * @returns {VirtualBase}
- */
- setIconUrl(iconUrl) {
+ setIconUrl(iconUrl: string) {
if (this.iconUrl === iconUrl || !this.canBeEdited)
- return;
+ return this;
this.iconUrl = iconUrl;
@@ -85,20 +80,14 @@ export class VirtualBase extends EventEmitter {
return this;
}
- /**
- * @returns {string}
- */
- getIconUrl() {
+ getIconUrl(): string {
return this.iconUrl
?? this.linkedFile?.iconUrl
?? this.linkedFolder?.iconUrl
?? AppsManager.getAppIconUrl(APPS.FILE_EXPLORER, "file");
}
- /**
- * @returns {string}
- */
- getType() {
+ getType(): string {
return "None";
}
@@ -111,14 +100,11 @@ export class VirtualBase extends EventEmitter {
if (parent == null)
return;
- parent.remove?.(this);
+ parent.remove?.(this as any);
this.confirmChanges(parent.getRoot());
}
- /**
- * @param {VirtualRoot} [root]
- */
- confirmChanges(root) {
+ confirmChanges(root?: VirtualRoot) {
if (root == null)
root = this.getRoot();
@@ -128,7 +114,7 @@ export class VirtualBase extends EventEmitter {
root?.saveData();
}
- open() {}
+ open(..._args: any[]): any {}
get path() {
return this.alias ?? this.displayPath;
@@ -143,9 +129,8 @@ export class VirtualBase extends EventEmitter {
/**
* Returns path without using any aliases
- * @returns {string}
*/
- get absolutePath() {
+ get absolutePath(): string {
if (this.parent?.isRoot) {
return "/" + this.id;
} else {
@@ -155,9 +140,8 @@ export class VirtualBase extends EventEmitter {
/**
* Returns whether this can be edited in its current state
- * @returns {boolean}
*/
- get canBeEdited() {
+ get canBeEdited(): boolean {
const isProtected = this.isProtected && this.getRoot().loadedDefaultData;
if (!isProtected && this.parent != null) {
@@ -167,10 +151,7 @@ export class VirtualBase extends EventEmitter {
}
}
- /**
- * @returns {VirtualRoot}
- */
- getRoot() {
+ getRoot(): VirtualRoot {
const root = this.root ?? this.parent?.getRoot();
if (root === null) {
@@ -180,24 +161,15 @@ export class VirtualBase extends EventEmitter {
return root;
}
- /**
- * @returns {boolean}
- */
- isFile() {
+ isFile(): boolean {
return false;
}
- /**
- * @returns {boolean}
- */
- isFolder() {
+ isFolder(): boolean {
return false;
}
- /**
- * @returns {object | null}
- */
- toJSON() {
+ toJSON(): VirtualBaseJson | null {
const object = {
nam: this.name,
ico: this.iconUrl,
diff --git a/src/features/windows/windowsManager.js b/src/features/windows/windowsManager.ts
similarity index 69%
rename from src/features/windows/windowsManager.js
rename to src/features/windows/windowsManager.ts
index 3fe5c1a..823a4e1 100644
--- a/src/features/windows/windowsManager.js
+++ b/src/features/windows/windowsManager.ts
@@ -1,24 +1,37 @@
-import { TASKBAR_HEIGHT } from "../../config/taskbar.config.js";
-import { SCREEN_MARGIN } from "../../config/windows.config.js";
-import AppsManager from "../apps/appsManager.js";
-import { randomRange } from "../math/random.js";
-import Vector2 from "../math/vector2.js";
-import { TrackingManager } from "../tracking/trackingManager.js";
-import { VirtualFile } from "../virtual-drive/file/virtualFile.js";
+import { TASKBAR_HEIGHT } from "../../config/taskbar.config";
+import { SCREEN_MARGIN } from "../../config/windows.config";
+import App from "../apps/app";
+import AppsManager from "../apps/appsManager";
+import { randomRange } from "../math/random";
+import Vector2 from "../math/vector2";
+import { TrackingManager } from "../tracking/trackingManager";
+import { VirtualFile } from "../virtual-drive/file/virtualFile";
+
+export interface WindowOptions {
+ id?: string;
+ app?: App;
+ size?: Vector2;
+ position?: Vector2;
+ fullscreen?: boolean | string;
+ options?: object;
+ isFocused?: boolean;
+ lastInteraction?: number;
+ minimized?: boolean;
+ [key: string]: any;
+}
export default class WindowsManager {
+ windows: { [id: string]: WindowOptions };
+ updateWindows: Function;
+ startupComplete: boolean;
+
constructor() {
this.windows = {};
this.updateWindows = () => {};
this.startupComplete = false;
}
- /**
- * @param {string} appId
- * @param {object | null} options
- * @returns {object | null}
- */
- open(appId, options) {
+ open(appId: string, options?: WindowOptions | null): object | null {
const app = AppsManager.getAppById(appId);
if (app == null) {
@@ -32,7 +45,7 @@ export default class WindowsManager {
let fullscreen = false;
if (options?.fullscreen) {
- if (typeof(options.fullscreen) == String) {
+ if (typeof(options.fullscreen) == "string") {
fullscreen = options.fullscreen.toLowerCase() === "true";
} else {
fullscreen = options.fullscreen;
@@ -41,7 +54,7 @@ export default class WindowsManager {
delete options.fullscreen;
}
- let id = 0;
+ let id: number | string = 0;
while (this.windowIds.includes(id.toString())) {
id++;
}
@@ -74,21 +87,13 @@ export default class WindowsManager {
// console.log(this);
}
- /**
- * @param {VirtualFile} file
- * @param {object} options
- * @returns {object}
- */
- openFile(file, options = {}) {
+ openFile(file: VirtualFile, options: object = {}): object {
const app = AppsManager.getAppByFileExtension(file?.extension);
if (app != null)
return this.open(app.id, { file, ...options });
}
- /**
- * @param {string} windowId
- */
- close(windowId) {
+ close(windowId: string) {
windowId = windowId.toString();
if (!this.windowIds.includes(windowId)) {
@@ -106,10 +111,7 @@ export default class WindowsManager {
// console.log(this);
}
- /**
- * @param {string} windowId
- */
- focus(windowId) {
+ focus(windowId: string) {
windowId = windowId.toString();
if (!this.windowIds.includes(windowId)) {
@@ -122,7 +124,7 @@ export default class WindowsManager {
window.isFocused = isFocused;
if (isFocused) {
- window.lastInteraction = new Date().valueOf();
+ window.lastInteraction = Date.now().valueOf();
window.minimized = false;
}
});
@@ -130,18 +132,14 @@ export default class WindowsManager {
this.updateWindows(this.windows);
}
- /**
- * @param {string} windowId
- */
- isFocused(windowId) {
+ isFocused(windowId: string) {
return this.windows[windowId].isFocused;
}
/**
- * @param {string} windowId
- * @param {boolean=} minimized
+ * @param minimized - Leave as undefined to toggle the window's minimization state
*/
- setMinimized(windowId, minimized) {
+ setMinimized(windowId: string, minimized?: boolean) {
windowId = windowId.toString();
if (!this.windowIds.includes(windowId)) {
@@ -163,11 +161,7 @@ export default class WindowsManager {
this.updateWindows(this.windows);
}
- /**
- * @param {string} appId
- * @returns {boolean}
- */
- isAppActive(appId) {
+ isAppActive(appId: string): boolean {
let active = false;
Object.values(this.windows).forEach((window) => {
@@ -180,11 +174,7 @@ export default class WindowsManager {
return active;
}
- /**
- * @param {string} appId
- * @returns {string}
- */
- getAppWindowId(appId) {
+ getAppWindowId(appId: string): string {
let windowId = null;
Object.values(this.windows).forEach((window) => {
@@ -197,18 +187,11 @@ export default class WindowsManager {
return windowId;
}
- /**
- * @param {Function} updateWindows
- */
- setUpdateWindows(updateWindows) {
+ setUpdateWindows(updateWindows: Function) {
this.updateWindows = updateWindows;
}
- /**
- * @param {string[]} appIds
- * @param {{}} options
- */
- startup(appIds, options) {
+ startup(appIds: string[], options: {}) {
if (appIds == null || this.startupComplete)
return;
@@ -219,10 +202,7 @@ export default class WindowsManager {
this.startupComplete = true;
}
- /**
- * @returns {string[]}
- */
- get windowIds() {
+ get windowIds(): string[] {
return Object.keys(this.windows);
}
}
\ No newline at end of file
diff --git a/src/features/z-index/zIndexGroup.js b/src/features/z-index/zIndexGroup.js
deleted file mode 100644
index 19cddb1..0000000
--- a/src/features/z-index/zIndexGroup.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { ZIndexManager } from "./zIndexManager.js";
-
-export class ZIndexGroup {
- /** @type {number} */
- length = 0;
-
- /** @type {number} */
- offset = 0;
-
- /** @type {number} */
- groupIndex = 0;
-
- /** @type {ZIndexManager} */
- zIndexManager = null;
-
- /**
- * @param {ZIndexManager} zIndexManager
- * @param {number} initialLength
- */
- constructor(zIndexManager, initialLength) {
- this.setManager(zIndexManager);
- this.setLength(initialLength ?? 0);
- }
-
- /**
- * @param {ZIndexManager} zIndexManager
- * @returns {ZIndexGroup}
- */
- setManager(zIndexManager) {
- this.zIndexManager = zIndexManager;
- return this;
- }
-
- /**
- * @param {number} offset
- * @returns {ZIndexGroup}
- */
- setOffset(offset) {
- this.offset = offset;
- return this;
- }
-
- /**
- * @param {number} length
- * @returns {ZIndexGroup}
- */
- setLength(length) {
- if (this.length === length)
- return;
-
- this.length = length;
- this.zIndexManager.update();
- return this;
- }
-
- /**
- * @param {number} index
- * @returns {number}
- */
- getIndex(index) {
- if (this.length < index + 1) {
- this.setLength(index + 1);
- }
-
- return this.offset + index;
- }
-}
\ No newline at end of file
diff --git a/src/features/z-index/zIndexGroup.ts b/src/features/z-index/zIndexGroup.ts
new file mode 100644
index 0000000..c82a4e8
--- /dev/null
+++ b/src/features/z-index/zIndexGroup.ts
@@ -0,0 +1,40 @@
+import { ZIndexManager } from "./zIndexManager";
+
+export class ZIndexGroup {
+ length: number = 0;
+ offset: number = 0;
+ groupIndex: number = 0;
+ zIndexManager: ZIndexManager = null;
+
+ constructor(zIndexManager: ZIndexManager, initialLength?: number) {
+ this.setManager(zIndexManager);
+ this.setLength(initialLength ?? 0);
+ }
+
+ setManager(zIndexManager: ZIndexManager): ZIndexGroup {
+ this.zIndexManager = zIndexManager;
+ return this;
+ }
+
+ setOffset(offset: number): ZIndexGroup {
+ this.offset = offset;
+ return this;
+ }
+
+ setLength(length: number): ZIndexGroup {
+ if (this.length === length)
+ return;
+
+ this.length = length;
+ this.zIndexManager.update();
+ return this;
+ }
+
+ getIndex(index: number): number {
+ if (this.length < index + 1) {
+ this.setLength(index + 1);
+ }
+
+ return this.offset + index;
+ }
+}
\ No newline at end of file
diff --git a/src/features/z-index/zIndexManager.js b/src/features/z-index/zIndexManager.ts
similarity index 66%
rename from src/features/z-index/zIndexManager.js
rename to src/features/z-index/zIndexManager.ts
index 2c7cd82..ef7ce1f 100644
--- a/src/features/z-index/zIndexManager.js
+++ b/src/features/z-index/zIndexManager.ts
@@ -1,16 +1,18 @@
-import { EventEmitter } from "../_utils/event.utils.js";
-import { ZIndexGroup } from "./zIndexGroup.js";
+import { EventEmitter } from "../_utils/event.utils";
+import { ZIndexGroup } from "./zIndexGroup";
-export class ZIndexManager extends EventEmitter {
+const ZIndexManagerEvents = {
+ indexChange: "indexChange",
+} as const;
+
+export class ZIndexManager extends EventEmitter {
static GROUPS = {
WINDOWS: 0,
TASKBAR: 1,
MODALS: 2,
};
- static EVENT_NAMES = {
- INDEX_CHANGE: "indexchange"
- };
+ static EVENT_NAMES = ZIndexManagerEvents;
/** @type {ZIndexGroup[]} */
groups = [];
@@ -35,7 +37,7 @@ export class ZIndexManager extends EventEmitter {
offset += group.length;
}
if (changed) {
- this.emit(ZIndexManager.EVENT_NAMES.INDEX_CHANGE);
+ this.emit("indexChange");
}
}
diff --git a/src/hooks/_utils/history.js b/src/hooks/_utils/history.ts
similarity index 95%
rename from src/hooks/_utils/history.js
rename to src/hooks/_utils/history.ts
index 623ec02..5b9979e 100644
--- a/src/hooks/_utils/history.js
+++ b/src/hooks/_utils/history.ts
@@ -1,5 +1,5 @@
import { useState } from "react";
-import { clamp } from "../../features/math/clamp.js";
+import { clamp } from "../../features/math/clamp";
/**
* @param {*} initialState
diff --git a/src/hooks/_utils/keyboard.js b/src/hooks/_utils/keyboard.ts
similarity index 75%
rename from src/hooks/_utils/keyboard.js
rename to src/hooks/_utils/keyboard.ts
index 024751e..a5e0829 100644
--- a/src/hooks/_utils/keyboard.js
+++ b/src/hooks/_utils/keyboard.ts
@@ -1,12 +1,12 @@
import { useCallback, useEffect, useState } from "react";
-import { removeFromArray } from "../../features/_utils/array.utils.js";
+import { removeFromArray } from "../../features/_utils/array.utils";
-/**
- * @param {object} params
- * @param {Function} params.onKeyDown
- * @param {Function} params.onKeyUp
- */
-export function useKeyboardListener({ onKeyDown, onKeyUp }) {
+interface UseKeyboardListenerParams {
+ onKeyDown?: (event: KeyboardEvent) => void;
+ onKeyUp?: (event: KeyboardEvent) => void;
+};
+
+export function useKeyboardListener({ onKeyDown, onKeyUp }: UseKeyboardListenerParams) {
useEffect(() => {
if (onKeyDown)
document.addEventListener("keydown", onKeyDown);
@@ -22,13 +22,13 @@ export function useKeyboardListener({ onKeyDown, onKeyUp }) {
}, [onKeyDown, onKeyUp]);
}
-/**
- * @param {object} props
- * @param {Object>} props.options
- * @param {Object>} props.shortcuts
- * @param {boolean} props.useCategories
- */
-export function useShortcuts({ options, shortcuts, useCategories = true }) {
+interface UseShortcutsParams {
+ options: Record> | Record;
+ shortcuts?: Record> | Record;
+ useCategories?: boolean,
+}
+
+export function useShortcuts({ options, shortcuts, useCategories = true }: UseShortcutsParams) {
const [activeKeys, setActiveKeys] = useState([]);
const checkShortcuts = useCallback((event, allowExecution = true) => {
@@ -41,7 +41,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }) {
if (keys.includes("Alt") && !event.altKey)
removeFromArray("Alt", keys);
- const checkGroup = (group, category) => {
+ const checkGroup = (group: Record, category?) => {
for (const [name, shortcut] of Object.entries(group)) {
let active = true;
@@ -62,7 +62,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }) {
if (category != null) {
options?.[category]?.[name]?.();
} else {
- options?.[name]?.();
+ (options?.[name] as Function)?.();
}
}
};
@@ -72,7 +72,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }) {
checkGroup(group, category);
}
} else {
- checkGroup(shortcuts);
+ checkGroup(shortcuts as Record);
}
setActiveKeys(keys);
diff --git a/src/hooks/_utils/mouse.js b/src/hooks/_utils/mouse.ts
similarity index 100%
rename from src/hooks/_utils/mouse.js
rename to src/hooks/_utils/mouse.ts
diff --git a/src/hooks/_utils/outsideClick.js b/src/hooks/_utils/outsideClick.tsx
similarity index 54%
rename from src/hooks/_utils/outsideClick.js
rename to src/hooks/_utils/outsideClick.tsx
index 68a61cd..1988db4 100644
--- a/src/hooks/_utils/outsideClick.js
+++ b/src/hooks/_utils/outsideClick.tsx
@@ -1,13 +1,13 @@
+import { useRef, useEffect, memo, ReactNode } from "react";
+
/**
* https://stackoverflow.com/a/42234988
*/
-import { useRef, useEffect, memo } from "react";
-
-function useOutsideClickListener(ref, callback) {
+function useOutsideClickListener(ref: { current: HTMLElement | null }, callback: (event: Event) => void) {
useEffect(() => {
- const handleClickOutside = (event) => {
- if (ref.current && !ref.current.contains(event.target)) {
+ const handleClickOutside = (event: Event) => {
+ if (ref.current && !ref.current.contains(event.target as HTMLElement)) {
callback(event);
}
};
@@ -25,7 +25,13 @@ function useOutsideClickListener(ref, callback) {
* @param {Function} props.onOutsideClick
* @param {import("react").ElementType} props.children
*/
-const OutsideClickListener = memo(({ onOutsideClick, children }) => {
+
+interface OutsideClickListenerProps {
+ onOutsideClick: (event: Event) => void;
+ children: ReactNode;
+}
+
+const OutsideClickListener = memo(({ onOutsideClick, children }: OutsideClickListenerProps) => {
const wrapperRef = useRef(null);
useOutsideClickListener(wrapperRef, onOutsideClick);
diff --git a/src/hooks/_utils/screen.js b/src/hooks/_utils/screen.ts
similarity index 96%
rename from src/hooks/_utils/screen.js
rename to src/hooks/_utils/screen.ts
index c442c8b..20285fc 100644
--- a/src/hooks/_utils/screen.js
+++ b/src/hooks/_utils/screen.ts
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
-import { TASKBAR_HEIGHT } from "../../config/taskbar.config.js";
+import { TASKBAR_HEIGHT } from "../../config/taskbar.config";
/**
* @returns {[number, number]}
diff --git a/src/hooks/_utils/scrollWithShadows.js b/src/hooks/_utils/scrollWithShadows.ts
similarity index 98%
rename from src/hooks/_utils/scrollWithShadows.js
rename to src/hooks/_utils/scrollWithShadows.ts
index 3316fee..366ab14 100644
--- a/src/hooks/_utils/scrollWithShadows.js
+++ b/src/hooks/_utils/scrollWithShadows.ts
@@ -3,7 +3,7 @@
*/
-import React, { useCallback, useEffect } from "react";
+import { useCallback, useEffect } from "react";
import { useState } from "react";
/**
diff --git a/src/hooks/modals/alert.js b/src/hooks/modals/alert.tsx
similarity index 65%
rename from src/hooks/modals/alert.js
rename to src/hooks/modals/alert.tsx
index 4a11333..dce7aeb 100644
--- a/src/hooks/modals/alert.js
+++ b/src/hooks/modals/alert.tsx
@@ -1,24 +1,21 @@
import { useCallback } from "react";
-import { DialogBox } from "../../components/modals/dialog-box/DialogBox.jsx";
-import { DIALOG_CONTENT_TYPES } from "../../config/modals.config.js";
-import Vector2 from "../../features/math/vector2.js";
-import { useWindowedModal } from "./windowedModal.js";
+import { DialogBox } from "../../components/modals/dialog-box/DialogBox";
+import { DIALOG_CONTENT_TYPES } from "../../config/modals.config";
+import Vector2 from "../../features/math/vector2";
+import { useWindowedModal } from "./windowedModal";
-/**
- * @typedef alertType
- * @param {object} options
- * @param {string} options.title
- * @param {string} options.text
- * @param {string} options.iconUrl
- */
+interface AlertParams {
+ title: string;
+ text: string;
+ iconUrl: string;
+ size?: Vector2;
+ single?: boolean;
+}
-/**
- * @returns {{ alert: alertType }}
- */
export function useAlert() {
const { openWindowedModal } = useWindowedModal();
- const alert = useCallback(({ title, text, iconUrl, size, single }) => {
+ const alert = useCallback(({ title, text, iconUrl, size, single }: AlertParams) => {
openWindowedModal({
title: title ?? "Alert",
iconUrl,
diff --git a/src/hooks/modals/contextMenu.js b/src/hooks/modals/contextMenu.tsx
similarity index 69%
rename from src/hooks/modals/contextMenu.js
rename to src/hooks/modals/contextMenu.tsx
index 85daea8..c832aa8 100644
--- a/src/hooks/modals/contextMenu.js
+++ b/src/hooks/modals/contextMenu.tsx
@@ -1,8 +1,9 @@
-import { useCallback } from "react";
-import Vector2 from "../../features/math/vector2.js";
-import Modal from "../../features/modals/modal.js";
-import { STYLES } from "../../components/actions/Actions.jsx";
+import { FC, useCallback } from "react";
+import Vector2 from "../../features/math/vector2";
+import Modal from "../../features/modals/modal";
+import { ActionsProps, STYLES } from "../../components/actions/Actions";
import { useModalsManager } from "./modalsManagerContext";
+import { ModalProps } from "../../components/modals/ModalView";
/**
* @callback onContextMenuType
@@ -19,7 +20,12 @@ import { useModalsManager } from "./modalsManagerContext";
* ShortcutsListener: import("../../components/actions/Actions.jsx").actionsType
* }}
*/
-export function useContextMenu({ Actions }) {
+
+interface UseContextMenuParams {
+ Actions: FC;
+}
+
+export function useContextMenu({ Actions }: UseContextMenuParams) {
const modalsManager = useModalsManager();
// Open a new modal when context menu is triggered
@@ -36,7 +42,7 @@ export function useContextMenu({ Actions }) {
positionY -= containerRect.y / 2;
}
- const newModal = new Modal(Actions)
+ const newModal = new Modal(Actions as unknown as FC)
.setPosition(new Vector2(positionX, positionY))
.setProps({
triggerParams: params,
@@ -50,7 +56,7 @@ export function useContextMenu({ Actions }) {
return newModal;
}, [Actions, modalsManager]);
- const ShortcutsListener = () => <>>;
+ const ShortcutsListener = () => ;
return { onContextMenu, ShortcutsListener };
}
\ No newline at end of file
diff --git a/src/hooks/modals/modalsContext.tsx b/src/hooks/modals/modalsContext.tsx
index a5ba3a4..77d21d9 100644
--- a/src/hooks/modals/modalsContext.tsx
+++ b/src/hooks/modals/modalsContext.tsx
@@ -1,6 +1,6 @@
-import React, { createContext, FC, ReactNode, useCallback, useContext, useState } from "react";
-import Modal from "../../features/modals/modal.js";
-import ModalsManager from "../../features/modals/modalsManager.js";
+import { createContext, FC, ReactNode, useCallback, useContext, useState } from "react";
+import Modal from "../../features/modals/modal";
+import ModalsManager from "../../features/modals/modalsManager";
type ModalsState = Modal[] | undefined;
diff --git a/src/hooks/modals/modalsManagerContext.tsx b/src/hooks/modals/modalsManagerContext.tsx
index 0c3e287..66914e8 100644
--- a/src/hooks/modals/modalsManagerContext.tsx
+++ b/src/hooks/modals/modalsManagerContext.tsx
@@ -1,5 +1,5 @@
-import React, { createContext, FC, ReactNode, useContext } from "react";
-import ModalsManager from "../../features/modals/modalsManager.js";
+import { createContext, FC, ReactNode, useContext } from "react";
+import ModalsManager from "../../features/modals/modalsManager";
import { ModalsProvider } from "./modalsContext";
type ModalsManagerState = ModalsManager | undefined;
diff --git a/src/hooks/modals/windowedModal.js b/src/hooks/modals/windowedModal.js
deleted file mode 100644
index b2dcee6..0000000
--- a/src/hooks/modals/windowedModal.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { useCallback } from "react";
-import Modal from "../../features/modals/modal.js";
-import Vector2 from "../../features/math/vector2.js";
-import { DEFAULT_DIALOG_SIZE } from "../../config/modals.config.js";
-import { useModalsManager } from "./modalsManagerContext";
-
-/**
- * @callback windowedModalType
- * @param {object} props
- */
-
-/**
- * @callback openWindowedModalType
- * @param {object} params
- * @param {string} params.iconUrl
- * @param {string} params.title
- * @param {Vector2} params.size
- * @param {windowedModalType} params.Modal
- * @returns {Modal}
- */
-
-/**
- * @returns {{ openWindowedModal: openWindowedModalType }}
- */
-export function useWindowedModal() {
- const modalsManager = useModalsManager();
-
- const openWindowedModal = useCallback(({ Modal: WindowedModal, ...params }) => {
- const size = params.size ?? DEFAULT_DIALOG_SIZE;
- let positionX = (window.innerWidth - size.x) / 4;
- let positionY = (window.innerHeight - size.y) / 4;
-
- if (modalsManager.containerRef?.current) {
- const containerRect = modalsManager.containerRef.current.getBoundingClientRect();
- positionX -= containerRect.x / 2;
- positionY -= containerRect.y / 2;
- }
-
- const newModal = new Modal(WindowedModal)
- .setPosition(new Vector2(positionX, positionY))
- .setSize(size)
- .setDismissible(false)
- .setProps({ params });
-
- const single = params.single ?? false;
-
- modalsManager.open(newModal, single);
- return newModal;
- }, [modalsManager]);
-
- return { openWindowedModal };
-}
\ No newline at end of file
diff --git a/src/hooks/modals/windowedModal.ts b/src/hooks/modals/windowedModal.ts
new file mode 100644
index 0000000..d3312a3
--- /dev/null
+++ b/src/hooks/modals/windowedModal.ts
@@ -0,0 +1,46 @@
+import { FC, useCallback } from "react";
+import Modal from "../../features/modals/modal";
+import Vector2 from "../../features/math/vector2";
+import { DEFAULT_DIALOG_SIZE } from "../../config/modals.config";
+import { useModalsManager } from "./modalsManagerContext";
+import { ModalProps } from "../../components/modals/ModalView";
+
+interface OpenWindowedModalParams {
+ appId?: string;
+ iconUrl?: string;
+ title?: string;
+ size: Vector2;
+ Modal: Function;
+ single?: boolean;
+ fullscreen?: boolean;
+}
+type OpenWindowedModal = (params: OpenWindowedModalParams) => Modal;
+
+export function useWindowedModal(): { openWindowedModal: OpenWindowedModal; } {
+ const modalsManager = useModalsManager();
+
+ const openWindowedModal = useCallback(({ Modal: WindowedModal, ...params }) => {
+ const size = params.size ?? DEFAULT_DIALOG_SIZE;
+ let positionX = (window.innerWidth - size.x) / 4;
+ let positionY = (window.innerHeight - size.y) / 4;
+
+ if (modalsManager.containerRef?.current) {
+ const containerRect = modalsManager.containerRef.current.getBoundingClientRect();
+ positionX -= containerRect.x / 2;
+ positionY -= containerRect.y / 2;
+ }
+
+ const newModal = new Modal(WindowedModal as FC)
+ .setPosition(new Vector2(positionX, positionY))
+ .setSize(size)
+ .setDismissible(false)
+ .setProps({ params });
+
+ const single = params.single ?? false;
+
+ modalsManager.open(newModal, single);
+ return newModal;
+ }, [modalsManager]);
+
+ return { openWindowedModal };
+}
\ No newline at end of file
diff --git a/src/hooks/settings/settingsManagerContext.tsx b/src/hooks/settings/settingsManagerContext.tsx
index dfadbf3..23de28f 100644
--- a/src/hooks/settings/settingsManagerContext.tsx
+++ b/src/hooks/settings/settingsManagerContext.tsx
@@ -1,7 +1,7 @@
-import React, { createContext, FC, ReactNode, useContext } from "react";
-import { SettingsManager } from "../../features/settings/settingsManager.js";
+import { createContext, FC, ReactNode, useContext } from "react";
+import { SettingsManager } from "../../features/settings/settingsManager";
import { useVirtualRoot } from "../virtual-drive/virtualRootContext";
-import { VirtualRoot } from "../../features/virtual-drive/root/virtualRoot.js";
+import { VirtualRoot } from "../../features/virtual-drive/root/virtualRoot";
type SettingsManagerState = SettingsManager | undefined;
diff --git a/src/hooks/virtual-drive/virtualRootContext.tsx b/src/hooks/virtual-drive/virtualRootContext.tsx
index a6830ad..08ab673 100644
--- a/src/hooks/virtual-drive/virtualRootContext.tsx
+++ b/src/hooks/virtual-drive/virtualRootContext.tsx
@@ -1,5 +1,5 @@
-import React, { createContext, useContext, FC, ReactNode } from "react";
-import { VirtualRoot } from "../../features/virtual-drive/root/virtualRoot.js";
+import { createContext, useContext, FC, ReactNode } from "react";
+import { VirtualRoot } from "../../features/virtual-drive/root/virtualRoot";
const VirtualRootContext = createContext(undefined);
diff --git a/src/hooks/windows/windowsContext.tsx b/src/hooks/windows/windowsContext.tsx
index b8482c0..92918dd 100644
--- a/src/hooks/windows/windowsContext.tsx
+++ b/src/hooks/windows/windowsContext.tsx
@@ -1,14 +1,15 @@
-import React, { createContext, FC, ReactNode, useCallback, useContext, useState } from "react";
+import { createContext, FC, ReactNode, useCallback, useContext, useState } from "react";
import WindowsManager from "../../features/windows/windowsManager";
+import { WindowProps } from "../../components/windows/WindowView";
-type WindowsState = object[] | undefined;
+type WindowsState = WindowProps[] | undefined;
const WindowsContext = createContext(undefined);
export const WindowsProvider: FC<{ children: ReactNode, windowsManager: WindowsManager }> = ({ children, windowsManager }) => {
const [windows, setWindows] = useState([]);
- const updateWindows = useCallback((updatedWindows: Record) => {
+ const updateWindows = useCallback((updatedWindows: Record) => {
setWindows(Object.values(updatedWindows));
}, []);
diff --git a/src/hooks/windows/windowsManagerContext.tsx b/src/hooks/windows/windowsManagerContext.tsx
index 504196a..2783e22 100644
--- a/src/hooks/windows/windowsManagerContext.tsx
+++ b/src/hooks/windows/windowsManagerContext.tsx
@@ -1,5 +1,5 @@
-import React, { createContext, FC, ReactNode, useContext } from "react";
-import WindowsManager from "../../features/windows/windowsManager.js";
+import { createContext, FC, ReactNode, useContext } from "react";
+import WindowsManager from "../../features/windows/windowsManager";
import { WindowsProvider } from "./windowsContext";
type WindowsManagerState = WindowsManager | undefined;
diff --git a/src/hooks/z-index/zIndex.js b/src/hooks/z-index/zIndex.ts
similarity index 80%
rename from src/hooks/z-index/zIndex.js
rename to src/hooks/z-index/zIndex.ts
index 5dfe4cd..4854dcf 100644
--- a/src/hooks/z-index/zIndex.js
+++ b/src/hooks/z-index/zIndex.ts
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { useZIndexManager } from "./zIndexManagerContext";
-import { ZIndexManager } from "../../features/z-index/zIndexManager.js";
+import { ZIndexManager } from "../../features/z-index/zIndexManager";
export function useZIndex({ groupIndex, index }) {
const initialIndex = (groupIndex * 10) + index;
@@ -16,10 +16,10 @@ export function useZIndex({ groupIndex, index }) {
};
updateIndex();
- zIndexManager.on(ZIndexManager.EVENT_NAMES.INDEX_CHANGE, updateIndex);
+ zIndexManager.on(ZIndexManager.EVENT_NAMES.indexChange, updateIndex);
return () => {
- zIndexManager.off(ZIndexManager.EVENT_NAMES.INDEX_CHANGE, updateIndex);
+ zIndexManager.off(ZIndexManager.EVENT_NAMES.indexChange, updateIndex);
};
}, [groupIndex, index, zIndex, zIndexManager]);
diff --git a/src/hooks/z-index/zIndexManagerContext.tsx b/src/hooks/z-index/zIndexManagerContext.tsx
index 1797763..924f3c0 100644
--- a/src/hooks/z-index/zIndexManagerContext.tsx
+++ b/src/hooks/z-index/zIndexManagerContext.tsx
@@ -1,5 +1,5 @@
-import React, { createContext, FC, ReactNode, useContext } from "react";
-import { ZIndexManager } from "../../features/z-index/zIndexManager.js";
+import { createContext, FC, ReactNode, useContext } from "react";
+import { ZIndexManager } from "../../features/z-index/zIndexManager";
type ZIndexManagerState = ZIndexManager | undefined;
diff --git a/src/index.tsx b/src/index.tsx
index c7aaf45..a96201a 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -2,8 +2,9 @@ import React from "react";
import ReactDOM from "react-dom/client";
import "./styles/global.css";
import App from "./App";
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
import reportWebVitals from "./reportWebVitals";
-import { ASCII_LOGO, NAME } from "./config/branding.config.js";
+import { ASCII_LOGO, NAME } from "./config/branding.config";
export const START_DATE = new Date();
@@ -22,4 +23,4 @@ console.info(ASCII_LOGO + space + welcomeMessage);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
\ No newline at end of file
+// reportWebVitals(console.log);
\ No newline at end of file
diff --git a/src/reportWebVitals.js b/src/reportWebVitals.ts
similarity index 100%
rename from src/reportWebVitals.js
rename to src/reportWebVitals.ts
diff --git a/src/setupTests.js b/src/setupTests.ts
similarity index 100%
rename from src/setupTests.js
rename to src/setupTests.ts
diff --git a/src/styles/global.css b/src/styles/global.css
index 4a9232c..1182bb2 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -24,6 +24,7 @@ body {
*, :after, :before {
color: var(--foreground-color-a);
+ font-size: 1rem;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
text-rendering: optimizelegibility;
diff --git a/tsconfig.json b/tsconfig.json
index c4450b0..1044570 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,7 +13,7 @@
/* Language and Environment */
"target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
- "jsx": "react", /* Specify what JSX code is generated. */
+ "jsx": "react-jsx", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
@@ -33,7 +33,7 @@
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
"types": ["webpack-env"], /* Specify type package names to be included without being referenced in a source file. */
- // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */