diff --git a/.npmrc b/.npmrc
new file mode 100644
index 000000000..eb1908282
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,5 @@
+# pnpm-related options
+shamefully-hoist=true
+strict-peer-dependencies=false
+# to get the latest compatible packages when creating the project https://github.com/pnpm/pnpm/issues/6463
+resolution-mode=highest
diff --git a/.postcssrc.js b/.postcssrc.js
deleted file mode 100644
index 1174fe52b..000000000
--- a/.postcssrc.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// https://github.com/michael-ciniawsky/postcss-load-config
-
-module.exports = {
- plugins: [
- // to edit target browsers: use "browserslist" field in package.json
- require('autoprefixer')
- ]
-}
diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index 90ff9bb4b..000000000
--- a/.prettierrc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "singleQuote": true,
- "semi": true
-}
\ No newline at end of file
diff --git a/.space.kts b/.space.kts
deleted file mode 100644
index e52385f37..000000000
--- a/.space.kts
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
-* JetBrains Space Automation
-* This Kotlin-script file lets you automate build activities
-* For more info, see https://www.jetbrains.com/help/space/automation.html
-*/
-
-job("Run npm test and publish") {
- container(displayName = "Run tests", image = "node:14-alpine") {
- env["REGISTRY"] = "https://registry.npmjs.org"
- shellScript {
- interpreter = "/bin/sh"
- content = """
- echo Install npm dependencies...
- npm install
- echo Run tests...
- npm run test
- """
- }
- }
-}
diff --git a/.stylintrc b/.stylintrc
deleted file mode 100644
index de984f6fd..000000000
--- a/.stylintrc
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "blocks": "never",
- "brackets": "never",
- "colons": "never",
- "colors": "always",
- "commaSpace": "always",
- "commentSpace": "always",
- "cssLiteral": "never",
- "depthLimit": false,
- "duplicates": true,
- "efficient": "always",
- "extendPref": false,
- "globalDupe": true,
- "indentPref": 4,
- "leadingZero": "never",
- "maxErrors": false,
- "maxWarnings": false,
- "mixed": false,
- "namingConvention": false,
- "namingConventionStrict": false,
- "none": "never",
- "noImportant": false,
- "parenSpace": "never",
- "placeholder": false,
- "prefixVarsWithDollar": "always",
- "quotePref": "single",
- "semicolons": "always",
- "sortOrder": false,
- "stackedProperties": "never",
- "trailingWhitespace": "never",
- "universal": "never",
- "valid": true,
- "zeroUnits": "never",
- "zIndexNormalize": false
-}
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 6d506e0af..000000000
--- a/babel.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* eslint-env node */
-// eslint-disable-next-line @typescript-eslint/no-var-requires
-
-module.exports = {
- presets: ['@quasar/babel-preset-app']
-};
diff --git a/index.html b/index.html
new file mode 100644
index 000000000..3c8c78f00
--- /dev/null
+++ b/index.html
@@ -0,0 +1,21 @@
+
+
+
+ <%= productName %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index 54c9b0155..000000000
--- a/jest.config.js
+++ /dev/null
@@ -1,82 +0,0 @@
-const esModules = ['quasar/lang', 'lodash-es'].join('|');
-
-/* eslint-env node */
-module.exports = {
- globals: {
- __DEV__: true,
- // TODO: Remove if resolved natively https://github.com/vuejs/vue-jest/issues/175
- 'vue-jest': {
- pug: { doctype: 'html' }
- }
- },
- testEnvironmentOptions: {
- url: 'http://localhost/',
- },
- testEnvironment: 'jsdom',
- testURL: 'http://localhost/',
- setupFilesAfterEnv: ['/test/jest/jest.setup.ts'],
- // noStackTrace: true,
- // bail: true,
- // cache: false,
- // verbose: true,
- // watch: true,
- collectCoverage: false,
- coverageDirectory: '/test/jest/coverage',
- collectCoverageFrom: [
- '/src/**/*.vue',
- '/src/**/*.js',
- '/src/**/*.ts',
- '/src/**/*.jsx',
- '/src/**/*.tsx'
- ],
- coveragePathIgnorePatterns: ['/node_modules/', '.d.ts$'],
- coverageThreshold: {
- global: {
- // branches: 50,
- // functions: 50,
- // lines: 50,
- // statements: 50
- }
- },
- testMatch: [
- // Matches tests in any subfolder of 'src' or into 'test/jest/__tests__'
- // Matches all files with extension 'js', 'jsx', 'ts' and 'tsx'
- '/test/jest/__tests__/**/*.(spec|test).+(ts|js)?(x)',
- '/src/**/*.jest.(spec|test).+(ts|js)?(x)'
- ],
- // Extension-less imports of components are resolved to .ts files by TS,
- // grating correct type-checking in test files.
- // Being 'vue' the first moduleFileExtension option, the very same imports
- // will be resolved to .vue files by Jest, if both .vue and .ts files are
- // in the same folder.
- // This guarantee a great dev experience both for testing and type-checking.
- // See https://github.com/vuejs/vue-jest/issues/188#issuecomment-620750728
- moduleFileExtensions: ['vue', 'js', 'jsx', 'json', 'ts', 'tsx'],
- moduleNameMapper: {
- '^quasar$': 'quasar/dist/quasar.common.js',
- '^~/(.*)$': '/$1',
- '^src/(.*)$': '/src/$1',
- '^app/(.*)$': '/$1',
- '^components/(.*)$': '/src/components/$1',
- '^layouts/(.*)$': '/src/layouts/$1',
- '^pages/(.*)$': '/src/pages/$1',
- '^assets/(.*)$': '/src/assets/$1',
- '^boot/(.*)$': '/src/boot/$1',
- '.*css$': '/test/jest/__tests__/__stub_module_files__/style.js'
- },
- transform: {
- // See https://jestjs.io/docs/en/configuration.html#transformignorepatterns-array-string
- [`^(${esModules}).+\\.js$`]: 'babel-jest',
- '^.+\\.(ts|js|html)$': 'ts-jest',
- '^.+\\.(ts|js)$': 'babel-jest',
- // vue-jest uses find-babel-file, which searches by this order:
- // (async) .babelrc, .babelrc.js, package.json, babel.config.js
- // (sync) .babelrc, .babelrc.js, babel.config.js, package.json
- // https://github.com/tleunen/find-babel-config/issues/33
- '.*\\.vue$': 'vue-jest',
- '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
- 'jest-transform-stub'
- },
- transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
- snapshotSerializers: ['/node_modules/jest-serializer-vue']
-};
diff --git a/package.json b/package.json
index 1733ad7cf..2bfb9b0fe 100644
--- a/package.json
+++ b/package.json
@@ -1,139 +1,125 @@
{
- "name": "r2modman",
- "version": "3.2.3",
- "description": "A simple and easy to use mod manager for many games using Thunderstore.",
- "productName": "r2modman",
- "author": "ebkr",
- "private": true,
- "license": "MIT",
- "scripts": {
- "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
- "run": "quasar dev -m electron --modern",
- "sync": "ts-node ./scripts/sync.ts",
- "build-win": "quasar build --mode electron -T win32",
- "build-linux": "quasar build --mode electron -T linux",
- "build-osx": "quasar build --mode electron -T mac",
- "publish": "quasar build --mode electron --publish always",
- "publish-win": "quasar build --mode electron -T win32 --publish always",
- "publish-linux": "quasar build --mode electron -T linux --publish always",
- "test:unit": "jest --updateSnapshot",
- "test:unit:ci": "jest --ci",
- "test:unit:coverage": "jest --coverage",
- "test:unit:watch": "jest --watch",
- "test:unit:watchAll": "jest --watchAll",
- "serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
- "concurrently:dev:jest": "concurrently \"quasar dev -m electron --modern\" \"jest --watch\"",
- "test:unit:ui": "majestic"
- },
- "dependencies": {
- "@node-steam/vdf": "^2.1.0",
- "@quasar/extras": "^1.0.0",
- "adm-zip": "^0.5.5",
- "ajv": "^8.17.1",
- "ajv-formats": "^3.0.1",
- "async-lock": "^1.2.6",
- "axios": "^0.24.0",
- "bulma": "^0.9.4",
- "bulma-checkradio": "^1.1.1",
- "bulma-divider": "^0.2.0",
- "bulma-slider": "2.0.4",
- "bulma-steps": "^2.2.1",
- "bulma-switch": "^2.0.0",
- "core-js": "^3.6.5",
- "dexie": "^3.2.7",
- "dot-prop": "^5.2.0",
- "electron-updater": "4.2.5",
- "elliptic": "^6.5.4",
- "fflate": "^0.8.2",
- "floating-vue": "^1.0.0-beta.19",
- "fs-extra": "^8.1.0",
- "github-markdown-css": "^5.7.0",
- "glob-parent": "^6.0.2",
- "highlight.js": "^10.4.1",
- "lodash.debounce": "^4.0.8",
- "modern-normalize": "^3.0.1",
- "moment": "^2.29.1",
- "node-ipc": "^9.1.1",
- "quasar": "^1.14.7",
- "quill": "^1.3.7",
- "sanitize-filename": "^1.6.3",
- "serialize-javascript": "^3.1.0",
- "tar": "^6.1.11",
- "trim-newlines": "^4.0.2",
- "unzipper": "^0.10.5",
- "uuid-js": "^0.7.5",
- "vue-i18n": "^8.0.0",
- "vuedraggable": "^2.24.3",
- "yaml": "^1.7.2"
- },
- "devDependencies": {
- "@babel/core": "^7.4.0",
- "@babel/preset-typescript": "^7.14.5",
- "@quasar/app": "^2.0.9",
- "@quasar/quasar-app-extension-testing": "^1.0.3",
- "@quasar/quasar-app-extension-testing-unit-jest": "^2.2.2",
- "@quasar/quasar-app-extension-typescript": "^1.0.2",
- "@types/adm-zip": "^0.4.34",
- "@types/async-lock": "^1.1.2",
- "@types/chai": "^4.2.11",
- "@types/fs-extra": "^8.0.1",
- "@types/jsdom": "^21.1.7",
- "@types/lodash.debounce": "^4.0.7",
- "@types/node": "^12.12.12",
- "@types/quill": "^2.0.3",
- "@types/sinon": "^10.0.2",
- "@types/unzipper": "^0.10.1",
- "@types/yaml": "^1.2.0",
- "@typescript-eslint/eslint-plugin": "^1.12.0",
- "@typescript-eslint/parser": "^1.12.0",
- "@vue/eslint-config-airbnb": "^4.0.0",
- "@vue/test-utils": "^1.3.6",
- "babel-core": "^7.0.0-beta.3",
- "babel-eslint": "^10.0.1",
- "babel-jest": "^27.0.2",
- "chai": "^4.2.0",
- "devtron": "^1.4.0",
- "electron": "^24.0.0",
- "electron-builder": "^24.10.5",
- "electron-debug": "^3.0.1",
- "electron-devtools-installer": "^3.0.0",
- "electron-packager": "14.1.1",
- "eslint": "^6.8.0",
- "eslint-config-prettier": "^6.0.0",
- "eslint-loader": "^2.1.1",
- "eslint-plugin-jest": "^24.1.0",
- "eslint-plugin-vue": "^5.0.0",
- "identity-obj-proxy": "^3.0.0",
- "jest": "^27.5.1",
- "jsdom": "^25.0.1",
- "majestic": "^1.2.24",
- "minimist": "^1.2.2",
- "mock-require": "^3.0.3",
- "quicktype-core": "^23.0.171",
- "sass": "^1.70.0",
- "sass-loader": "^10.2.1",
- "sinon": "^11.1.1",
- "ts-jest": "^29.2.5",
- "ts-node": "^8.10.2",
- "typescript": "^4.5.5",
- "vue": "2.7.16",
- "vue-jest": "^3.0.0",
- "wallaby-vue-compiler": "^1.0.3"
- },
- "browserslist": [
- "last 10 Chrome versions",
- "last 10 Firefox versions",
- "last 4 Edge versions",
- "last 7 Safari versions",
- "last 8 Android versions",
- "last 8 ChromeAndroid versions",
- "last 8 FirefoxAndroid versions",
- "last 10 iOS versions",
- "last 5 Opera versions"
- ],
- "engines": {
- "node": ">= 18.0.0",
- "npm": ">= 10.0.0",
- "yarn": ">= 1.21.1"
- }
+ "name": "r2modman",
+ "version": "3.2.1",
+ "description": "A simple and easy to use mod manager for many games using Thunderstore.",
+ "productName": "r2modman",
+ "author": "ebkr",
+ "private": true,
+ "license": "MIT",
+ "type": "module",
+ "scripts": {
+ "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
+ "run": "quasar dev -m electron --modern",
+ "dev": "quasar dev -m electron --modern --devtools",
+ "sync": "ts-node ./scripts/sync.ts",
+ "build-win": "quasar build --mode electron -T win32",
+ "build-linux": "quasar build --mode electron -T linux",
+ "build-osx": "quasar build --mode electron -T mac",
+ "publish": "quasar build --mode electron --publish always",
+ "publish-win": "quasar build --mode electron -T win32 --publish always",
+ "publish-linux": "quasar build --mode electron -T linux --publish always",
+ "test:unit": "jest",
+ "test:unit:ci": "jest --ci",
+ "test:unit:coverage": "jest --coverage",
+ "test:unit:watch": "jest --watch",
+ "test:unit:watchAll": "jest --watchAll",
+ "serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
+ "concurrently:dev:jest": "concurrently \"quasar dev -m electron --modern\" \"jest --watch\"",
+ "test:unit:ui": "majestic"
+ },
+ "dependencies": {
+ "@node-steam/vdf": "^2.1.0",
+ "@quasar/extras": "^1.17.0",
+ "adm-zip": "^0.5.5",
+ "ajv": "^8.17.1",
+ "ajv-formats": "^3.0.1",
+ "async-lock": "^1.2.6",
+ "axios": "^0.24.0",
+ "bulma": "^0.9.4",
+ "bulma-checkradio": "^1.1.1",
+ "bulma-divider": "^0.2.0",
+ "bulma-slider": "2.0.4",
+ "bulma-steps": "^2.2.1",
+ "bulma-switch": "^2.0.0",
+ "core-js": "^3.6.5",
+ "dexie": "^3.2.7",
+ "dot-prop": "^5.2.0",
+ "electron-updater": "4.2.5",
+ "elliptic": "^6.5.4",
+ "fflate": "^0.8.2",
+ "floating-vue": "5.2.2",
+ "fs-extra": "^8.1.0",
+ "github-markdown-css": "^5.7.0",
+ "glob-parent": "^6.0.2",
+ "highlight.js": "^10.4.1",
+ "lodash.debounce": "^4.0.8",
+ "modern-normalize": "^3.0.1",
+ "moment": "^2.29.1",
+ "node-ipc": "^12.0.0",
+ "quasar": "^2.18.1",
+ "quill": "^1.3.7",
+ "sanitize-filename": "^1.6.3",
+ "serialize-javascript": "^3.1.0",
+ "tar": "^6.1.11",
+ "trim-newlines": "^4.0.2",
+ "unzipper": "^0.10.5",
+ "uuid-js": "^0.7.5",
+ "vue-i18n": "^11.1.6",
+ "vue-router": "^4.5.1",
+ "vuedraggable": "4.1.0",
+ "vuex": "^4.1.0",
+ "yaml": "^1.7.2"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.4.0",
+ "@babel/preset-typescript": "^7.14.5",
+ "@quasar/app-vite": "^2.2.1",
+ "@types/adm-zip": "^0.4.34",
+ "@types/async-lock": "^1.1.2",
+ "@types/chai": "^4.2.11",
+ "@types/fs-extra": "^8.0.1",
+ "@types/jsdom": "^21.1.7",
+ "@types/lodash.debounce": "^4.0.7",
+ "@types/node": "^20.19.1",
+ "@types/quill": "^2.0.3",
+ "@types/sinon": "^10.0.2",
+ "@types/unzipper": "^0.10.1",
+ "@types/yaml": "^1.2.0",
+ "@vue/devtools": "^7.7.7",
+ "@vue/test-utils": "^2.4.6",
+ "autoprefixer": "^10.4.21",
+ "babel-core": "^7.0.0-beta.3",
+ "babel-jest": "^27.0.2",
+ "chai": "^4.2.0",
+ "devtron": "^1.4.0",
+ "electron": "^36.5.0",
+ "electron-builder": "^24.10.5",
+ "electron-debug": "^3.0.1",
+ "electron-devtools-installer": "^3.0.0",
+ "electron-packager": "14.1.1",
+ "eslint-plugin-jest": "^28.8.3",
+ "identity-obj-proxy": "^3.0.0",
+ "jest": "^29.7.0",
+ "jsdom": "^25.0.1",
+ "majestic": "^1.2.24",
+ "minimist": "^1.2.2",
+ "mock-require": "^3.0.3",
+ "quicktype-core": "^23.0.171",
+ "postcss": "^8.5.6",
+ "sass": "^1.70.0",
+ "sass-loader": "^16.0.5",
+ "sinon": "^11.1.1",
+ "ts-jest": "^29.2.5",
+ "ts-node": "^8.10.2",
+ "typescript": "^5.9.2",
+ "vite-plugin-node-polyfills": "^0.23.0",
+ "vue": "^3.5.16",
+ "vue-jest": "^3.0.0",
+ "wallaby-vue-compiler": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 18.0.0",
+ "npm": ">= 10.0.0",
+ "yarn": ">= 1.21.1"
+ }
}
diff --git a/public/images/game_selection/20MinutesTillDawn.jpg b/public/images/game_selection/20MinutesTillDawn.jpg
new file mode 100644
index 000000000..f118d4c77
Binary files /dev/null and b/public/images/game_selection/20MinutesTillDawn.jpg differ
diff --git a/public/images/game_selection/9Kings.png b/public/images/game_selection/9Kings.png
new file mode 100644
index 000000000..3549b115c
Binary files /dev/null and b/public/images/game_selection/9Kings.png differ
diff --git a/public/images/game_selection/AGAINST.jpg b/public/images/game_selection/AGAINST.jpg
new file mode 100644
index 000000000..4e2a2955b
Binary files /dev/null and b/public/images/game_selection/AGAINST.jpg differ
diff --git a/public/images/game_selection/ANEURISM_IV.png b/public/images/game_selection/ANEURISM_IV.png
new file mode 100644
index 000000000..de8fd76b4
Binary files /dev/null and b/public/images/game_selection/ANEURISM_IV.png differ
diff --git a/public/images/game_selection/ASKA.png b/public/images/game_selection/ASKA.png
new file mode 100644
index 000000000..95efd43af
Binary files /dev/null and b/public/images/game_selection/ASKA.png differ
diff --git a/public/images/game_selection/ATLYSS.png b/public/images/game_selection/ATLYSS.png
new file mode 100644
index 000000000..623a1bf82
Binary files /dev/null and b/public/images/game_selection/ATLYSS.png differ
diff --git a/public/images/game_selection/AcrossTheObelisk.png b/public/images/game_selection/AcrossTheObelisk.png
new file mode 100644
index 000000000..ecd720a4f
Binary files /dev/null and b/public/images/game_selection/AcrossTheObelisk.png differ
diff --git a/public/images/game_selection/AgainstTheStorm.png b/public/images/game_selection/AgainstTheStorm.png
new file mode 100644
index 000000000..844147a29
Binary files /dev/null and b/public/images/game_selection/AgainstTheStorm.png differ
diff --git a/public/images/game_selection/AleAndTaleTavern.png b/public/images/game_selection/AleAndTaleTavern.png
new file mode 100644
index 000000000..aa96626c4
Binary files /dev/null and b/public/images/game_selection/AleAndTaleTavern.png differ
diff --git a/public/images/game_selection/Aloft.png b/public/images/game_selection/Aloft.png
new file mode 100644
index 000000000..f329c5119
Binary files /dev/null and b/public/images/game_selection/Aloft.png differ
diff --git a/public/images/game_selection/AmongUs.png b/public/images/game_selection/AmongUs.png
new file mode 100644
index 000000000..de5280353
Binary files /dev/null and b/public/images/game_selection/AmongUs.png differ
diff --git a/public/images/game_selection/AnotherCrabsTreasure.png b/public/images/game_selection/AnotherCrabsTreasure.png
new file mode 100644
index 000000000..0d39d486c
Binary files /dev/null and b/public/images/game_selection/AnotherCrabsTreasure.png differ
diff --git a/public/images/game_selection/ArcusChroma.png b/public/images/game_selection/ArcusChroma.png
new file mode 100644
index 000000000..6ed1a8a43
Binary files /dev/null and b/public/images/game_selection/ArcusChroma.png differ
diff --git a/public/images/game_selection/Atomicrops.jpg b/public/images/game_selection/Atomicrops.jpg
new file mode 100644
index 000000000..9c205ae05
Binary files /dev/null and b/public/images/game_selection/Atomicrops.jpg differ
diff --git a/public/images/game_selection/BONELAB.jpg b/public/images/game_selection/BONELAB.jpg
new file mode 100644
index 000000000..3c7c2ccc7
Binary files /dev/null and b/public/images/game_selection/BONELAB.jpg differ
diff --git a/public/images/game_selection/BONEWORKS.jpg b/public/images/game_selection/BONEWORKS.jpg
new file mode 100644
index 000000000..62c35f4ea
Binary files /dev/null and b/public/images/game_selection/BONEWORKS.jpg differ
diff --git a/public/images/game_selection/BackToTheDawn.png b/public/images/game_selection/BackToTheDawn.png
new file mode 100644
index 000000000..3b008e814
Binary files /dev/null and b/public/images/game_selection/BackToTheDawn.png differ
diff --git a/public/images/game_selection/BackpackHero.jpg b/public/images/game_selection/BackpackHero.jpg
new file mode 100644
index 000000000..0a9bcf5d7
Binary files /dev/null and b/public/images/game_selection/BackpackHero.jpg differ
diff --git a/public/images/game_selection/Balatro.png b/public/images/game_selection/Balatro.png
new file mode 100644
index 000000000..f00e53422
Binary files /dev/null and b/public/images/game_selection/Balatro.png differ
diff --git a/public/images/game_selection/BelowTheStone.png b/public/images/game_selection/BelowTheStone.png
new file mode 100644
index 000000000..c9631fc7a
Binary files /dev/null and b/public/images/game_selection/BelowTheStone.png differ
diff --git a/public/images/game_selection/BetrayalBeach.png b/public/images/game_selection/BetrayalBeach.png
new file mode 100644
index 000000000..e4fce24c2
Binary files /dev/null and b/public/images/game_selection/BetrayalBeach.png differ
diff --git a/public/images/game_selection/BombRushCyberfunk.jpg b/public/images/game_selection/BombRushCyberfunk.jpg
new file mode 100644
index 000000000..6030195bc
Binary files /dev/null and b/public/images/game_selection/BombRushCyberfunk.jpg differ
diff --git a/public/images/game_selection/BoplBattle.png b/public/images/game_selection/BoplBattle.png
new file mode 100644
index 000000000..ee300f2f7
Binary files /dev/null and b/public/images/game_selection/BoplBattle.png differ
diff --git a/public/images/game_selection/CastleStory.png b/public/images/game_selection/CastleStory.png
new file mode 100644
index 000000000..6ab666841
Binary files /dev/null and b/public/images/game_selection/CastleStory.png differ
diff --git a/public/images/game_selection/CatsAreLiquidABP.jpg b/public/images/game_selection/CatsAreLiquidABP.jpg
new file mode 100644
index 000000000..9e1dcf3b6
Binary files /dev/null and b/public/images/game_selection/CatsAreLiquidABP.jpg differ
diff --git a/public/images/game_selection/ChronoArk.jpg b/public/images/game_selection/ChronoArk.jpg
new file mode 100644
index 000000000..7119d531a
Binary files /dev/null and b/public/images/game_selection/ChronoArk.jpg differ
diff --git a/public/images/game_selection/CitiesSkylines2.png b/public/images/game_selection/CitiesSkylines2.png
new file mode 100644
index 000000000..62ea9346d
Binary files /dev/null and b/public/images/game_selection/CitiesSkylines2.png differ
diff --git a/public/images/game_selection/ContentWarning.png b/public/images/game_selection/ContentWarning.png
new file mode 100644
index 000000000..8ba40ba62
Binary files /dev/null and b/public/images/game_selection/ContentWarning.png differ
diff --git a/public/images/game_selection/CoreKeeper.png b/public/images/game_selection/CoreKeeper.png
new file mode 100644
index 000000000..27fecf255
Binary files /dev/null and b/public/images/game_selection/CoreKeeper.png differ
diff --git a/public/images/game_selection/Cotl.jpg b/public/images/game_selection/Cotl.jpg
new file mode 100644
index 000000000..973e8bfc0
Binary files /dev/null and b/public/images/game_selection/Cotl.jpg differ
diff --git a/public/images/game_selection/DEPO.png b/public/images/game_selection/DEPO.png
new file mode 100644
index 000000000..92b612498
Binary files /dev/null and b/public/images/game_selection/DEPO.png differ
diff --git a/public/images/game_selection/DUSK.png b/public/images/game_selection/DUSK.png
new file mode 100644
index 000000000..a761407ee
Binary files /dev/null and b/public/images/game_selection/DUSK.png differ
diff --git a/public/images/game_selection/DaleAndDawson.png b/public/images/game_selection/DaleAndDawson.png
new file mode 100644
index 000000000..ed02047aa
Binary files /dev/null and b/public/images/game_selection/DaleAndDawson.png differ
diff --git a/public/images/game_selection/DeepRockGalacticSurvivor.png b/public/images/game_selection/DeepRockGalacticSurvivor.png
new file mode 100644
index 000000000..2f11fc544
Binary files /dev/null and b/public/images/game_selection/DeepRockGalacticSurvivor.png differ
diff --git a/public/images/game_selection/DiscoElysium.webp b/public/images/game_selection/DiscoElysium.webp
new file mode 100644
index 000000000..7f9650a38
Binary files /dev/null and b/public/images/game_selection/DiscoElysium.webp differ
diff --git a/public/images/game_selection/Distance.png b/public/images/game_selection/Distance.png
new file mode 100644
index 000000000..08a22cc43
Binary files /dev/null and b/public/images/game_selection/Distance.png differ
diff --git a/public/images/game_selection/Dredge.png b/public/images/game_selection/Dredge.png
new file mode 100644
index 000000000..dc1128416
Binary files /dev/null and b/public/images/game_selection/Dredge.png differ
diff --git a/public/images/game_selection/DysonSphereProgram.png b/public/images/game_selection/DysonSphereProgram.png
new file mode 100644
index 000000000..c07d2fa3b
Binary files /dev/null and b/public/images/game_selection/DysonSphereProgram.png differ
diff --git a/public/images/game_selection/ENADreamBBQ.png b/public/images/game_selection/ENADreamBBQ.png
new file mode 100644
index 000000000..ad7716b34
Binary files /dev/null and b/public/images/game_selection/ENADreamBBQ.png differ
diff --git a/public/images/game_selection/EnterTheGungeon.jpg b/public/images/game_selection/EnterTheGungeon.jpg
new file mode 100644
index 000000000..8bcc520a7
Binary files /dev/null and b/public/images/game_selection/EnterTheGungeon.jpg differ
diff --git a/public/images/game_selection/Erenshor.jpg b/public/images/game_selection/Erenshor.jpg
new file mode 100644
index 000000000..e8f6e74e9
Binary files /dev/null and b/public/images/game_selection/Erenshor.jpg differ
diff --git a/public/images/game_selection/FiveNightsAtFreddysIntoThePit.png b/public/images/game_selection/FiveNightsAtFreddysIntoThePit.png
new file mode 100644
index 000000000..8321a4fb6
Binary files /dev/null and b/public/images/game_selection/FiveNightsAtFreddysIntoThePit.png differ
diff --git a/public/images/game_selection/ForTheKing.png b/public/images/game_selection/ForTheKing.png
new file mode 100644
index 000000000..2629666eb
Binary files /dev/null and b/public/images/game_selection/ForTheKing.png differ
diff --git a/public/images/game_selection/GTFO.jpg b/public/images/game_selection/GTFO.jpg
new file mode 100644
index 000000000..7c114000c
Binary files /dev/null and b/public/images/game_selection/GTFO.jpg differ
diff --git a/public/images/game_selection/GangBeasts.png b/public/images/game_selection/GangBeasts.png
new file mode 100644
index 000000000..6a185ffb9
Binary files /dev/null and b/public/images/game_selection/GangBeasts.png differ
diff --git a/public/images/game_selection/Gatekeeper.png b/public/images/game_selection/Gatekeeper.png
new file mode 100644
index 000000000..7e795b61f
Binary files /dev/null and b/public/images/game_selection/Gatekeeper.png differ
diff --git a/public/images/game_selection/GladioMori.png b/public/images/game_selection/GladioMori.png
new file mode 100644
index 000000000..b138b19e6
Binary files /dev/null and b/public/images/game_selection/GladioMori.png differ
diff --git a/public/images/game_selection/Gloomwood.png b/public/images/game_selection/Gloomwood.png
new file mode 100644
index 000000000..27c731151
Binary files /dev/null and b/public/images/game_selection/Gloomwood.png differ
diff --git a/public/images/game_selection/GoodbyeVolcanoHigh.png b/public/images/game_selection/GoodbyeVolcanoHigh.png
new file mode 100644
index 000000000..ad5152d22
Binary files /dev/null and b/public/images/game_selection/GoodbyeVolcanoHigh.png differ
diff --git a/public/images/game_selection/GoreBox.png b/public/images/game_selection/GoreBox.png
new file mode 100644
index 000000000..bce666e87
Binary files /dev/null and b/public/images/game_selection/GoreBox.png differ
diff --git a/public/images/game_selection/GreenHellVR.png b/public/images/game_selection/GreenHellVR.png
new file mode 100644
index 000000000..e9e87f3ea
Binary files /dev/null and b/public/images/game_selection/GreenHellVR.png differ
diff --git a/public/images/game_selection/GuiltyasSock.png b/public/images/game_selection/GuiltyasSock.png
new file mode 100644
index 000000000..8eae2db69
Binary files /dev/null and b/public/images/game_selection/GuiltyasSock.png differ
diff --git a/public/images/game_selection/H3VR.png b/public/images/game_selection/H3VR.png
new file mode 100644
index 000000000..8505f1723
Binary files /dev/null and b/public/images/game_selection/H3VR.png differ
diff --git a/public/images/game_selection/HOTDS.jpg b/public/images/game_selection/HOTDS.jpg
new file mode 100644
index 000000000..dc4de4158
Binary files /dev/null and b/public/images/game_selection/HOTDS.jpg differ
diff --git a/public/images/game_selection/Hades2.png b/public/images/game_selection/Hades2.png
new file mode 100644
index 000000000..7fbc80d29
Binary files /dev/null and b/public/images/game_selection/Hades2.png differ
diff --git a/public/images/game_selection/HardBullet.jpg b/public/images/game_selection/HardBullet.jpg
new file mode 100644
index 000000000..d64493581
Binary files /dev/null and b/public/images/game_selection/HardBullet.jpg differ
diff --git a/public/images/game_selection/HardTime3.png b/public/images/game_selection/HardTime3.png
new file mode 100644
index 000000000..34cf61d47
Binary files /dev/null and b/public/images/game_selection/HardTime3.png differ
diff --git a/public/images/game_selection/HumanFallFlat.png b/public/images/game_selection/HumanFallFlat.png
new file mode 100644
index 000000000..26ee6dc55
Binary files /dev/null and b/public/images/game_selection/HumanFallFlat.png differ
diff --git a/public/images/game_selection/IAmYourBeast.webp b/public/images/game_selection/IAmYourBeast.webp
new file mode 100644
index 000000000..0eae38a2c
Binary files /dev/null and b/public/images/game_selection/IAmYourBeast.webp differ
diff --git a/public/images/game_selection/Inscryption.png b/public/images/game_selection/Inscryption.png
new file mode 100644
index 000000000..4633e9b24
Binary files /dev/null and b/public/images/game_selection/Inscryption.png differ
diff --git a/public/images/game_selection/Labyrinthine.png b/public/images/game_selection/Labyrinthine.png
new file mode 100644
index 000000000..ec9b885ff
Binary files /dev/null and b/public/images/game_selection/Labyrinthine.png differ
diff --git a/public/images/game_selection/LastTrainOuttaWormtown.png b/public/images/game_selection/LastTrainOuttaWormtown.png
new file mode 100644
index 000000000..aefad9b39
Binary files /dev/null and b/public/images/game_selection/LastTrainOuttaWormtown.png differ
diff --git a/public/images/game_selection/LethalCompany.png b/public/images/game_selection/LethalCompany.png
new file mode 100644
index 000000000..0a3b9b584
Binary files /dev/null and b/public/images/game_selection/LethalCompany.png differ
diff --git a/public/images/game_selection/LethalLeagueBlaze.png b/public/images/game_selection/LethalLeagueBlaze.png
new file mode 100644
index 000000000..1ab69d218
Binary files /dev/null and b/public/images/game_selection/LethalLeagueBlaze.png differ
diff --git a/public/images/game_selection/LostSkies.png b/public/images/game_selection/LostSkies.png
new file mode 100644
index 000000000..4818029d1
Binary files /dev/null and b/public/images/game_selection/LostSkies.png differ
diff --git a/public/images/game_selection/Lycans.png b/public/images/game_selection/Lycans.png
new file mode 100644
index 000000000..81c34f5d3
Binary files /dev/null and b/public/images/game_selection/Lycans.png differ
diff --git a/public/images/game_selection/Magicite.png b/public/images/game_selection/Magicite.png
new file mode 100644
index 000000000..507b0f312
Binary files /dev/null and b/public/images/game_selection/Magicite.png differ
diff --git a/public/images/game_selection/Magicraft.png b/public/images/game_selection/Magicraft.png
new file mode 100644
index 000000000..61f8d4630
Binary files /dev/null and b/public/images/game_selection/Magicraft.png differ
diff --git a/public/images/game_selection/Mechanica.jpg b/public/images/game_selection/Mechanica.jpg
new file mode 100644
index 000000000..fafd5662e
Binary files /dev/null and b/public/images/game_selection/Mechanica.jpg differ
diff --git a/public/images/game_selection/MeepleStation.png b/public/images/game_selection/MeepleStation.png
new file mode 100644
index 000000000..06596e849
Binary files /dev/null and b/public/images/game_selection/MeepleStation.png differ
diff --git a/public/images/game_selection/MiSide.webp b/public/images/game_selection/MiSide.webp
new file mode 100644
index 000000000..f17f58334
Binary files /dev/null and b/public/images/game_selection/MiSide.webp differ
diff --git a/public/images/game_selection/MonsterTrain2.png b/public/images/game_selection/MonsterTrain2.png
new file mode 100644
index 000000000..f6995b5a7
Binary files /dev/null and b/public/images/game_selection/MonsterTrain2.png differ
diff --git a/public/images/game_selection/Muck.png b/public/images/game_selection/Muck.png
new file mode 100644
index 000000000..3cf08095d
Binary files /dev/null and b/public/images/game_selection/Muck.png differ
diff --git a/public/images/game_selection/MyDreamSetup.png b/public/images/game_selection/MyDreamSetup.png
new file mode 100644
index 000000000..ad3cf9af7
Binary files /dev/null and b/public/images/game_selection/MyDreamSetup.png differ
diff --git a/public/images/game_selection/NASB.jpg b/public/images/game_selection/NASB.jpg
new file mode 100644
index 000000000..9c798ead0
Binary files /dev/null and b/public/images/game_selection/NASB.jpg differ
diff --git a/public/images/game_selection/NearlyDead.png b/public/images/game_selection/NearlyDead.png
new file mode 100644
index 000000000..08bac10bd
Binary files /dev/null and b/public/images/game_selection/NearlyDead.png differ
diff --git a/public/images/game_selection/NineSols.png b/public/images/game_selection/NineSols.png
new file mode 100644
index 000000000..b99266b2a
Binary files /dev/null and b/public/images/game_selection/NineSols.png differ
diff --git a/public/images/game_selection/ObraDinn.png b/public/images/game_selection/ObraDinn.png
new file mode 100644
index 000000000..ddb9f6e4b
Binary files /dev/null and b/public/images/game_selection/ObraDinn.png differ
diff --git a/public/images/game_selection/OddRemedy.png b/public/images/game_selection/OddRemedy.png
new file mode 100644
index 000000000..06d60fc54
Binary files /dev/null and b/public/images/game_selection/OddRemedy.png differ
diff --git a/public/images/game_selection/OldMarketSimulator.png b/public/images/game_selection/OldMarketSimulator.png
new file mode 100644
index 000000000..b2680f91d
Binary files /dev/null and b/public/images/game_selection/OldMarketSimulator.png differ
diff --git a/public/images/game_selection/Outward.jpg b/public/images/game_selection/Outward.jpg
new file mode 100644
index 000000000..ecc720138
Binary files /dev/null and b/public/images/game_selection/Outward.jpg differ
diff --git a/public/images/game_selection/OutwardDe.jpg b/public/images/game_selection/OutwardDe.jpg
new file mode 100644
index 000000000..baa7b04b1
Binary files /dev/null and b/public/images/game_selection/OutwardDe.jpg differ
diff --git a/public/images/game_selection/PEAK.webp b/public/images/game_selection/PEAK.webp
new file mode 100644
index 000000000..c578fad12
Binary files /dev/null and b/public/images/game_selection/PEAK.webp differ
diff --git a/public/images/game_selection/PIGFACE.png b/public/images/game_selection/PIGFACE.png
new file mode 100644
index 000000000..ef639f54e
Binary files /dev/null and b/public/images/game_selection/PIGFACE.png differ
diff --git a/public/images/game_selection/PaintingVr.png b/public/images/game_selection/PaintingVr.png
new file mode 100644
index 000000000..febbdc552
Binary files /dev/null and b/public/images/game_selection/PaintingVr.png differ
diff --git a/public/images/game_selection/Palworld.png b/public/images/game_selection/Palworld.png
new file mode 100644
index 000000000..dbb8690c7
Binary files /dev/null and b/public/images/game_selection/Palworld.png differ
diff --git a/public/images/game_selection/Panicore.png b/public/images/game_selection/Panicore.png
new file mode 100644
index 000000000..cb0c9fc24
Binary files /dev/null and b/public/images/game_selection/Panicore.png differ
diff --git a/public/images/game_selection/PaqueretteDownTheBunburrows.png b/public/images/game_selection/PaqueretteDownTheBunburrows.png
new file mode 100644
index 000000000..6a7b7fe9b
Binary files /dev/null and b/public/images/game_selection/PaqueretteDownTheBunburrows.png differ
diff --git a/public/images/game_selection/PeaksOfYore.png b/public/images/game_selection/PeaksOfYore.png
new file mode 100644
index 000000000..c97ee56f3
Binary files /dev/null and b/public/images/game_selection/PeaksOfYore.png differ
diff --git a/public/images/game_selection/Peglin.jpg b/public/images/game_selection/Peglin.jpg
new file mode 100644
index 000000000..057568510
Binary files /dev/null and b/public/images/game_selection/Peglin.jpg differ
diff --git a/public/images/game_selection/Plasma.jpg b/public/images/game_selection/Plasma.jpg
new file mode 100644
index 000000000..3da5b0b7b
Binary files /dev/null and b/public/images/game_selection/Plasma.jpg differ
diff --git a/public/images/game_selection/PotionCraft.jpg b/public/images/game_selection/PotionCraft.jpg
new file mode 100644
index 000000000..ac15332ba
Binary files /dev/null and b/public/images/game_selection/PotionCraft.jpg differ
diff --git a/public/images/game_selection/PulsarLostColony.png b/public/images/game_selection/PulsarLostColony.png
new file mode 100644
index 000000000..80121dc9b
Binary files /dev/null and b/public/images/game_selection/PulsarLostColony.png differ
diff --git a/public/images/game_selection/REPO.png b/public/images/game_selection/REPO.png
new file mode 100644
index 000000000..4fcf52d67
Binary files /dev/null and b/public/images/game_selection/REPO.png differ
diff --git a/public/images/game_selection/ROUNDS.png b/public/images/game_selection/ROUNDS.png
new file mode 100644
index 000000000..253f862d6
Binary files /dev/null and b/public/images/game_selection/ROUNDS.png differ
diff --git a/public/images/game_selection/RUMBLE.png b/public/images/game_selection/RUMBLE.png
new file mode 100644
index 000000000..e26fcf42a
Binary files /dev/null and b/public/images/game_selection/RUMBLE.png differ
diff --git a/public/images/game_selection/Ravenfield.jpg b/public/images/game_selection/Ravenfield.jpg
new file mode 100644
index 000000000..d4950b7ad
Binary files /dev/null and b/public/images/game_selection/Ravenfield.jpg differ
diff --git a/public/images/game_selection/RiskOfRain2.jpg b/public/images/game_selection/RiskOfRain2.jpg
new file mode 100644
index 000000000..102677a79
Binary files /dev/null and b/public/images/game_selection/RiskOfRain2.jpg differ
diff --git a/public/images/game_selection/RiskOfRainReturns.png b/public/images/game_selection/RiskOfRainReturns.png
new file mode 100644
index 000000000..6e6505b6f
Binary files /dev/null and b/public/images/game_selection/RiskOfRainReturns.png differ
diff --git a/public/images/game_selection/RogueGenesia.jpg b/public/images/game_selection/RogueGenesia.jpg
new file mode 100644
index 000000000..bb0da72d9
Binary files /dev/null and b/public/images/game_selection/RogueGenesia.jpg differ
diff --git a/public/images/game_selection/RogueTower.jpg b/public/images/game_selection/RogueTower.jpg
new file mode 100644
index 000000000..5e3924869
Binary files /dev/null and b/public/images/game_selection/RogueTower.jpg differ
diff --git a/public/images/game_selection/STRAFTAT.png b/public/images/game_selection/STRAFTAT.png
new file mode 100644
index 000000000..aee2efb8a
Binary files /dev/null and b/public/images/game_selection/STRAFTAT.png differ
diff --git a/public/images/game_selection/SULFUR.png b/public/images/game_selection/SULFUR.png
new file mode 100644
index 000000000..fb97a40ff
Binary files /dev/null and b/public/images/game_selection/SULFUR.png differ
diff --git a/public/images/game_selection/Sailwind.png b/public/images/game_selection/Sailwind.png
new file mode 100644
index 000000000..ce62f3b1a
Binary files /dev/null and b/public/images/game_selection/Sailwind.png differ
diff --git a/public/images/game_selection/ScheduleI.png b/public/images/game_selection/ScheduleI.png
new file mode 100644
index 000000000..215d79e61
Binary files /dev/null and b/public/images/game_selection/ScheduleI.png differ
diff --git a/public/images/game_selection/ScrewDrivers.png b/public/images/game_selection/ScrewDrivers.png
new file mode 100644
index 000000000..1e82f2009
Binary files /dev/null and b/public/images/game_selection/ScrewDrivers.png differ
diff --git a/public/images/game_selection/Shapez2.png b/public/images/game_selection/Shapez2.png
new file mode 100644
index 000000000..4d14c3aa8
Binary files /dev/null and b/public/images/game_selection/Shapez2.png differ
diff --git a/public/images/game_selection/SlipstreamRogueSpace.png b/public/images/game_selection/SlipstreamRogueSpace.png
new file mode 100644
index 000000000..c96ae9af7
Binary files /dev/null and b/public/images/game_selection/SlipstreamRogueSpace.png differ
diff --git a/public/images/game_selection/SongsOfConquest.png b/public/images/game_selection/SongsOfConquest.png
new file mode 100644
index 000000000..03f5217c6
Binary files /dev/null and b/public/images/game_selection/SongsOfConquest.png differ
diff --git a/public/images/game_selection/Stacklands.jpg b/public/images/game_selection/Stacklands.jpg
new file mode 100644
index 000000000..770275e4d
Binary files /dev/null and b/public/images/game_selection/Stacklands.jpg differ
diff --git a/public/images/game_selection/Starsand.png b/public/images/game_selection/Starsand.png
new file mode 100644
index 000000000..f06bc0b8b
Binary files /dev/null and b/public/images/game_selection/Starsand.png differ
diff --git a/public/images/game_selection/Subnautica.png b/public/images/game_selection/Subnautica.png
new file mode 100644
index 000000000..5cd7a0e63
Binary files /dev/null and b/public/images/game_selection/Subnautica.png differ
diff --git a/public/images/game_selection/SubnauticaBelowZero.png b/public/images/game_selection/SubnauticaBelowZero.png
new file mode 100644
index 000000000..8b7825bf5
Binary files /dev/null and b/public/images/game_selection/SubnauticaBelowZero.png differ
diff --git a/public/images/game_selection/Subterranauts.png b/public/images/game_selection/Subterranauts.png
new file mode 100644
index 000000000..52b5ce422
Binary files /dev/null and b/public/images/game_selection/Subterranauts.png differ
diff --git a/public/images/game_selection/Subterror.png b/public/images/game_selection/Subterror.png
new file mode 100644
index 000000000..d710addcc
Binary files /dev/null and b/public/images/game_selection/Subterror.png differ
diff --git a/public/images/game_selection/Sunkenland.jpg b/public/images/game_selection/Sunkenland.jpg
new file mode 100644
index 000000000..1d11197f5
Binary files /dev/null and b/public/images/game_selection/Sunkenland.jpg differ
diff --git a/public/images/game_selection/SupermarketTogether.png b/public/images/game_selection/SupermarketTogether.png
new file mode 100644
index 000000000..a9bdfb581
Binary files /dev/null and b/public/images/game_selection/SupermarketTogether.png differ
diff --git a/public/images/game_selection/TCGCardShopSimulator.png b/public/images/game_selection/TCGCardShopSimulator.png
new file mode 100644
index 000000000..fcbf2ef81
Binary files /dev/null and b/public/images/game_selection/TCGCardShopSimulator.png differ
diff --git a/public/images/game_selection/TaleSpire.jpg b/public/images/game_selection/TaleSpire.jpg
new file mode 100644
index 000000000..0260ccb2f
Binary files /dev/null and b/public/images/game_selection/TaleSpire.jpg differ
diff --git a/public/images/game_selection/TankTeam.png b/public/images/game_selection/TankTeam.png
new file mode 100644
index 000000000..3881dcf63
Binary files /dev/null and b/public/images/game_selection/TankTeam.png differ
diff --git a/public/images/game_selection/ThunderstoreBeta.jpg b/public/images/game_selection/ThunderstoreBeta.jpg
new file mode 100644
index 000000000..fc6cdd13a
Binary files /dev/null and b/public/images/game_selection/ThunderstoreBeta.jpg differ
diff --git a/public/images/game_selection/Timberborn.png b/public/images/game_selection/Timberborn.png
new file mode 100644
index 000000000..93aee0bc0
Binary files /dev/null and b/public/images/game_selection/Timberborn.png differ
diff --git a/public/images/game_selection/Titanfall2.jpg b/public/images/game_selection/Titanfall2.jpg
new file mode 100644
index 000000000..40fa4ce8f
Binary files /dev/null and b/public/images/game_selection/Titanfall2.jpg differ
diff --git a/public/images/game_selection/TotallyAccurateBattleSimulator.jpg b/public/images/game_selection/TotallyAccurateBattleSimulator.jpg
new file mode 100644
index 000000000..2bf8556ea
Binary files /dev/null and b/public/images/game_selection/TotallyAccurateBattleSimulator.jpg differ
diff --git a/public/images/game_selection/TouhouLostBranchOfLegend.jpg b/public/images/game_selection/TouhouLostBranchOfLegend.jpg
new file mode 100644
index 000000000..1d43453c2
Binary files /dev/null and b/public/images/game_selection/TouhouLostBranchOfLegend.jpg differ
diff --git a/public/images/game_selection/TromboneChamp.jpg b/public/images/game_selection/TromboneChamp.jpg
new file mode 100644
index 000000000..22f8fb136
Binary files /dev/null and b/public/images/game_selection/TromboneChamp.jpg differ
diff --git a/public/images/game_selection/ULTRAKILL.jpg b/public/images/game_selection/ULTRAKILL.jpg
new file mode 100644
index 000000000..4397ffe0a
Binary files /dev/null and b/public/images/game_selection/ULTRAKILL.jpg differ
diff --git a/public/images/game_selection/VRising.jpg b/public/images/game_selection/VRising.jpg
new file mode 100644
index 000000000..83ebab9a6
Binary files /dev/null and b/public/images/game_selection/VRising.jpg differ
diff --git a/public/images/game_selection/Valheim.jpg b/public/images/game_selection/Valheim.jpg
new file mode 100644
index 000000000..4019cd2ff
Binary files /dev/null and b/public/images/game_selection/Valheim.jpg differ
diff --git a/public/images/game_selection/Vertigo2.png b/public/images/game_selection/Vertigo2.png
new file mode 100644
index 000000000..b4f9ef405
Binary files /dev/null and b/public/images/game_selection/Vertigo2.png differ
diff --git a/public/images/game_selection/VoidCrew.png b/public/images/game_selection/VoidCrew.png
new file mode 100644
index 000000000..65b6d91c6
Binary files /dev/null and b/public/images/game_selection/VoidCrew.png differ
diff --git a/public/images/game_selection/VotV.png b/public/images/game_selection/VotV.png
new file mode 100644
index 000000000..9da6a11c9
Binary files /dev/null and b/public/images/game_selection/VotV.png differ
diff --git a/public/images/game_selection/VtolVR.jpg b/public/images/game_selection/VtolVR.jpg
new file mode 100644
index 000000000..03973734b
Binary files /dev/null and b/public/images/game_selection/VtolVR.jpg differ
diff --git a/public/images/game_selection/WEBFISHING.png b/public/images/game_selection/WEBFISHING.png
new file mode 100644
index 000000000..5c947a411
Binary files /dev/null and b/public/images/game_selection/WEBFISHING.png differ
diff --git a/public/images/game_selection/WLKRR.jpg b/public/images/game_selection/WLKRR.jpg
new file mode 100644
index 000000000..77661862a
Binary files /dev/null and b/public/images/game_selection/WLKRR.jpg differ
diff --git a/public/images/game_selection/WhiteKnuckle.png b/public/images/game_selection/WhiteKnuckle.png
new file mode 100644
index 000000000..8153395e1
Binary files /dev/null and b/public/images/game_selection/WhiteKnuckle.png differ
diff --git a/public/images/game_selection/WizardOfLegend.jpg b/public/images/game_selection/WizardOfLegend.jpg
new file mode 100644
index 000000000..6ac31aad0
Binary files /dev/null and b/public/images/game_selection/WizardOfLegend.jpg differ
diff --git a/public/images/game_selection/WizardWithAGun.jpg b/public/images/game_selection/WizardWithAGun.jpg
new file mode 100644
index 000000000..966127e18
Binary files /dev/null and b/public/images/game_selection/WizardWithAGun.jpg differ
diff --git a/public/images/game_selection/ancient-dungeon-vr.png b/public/images/game_selection/ancient-dungeon-vr.png
new file mode 100644
index 000000000..2ab7261c5
Binary files /dev/null and b/public/images/game_selection/ancient-dungeon-vr.png differ
diff --git a/public/images/game_selection/atrio-the-dark-wild.jpg b/public/images/game_selection/atrio-the-dark-wild.jpg
new file mode 100644
index 000000000..45d598433
Binary files /dev/null and b/public/images/game_selection/atrio-the-dark-wild.jpg differ
diff --git a/public/images/game_selection/bad-north.webp b/public/images/game_selection/bad-north.webp
new file mode 100644
index 000000000..50f6b19c7
Binary files /dev/null and b/public/images/game_selection/bad-north.webp differ
diff --git a/public/images/game_selection/brotato.jpg b/public/images/game_selection/brotato.jpg
new file mode 100644
index 000000000..345650991
Binary files /dev/null and b/public/images/game_selection/brotato.jpg differ
diff --git a/public/images/game_selection/dome-keeper.jpg b/public/images/game_selection/dome-keeper.jpg
new file mode 100644
index 000000000..5a58060d5
Binary files /dev/null and b/public/images/game_selection/dome-keeper.jpg differ
diff --git a/public/images/game_selection/garfield-kart-furious-racing.png b/public/images/game_selection/garfield-kart-furious-racing.png
new file mode 100644
index 000000000..3706479ba
Binary files /dev/null and b/public/images/game_selection/garfield-kart-furious-racing.png differ
diff --git a/public/images/game_selection/lens-island.webp b/public/images/game_selection/lens-island.webp
new file mode 100644
index 000000000..7521ddcf7
Binary files /dev/null and b/public/images/game_selection/lens-island.webp differ
diff --git a/public/images/game_selection/logic-world.webp b/public/images/game_selection/logic-world.webp
new file mode 100644
index 000000000..5abf4d9df
Binary files /dev/null and b/public/images/game_selection/logic-world.webp differ
diff --git a/public/images/game_selection/lost-skies-island-creator.webp b/public/images/game_selection/lost-skies-island-creator.webp
new file mode 100644
index 000000000..2ec951067
Binary files /dev/null and b/public/images/game_selection/lost-skies-island-creator.webp differ
diff --git a/public/images/game_selection/mage-arena.webp b/public/images/game_selection/mage-arena.webp
new file mode 100644
index 000000000..26081be2c
Binary files /dev/null and b/public/images/game_selection/mage-arena.webp differ
diff --git a/public/images/game_selection/mycopunk.webp b/public/images/game_selection/mycopunk.webp
new file mode 100644
index 000000000..f6b1e19d5
Binary files /dev/null and b/public/images/game_selection/mycopunk.webp differ
diff --git a/public/images/game_selection/ostranauts.webp b/public/images/game_selection/ostranauts.webp
new file mode 100644
index 000000000..462e502ca
Binary files /dev/null and b/public/images/game_selection/ostranauts.webp differ
diff --git a/public/images/game_selection/patapon-1-2-replay.webp b/public/images/game_selection/patapon-1-2-replay.webp
new file mode 100644
index 000000000..dfaeedaee
Binary files /dev/null and b/public/images/game_selection/patapon-1-2-replay.webp differ
diff --git a/public/images/game_selection/patch-quest.jpg b/public/images/game_selection/patch-quest.jpg
new file mode 100644
index 000000000..c5a89a91c
Binary files /dev/null and b/public/images/game_selection/patch-quest.jpg differ
diff --git a/public/images/game_selection/receiver-2.jpg b/public/images/game_selection/receiver-2.jpg
new file mode 100644
index 000000000..eeab9dac9
Binary files /dev/null and b/public/images/game_selection/receiver-2.jpg differ
diff --git a/public/images/game_selection/shadows-of-doubt.jpg b/public/images/game_selection/shadows-of-doubt.jpg
new file mode 100644
index 000000000..7408bd3cd
Binary files /dev/null and b/public/images/game_selection/shadows-of-doubt.jpg differ
diff --git a/public/images/game_selection/shadows-over-loathing.jpg b/public/images/game_selection/shadows-over-loathing.jpg
new file mode 100644
index 000000000..02414e0fe
Binary files /dev/null and b/public/images/game_selection/shadows-over-loathing.jpg differ
diff --git a/public/images/game_selection/skul-the-hero-slayer.jpg b/public/images/game_selection/skul-the-hero-slayer.jpg
new file mode 100644
index 000000000..619fb549b
Binary files /dev/null and b/public/images/game_selection/skul-the-hero-slayer.jpg differ
diff --git a/public/images/game_selection/sons-of-the-forest.jpg b/public/images/game_selection/sons-of-the-forest.jpg
new file mode 100644
index 000000000..4d9be7f63
Binary files /dev/null and b/public/images/game_selection/sons-of-the-forest.jpg differ
diff --git a/public/images/game_selection/sun-haven.jpg b/public/images/game_selection/sun-haven.jpg
new file mode 100644
index 000000000..3b4819f8b
Binary files /dev/null and b/public/images/game_selection/sun-haven.jpg differ
diff --git a/public/images/game_selection/techtonica.png b/public/images/game_selection/techtonica.png
new file mode 100644
index 000000000..880164fad
Binary files /dev/null and b/public/images/game_selection/techtonica.png differ
diff --git a/public/images/game_selection/the-ouroboros-king.jpg b/public/images/game_selection/the-ouroboros-king.jpg
new file mode 100644
index 000000000..c96600dfb
Binary files /dev/null and b/public/images/game_selection/the-ouroboros-king.jpg differ
diff --git a/public/images/game_selection/the-planet-crafter.jpg b/public/images/game_selection/the-planet-crafter.jpg
new file mode 100644
index 000000000..e2017cf65
Binary files /dev/null and b/public/images/game_selection/the-planet-crafter.jpg differ
diff --git a/public/images/game_selection/thronefall.png b/public/images/game_selection/thronefall.png
new file mode 100644
index 000000000..e33996f30
Binary files /dev/null and b/public/images/game_selection/thronefall.png differ
diff --git a/public/images/game_selection/ultimate-chicken-horse.jpg b/public/images/game_selection/ultimate-chicken-horse.jpg
new file mode 100644
index 000000000..fd57d299e
Binary files /dev/null and b/public/images/game_selection/ultimate-chicken-horse.jpg differ
diff --git a/public/images/game_selection/vellum.webp b/public/images/game_selection/vellum.webp
new file mode 100644
index 000000000..72c268d1a
Binary files /dev/null and b/public/images/game_selection/vellum.webp differ
diff --git a/public/images/game_selection/west-of-loathing.jpg b/public/images/game_selection/west-of-loathing.jpg
new file mode 100644
index 000000000..a32fdc889
Binary files /dev/null and b/public/images/game_selection/west-of-loathing.jpg differ
diff --git a/public/images/game_selection/wildfrost.jpg b/public/images/game_selection/wildfrost.jpg
new file mode 100644
index 000000000..ec730a4e5
Binary files /dev/null and b/public/images/game_selection/wildfrost.jpg differ
diff --git a/public/images/game_selection/word-play.webp b/public/images/game_selection/word-play.webp
new file mode 100644
index 000000000..41e20360c
Binary files /dev/null and b/public/images/game_selection/word-play.webp differ
diff --git a/public/images/game_selection/wrestling-empire.jpg b/public/images/game_selection/wrestling-empire.jpg
new file mode 100644
index 000000000..328c8cf26
Binary files /dev/null and b/public/images/game_selection/wrestling-empire.jpg differ
diff --git a/public/images/game_selection/zort.png b/public/images/game_selection/zort.png
new file mode 100644
index 000000000..7cde69f41
Binary files /dev/null and b/public/images/game_selection/zort.png differ
diff --git a/quasar.conf.js b/quasar.conf.js
deleted file mode 100644
index fa5470179..000000000
--- a/quasar.conf.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * This file runs in a Node context (it's NOT transpiled by Babel), so use only
- * the ES6 features that are supported by your Node version. https://node.green/
- */
-
-// Configuration for your app
-// https://quasar.dev/quasar-cli/quasar-conf-js
-/* eslint-disable @typescript-eslint/no-var-requires */
-const { configure } = require('quasar/wrappers');
-
-module.exports = configure(function(/* ctx */) {
- return {
- // https://v1.quasar.dev/quasar-cli/quasar-conf-js#property-sourcefiles
- sourceFiles: {
- rootComponent: 'src/AppWrapper.vue'
- },
-
- // https://quasar.dev/quasar-cli/supporting-ts
- supportTS: true,
-
- // https://quasar.dev/quasar-cli/prefetch-feature
- // preFetch: true,
-
- // app boot file (/src/boot)
- // --> boot files are part of "main.js"
- // https://quasar.dev/quasar-cli/boot-files
- boot: [
- 'i18n',
- 'axios',
- 'floating-vue' // Tooltips
- ],
-
- // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
- css: [
- 'app.scss'
- ],
-
- // https://github.com/quasarframework/quasar/tree/dev/extras
- extras: [
- // 'ionicons-v4',
- // 'mdi-v5',
- // 'fontawesome-v5',
- // 'eva-icons',
- // 'themify',
- // 'line-awesome',
- // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
-
- 'roboto-font', // optional, you are not bound to it
- 'material-icons' // optional, you are not bound to it
- ],
-
- // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
- build: {
- vueRouterMode: 'hash', // available values: 'hash', 'history'
-
- win: {
- publish: {
- provider: 'github'
- }
- },
- linux: {
- publish: {
- provider: 'github'
- }
- },
-
- // transpile: false,
-
- // Add dependencies for transpiling with Babel (Array of string/regex)
- // (from node_modules, which are by default not transpiled).
- // Applies only if "transpile" is set to true.
- // transpileDependencies: [],
-
- // rtl: false, // https://quasar.dev/options/rtl-support
- // preloadChunks: true,
- // showProgress: false,
- // gzip: true,
- // analyze: true,
-
- // Options below are automatically set depending on the env, set them if you want to override
- // extractCSS: false,
-
- // https://quasar.dev/quasar-cli/handling-webpack
- extendWebpack(cfg) {
- }
- },
-
- // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
- devServer: {
- https: false,
- port: 9020,
- open: true // opens browser window automatically
- },
-
- // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
- framework: {
- iconSet: 'material-icons', // Quasar icon set
- lang: 'en-us', // Quasar language pack
- config: {},
-
- // Possible values for "importStrategy":
- // * 'auto' - (DEFAULT) Auto-import needed Quasar components & directives
- // * 'all' - Manually specify what to import
- importStrategy: 'auto',
-
- // For special cases outside of where "auto" importStrategy can have an impact
- // (like functional components as one of the examples),
- // you can manually specify Quasar components/directives to be available everywhere:
- //
- // components: [],
- // directives: [],
-
- // Quasar plugins
- plugins: []
- },
-
- // animations: 'all', // --- includes all animations
- // https://quasar.dev/options/animations
- animations: [],
-
- // https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
- ssr: {
- pwa: false
- },
-
- // https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
- pwa: {
- workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
- workboxOptions: {}, // only for GenerateSW
- manifest: {
- name: `r2modmanPlus`,
- short_name: `r2modmanPlus`,
- description: `A simple and easy to use Risk of Rain 2 mod manager`,
- display: 'standalone',
- orientation: 'portrait',
- background_color: '#ffffff',
- theme_color: '#027be3',
- icons: [
- {
- src: 'icons/icon-128x128.png',
- sizes: '128x128',
- type: 'image/png'
- },
- {
- src: 'icons/icon-192x192.png',
- sizes: '192x192',
- type: 'image/png'
- },
- {
- src: 'icons/icon-256x256.png',
- sizes: '256x256',
- type: 'image/png'
- },
- {
- src: 'icons/icon-384x384.png',
- sizes: '384x384',
- type: 'image/png'
- },
- {
- src: 'icons/icon-512x512.png',
- sizes: '512x512',
- type: 'image/png'
- }
- ]
- }
- },
-
- // Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
- cordova: {
- // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
- },
-
- // Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
- capacitor: {
- hideSplashscreen: true
- },
-
- // Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
- electron: {
- bundler: 'builder', // 'packager' or 'builder'
-
- packager: {
- // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
-
- // OS X / Mac App Store
- // appBundleId: '',
- // appCategoryType: '',
- // osxSign: '',
- // protocol: 'myapp://path',
-
- // Windows only
- // win32metadata: { ... }
- },
-
- builder: {
- // https://www.electron.build/configuration/configuration
-
- appId: 'ebkr-r2modman',
- win: {
- target: ['nsis', 'portable'],
- icon: 'src/assets/icon.ico'
- },
- nsis: {
- oneClick: false,
- allowToChangeInstallationDirectory: true,
- allowElevation: false,
- perMachine: false,
- include: 'build/installer.nsh'
- },
- linux: {
- target: ['AppImage', 'tar.gz', 'deb', 'rpm', 'pacman'],
- icon: 'src/assets/icon',
- maintainer: 'ebkr',
- vendor: 'ebkr',
- synopsis: 'Risk of Rain 2 Mod Manager',
- category: 'Game',
- mimeTypes: [
- "x-scheme-handler/ror2mm"
- ]
- },
- mac: {
- category: "games",
- icon: "src/assets/icon"
- }
- },
-
- // More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
- nodeIntegration: true,
-
- extendWebpack(/* cfg */) {
- // do something with Electron main process Webpack cfg
- // chainWebpack also available besides this extendWebpack
- }
- }
- };
-});
diff --git a/quasar.config.ts b/quasar.config.ts
new file mode 100644
index 000000000..34ce00b37
--- /dev/null
+++ b/quasar.config.ts
@@ -0,0 +1,262 @@
+// Configuration for your app
+// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file
+
+import { defineConfig } from '#q-app/wrappers';
+import { nodePolyfills } from 'vite-plugin-node-polyfills';
+
+export default defineConfig((ctx) => {
+ return {
+ // https://v2.quasar.dev/quasar-cli-vite/prefetch-feature
+ // preFetch: true,
+
+ // app boot file (/src/boot)
+ // --> boot files are part of "main.js"
+ // https://v2.quasar.dev/quasar-cli-vite/boot-files
+ boot: [
+ 'i18n',
+ // 'axios',
+ 'floating-vue'
+ ],
+
+ // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#css
+ css: [
+ 'app.scss'
+ ],
+
+ // https://github.com/quasarframework/quasar/tree/dev/extras
+ extras: [
+ // 'ionicons-v4',
+ // 'mdi-v7',
+ // 'fontawesome-v6',
+ // 'eva-icons',
+ // 'themify',
+ // 'line-awesome',
+ // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
+
+ 'roboto-font', // optional, you are not bound to it
+ 'material-icons', // optional, you are not bound to it
+ ],
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#build
+ build: {
+ target: {
+ browser: [ 'esnext' ],
+ node: 'esnext'
+ },
+
+ typescript: {
+ strict: true,
+ vueShim: true
+ // extendTsConfig (tsConfig) {}
+ },
+
+ vueRouterMode: 'history', // available values: 'hash', 'history'
+ // vueRouterBase,
+ // vueDevtools,
+ // vueOptionsAPI: false,
+
+ rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
+
+ publicPath: '/',
+ // analyze: true,
+ // env: {},
+ // rawDefine: {}
+ // ignorePublicFolder: true,
+ minify: 'esbuild',
+ polyfillModulePreload: true,
+ // distDir
+
+ // extendViteConf (viteConf) {},
+ viteVuePluginOptions: {
+ template: {
+ compilerOptions: {
+ isCustomElement: (tag) => ["strike"].includes(tag)
+ }
+ }
+ },
+
+ win: {
+ publish: {
+ provider: 'github'
+ }
+ },
+ linux: {
+ publish: {
+ provider: 'github'
+ }
+ },
+
+ vitePlugins: [
+ ]
+ },
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#devserver
+ devServer: {
+ https: false,
+ port: 9020,
+ open: true // opens browser window automatically
+ },
+
+ // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework
+ framework: {
+ config: {},
+
+ iconSet: 'material-icons', // Quasar icon set
+ lang: 'en-US', // Quasar language pack
+
+ // For special cases outside of where the auto-import strategy can have an impact
+ // (like functional components as one of the examples),
+ // you can manually specify Quasar components/directives to be available everywhere:
+ //
+ // components: [],
+ // directives: [],
+
+ // Quasar plugins
+ plugins: []
+ },
+
+ // animations: 'all', // --- includes all animations
+ // https://v2.quasar.dev/options/animations
+ animations: [],
+
+ // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#sourcefiles
+ sourceFiles: {
+ rootComponent: 'src/AppWrapper.vue',
+ // router: 'src/router/index',
+ // store: 'src/store/index',
+ // pwaRegisterServiceWorker: 'src-pwa/register-service-worker',
+ // pwaServiceWorker: 'src-pwa/custom-service-worker',
+ // pwaManifestFile: 'src-pwa/manifest.json',
+ electronMain: process.env.NODE_ENV === 'development' ? 'src-electron/electron-main.dev' : 'src-electron/electron-main',
+ electronPreload: 'src-electron/electron-preload'
+ // bexManifestFile: 'src-bex/manifest.json
+ },
+
+ // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr
+ ssr: {
+ prodPort: 3000, // The default port that the production server should use
+ // (gets superseded if process.env.PORT is specified at runtime)
+
+ middlewares: [
+ 'render' // keep this as last one
+ ],
+
+ // extendPackageJson (json) {},
+ // extendSSRWebserverConf (esbuildConf) {},
+
+ // manualStoreSerialization: true,
+ // manualStoreSsrContextInjection: true,
+ // manualStoreHydration: true,
+ // manualPostHydrationTrigger: true,
+
+ pwa: false
+ // pwaOfflineHtmlFilename: 'offline.html', // do NOT use index.html as name!
+
+ // pwaExtendGenerateSWOptions (cfg) {},
+ // pwaExtendInjectManifestOptions (cfg) {}
+ },
+
+ // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
+ pwa: {
+ workboxMode: 'GenerateSW' // 'GenerateSW' or 'InjectManifest'
+ // swFilename: 'sw.js',
+ // manifestFilename: 'manifest.json',
+ // extendManifestJson (json) {},
+ // useCredentialsForManifestTag: true,
+ // injectPwaMetaTags: false,
+ // extendPWACustomSWConf (esbuildConf) {},
+ // extendGenerateSWOptions (cfg) {},
+ // extendInjectManifestOptions (cfg) {}
+ },
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova
+ cordova: {
+ // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
+ },
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor
+ capacitor: {
+ hideSplashscreen: true
+ },
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron
+ electron: {
+
+ // extendElectronMainConf (esbuildConf) {},
+ // extendElectronPreloadConf (esbuildConf) {},
+
+ // extendPackageJson (json) {},
+
+ // Electron preload scripts (if any) from /src-electron, WITHOUT file extension
+ preloadScripts: [ 'electron-preload' ],
+
+ // specify the debugging port to use for the Electron app when running in development mode
+ inspectPort: 5858,
+
+ bundler: 'builder', // 'packager' or 'builder'
+
+ packager: {
+ // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
+
+ // OS X / Mac App Store
+ // appBundleId: '',
+ // appCategoryType: '',
+ // osxSign: '',
+ // protocol: 'myapp://path',
+
+ // Windows only
+ // win32metadata: { ... }
+ },
+
+ builder: {
+ // https://www.electron.build/configuration/configuration
+
+ appId: 'ebkr-r2modman',
+ win: {
+ target: ['nsis', 'portable'],
+ icon: 'src/assets/icon.ico'
+ },
+ nsis: {
+ oneClick: false,
+ allowToChangeInstallationDirectory: true,
+ allowElevation: false,
+ perMachine: false,
+ include: 'build/installer.nsh'
+ },
+ linux: {
+ target: ['AppImage', 'tar.gz', 'deb', 'rpm', 'pacman'],
+ icon: 'src/assets/icon',
+ maintainer: 'ebkr',
+ vendor: 'ebkr',
+ synopsis: 'Risk of Rain 2 Mod Manager',
+ category: 'Game',
+ mimeTypes: [
+ "x-scheme-handler/ror2mm"
+ ]
+ },
+ mac: {
+ category: "games",
+ icon: "src/assets/icon"
+ }
+ },
+
+ nodeIntegration: true,
+ },
+
+ // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
+ bex: {
+ // extendBexScriptsConf (esbuildConf) {},
+ // extendBexManifestJson (json) {},
+
+ /**
+ * The list of extra scripts (js/ts) not in your bex manifest that you want to
+ * compile and use in your browser extension. Maybe dynamic use them?
+ *
+ * Each entry in the list should be a relative filename to /src-bex/
+ *
+ * @example [ 'my-script.ts', 'sub-folder/my-other-script.js' ]
+ */
+ extraScripts: []
+ }
+ }
+});
diff --git a/quasar.extensions.json b/quasar.extensions.json
deleted file mode 100644
index c2084877e..000000000
--- a/quasar.extensions.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "@quasar/typescript": {
- "webpack": "plugin",
- "rename": true,
- "vscode": true,
- "prettier": true
- },
- "@quasar/testing-unit-jest": {
- "babel": "babelrc",
- "options": [
- "scripts",
- "typescript",
- "SFC",
- "wallabyjs",
- "majestic"
- ]
- }
-}
\ No newline at end of file
diff --git a/quasar.testing.json b/quasar.testing.json
deleted file mode 100644
index a9da8280f..000000000
--- a/quasar.testing.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "unit-jest": {
- "runnerCommand": "jest --ci"
- }
-}
diff --git a/src-electron/electron-env.d.ts b/src-electron/electron-env.d.ts
new file mode 100644
index 000000000..b05aa81e9
--- /dev/null
+++ b/src-electron/electron-env.d.ts
@@ -0,0 +1,8 @@
+declare namespace NodeJS {
+ interface ProcessEnv {
+ QUASAR_PUBLIC_FOLDER: string;
+ QUASAR_ELECTRON_PRELOAD_FOLDER: string;
+ QUASAR_ELECTRON_PRELOAD_EXTENSION: string;
+ APP_URL: string;
+ }
+}
diff --git a/src-electron/electron-flag.d.ts b/src-electron/electron-flag.d.ts
deleted file mode 100644
index a78cbf501..000000000
--- a/src-electron/electron-flag.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
-// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
-import "quasar/dist/types/feature-flag";
-
-declare module "quasar/dist/types/feature-flag" {
- interface QuasarFeatureFlags {
- electron: true;
- }
-}
diff --git a/src-electron/electron-main.dev.ts b/src-electron/electron-main.dev.ts
new file mode 100644
index 000000000..e5c6c6a79
--- /dev/null
+++ b/src-electron/electron-main.dev.ts
@@ -0,0 +1,7 @@
+/**
+ * This file is used specifically and only for development. It installs
+ * `electron-debug` & `vue-devtools`. There shouldn't be any need to
+ * modify this file, but it can be used to extend your development
+ * environment.
+ */
+import './electron-main'
diff --git a/src-electron/main-process/electron-main.js b/src-electron/electron-main.ts
similarity index 60%
rename from src-electron/main-process/electron-main.js
rename to src-electron/electron-main.ts
index cb1673503..4ad4fc14d 100644
--- a/src-electron/main-process/electron-main.js
+++ b/src-electron/electron-main.ts
@@ -1,9 +1,12 @@
import { app, BrowserWindow, ipcMain, nativeTheme, protocol } from 'electron';
-import Listeners from './ipcListeners';
-import Persist from './window-state-persist';
+import { Listeners } from './ipcListeners';
+import { Persist } from './window-state-persist';
import path from 'path';
import ipcServer from 'node-ipc';
-import * as fs from 'fs';
+import fs from 'fs';
+import { fileURLToPath } from 'url';
+import 'app/src-electron/ipc/init-ipc';
+import { hookIpc } from 'app/src-electron/ipc/init-ipc';
app.allowRendererProcessReuse = true;
@@ -18,6 +21,10 @@ try {
* Set `__statics` path to static files in production;
* The reason we are setting it here is that the path needs to be evaluated at runtime
*/
+
+const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
+const __dirname = path.dirname(__filename);
+
if (process.env.PROD) {
global.__statics = __dirname;
global.__statics = path.join(__dirname, 'statics').replace(/\\/g, '\\\\');
@@ -26,10 +33,7 @@ if (process.env.PROD) {
let mainWindow;
-function createWindow() {
- /**
- * Initial window options
- */
+async function createWindow() {
const windowSize = Persist.getSize(app, {
defaultWidth: 1200,
@@ -40,16 +44,21 @@ function createWindow() {
width: windowSize.width,
height: windowSize.height,
useContentSize: true,
+ icon: path.resolve(__dirname, 'icons/icon.png'),
+ autoHideMenuBar: process.env.PROD,
webPreferences: {
- nodeIntegration: true,
- nodeIntegrationInWorker: true,
- webSecurity: false,
- contextIsolation: false
- },
- icon: path.join(__dirname, 'icon.png'),
- autoHideMenuBar: process.env.PROD
+ preload: path.resolve(
+ fileURLToPath(new URL('.', import.meta.url)),
+ path.join(process.env.QUASAR_ELECTRON_PRELOAD_FOLDER, 'electron-preload' + process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION)
+ ),
+ // TODO - Remove and find an appropriate workaround for CORS blocking by Electron
+ // Likely workaround is to move network requests to backend
+ webSecurity: false
+ }
});
+ hookIpc(mainWindow);
+
if (windowSize.maximized) {
mainWindow.maximize();
}
@@ -59,15 +68,19 @@ function createWindow() {
// Initialise client to server communication listener
new Listeners(mainWindow, app);
- mainWindow.loadURL(process.env.APP_URL);
+ if (process.env.DEV) {
+ await mainWindow.loadURL(process.env.APP_URL);
+ } else {
+ await mainWindow.loadFile('index.html');
+ }
mainWindow.on('closed', () => {
mainWindow = null;
});
}
-app.on('ready', () => {
- createWindow();
+app.on('ready', async () => {
+ await createWindow();
let reqLockSuccess = app.requestSingleInstanceLock();
if (!reqLockSuccess) {
// If this isn't the single instance,
@@ -95,15 +108,33 @@ app.on('ready', () => {
}
});
+protocol.registerSchemesAsPrivileged([
+ {
+ scheme: 'public',
+ privileges: {
+ standard: true,
+ secure: true,
+ supportFetchAPI: true
+ }
+ }
+])
+
app.whenReady().then(() => {
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = request.url.replace('file:///', '');
if (fs.existsSync(pathname)) {
callback(pathname);
} else {
- callback(path.join(__statics, "unknown.png"));
+ callback(path.join(global.__statics, 'unknown.png'));
}
});
+
+ protocol.handle('public', async (req: any) => {
+ const publicFolder = path.resolve(__dirname, process.env.QUASAR_PUBLIC_FOLDER);
+ const filePath = (req.url as string).substring("public://".length).replace(/\\/g, path.sep);
+ const fileContent = await fs.promises.readFile(path.join(publicFolder, filePath))
+ return new Response(fileContent);
+ })
});
app.on('window-all-closed', () => {
diff --git a/src-electron/electron-preload.ts b/src-electron/electron-preload.ts
new file mode 100644
index 000000000..b40751b82
--- /dev/null
+++ b/src-electron/electron-preload.ts
@@ -0,0 +1,31 @@
+/**
+ * This file is used specifically for security reasons.
+ * Here you can access Nodejs stuff and inject functionality into
+ * the renderer thread (accessible there through the "window" object)
+ *
+ * WARNING!
+ * If you import anything from node_modules, then make sure that the package is specified
+ * in package.json > dependencies and NOT in devDependencies
+ *
+ * Example (injects window.myAPI.doAThing() into renderer thread):
+ *
+ * import { contextBridge } from 'electron'
+ *
+ * contextBridge.exposeInMainWorld('myAPI', {
+ * doAThing: () => {}
+ * })
+ *
+ * WARNING!
+ * If accessing Node functionality (like importing @electron/remote) then in your
+ * electron-main.ts you will need to set the following when you instantiate BrowserWindow:
+ *
+ * mainWindow = new BrowserWindow({
+ * // ...
+ * webPreferences: {
+ * // ...
+ * sandbox: false // <-- to be able to import @electron/remote in preload script
+ * }
+ * }
+ */
+
+import "./preload/expose-preload";
diff --git a/src-electron/icons/icon.icns b/src-electron/icons/icon.icns
index 9cc7e8e5a..8a28a4beb 100644
Binary files a/src-electron/icons/icon.icns and b/src-electron/icons/icon.icns differ
diff --git a/src-electron/icons/icon.ico b/src-electron/icons/icon.ico
index ae49a0194..6944eda46 100644
Binary files a/src-electron/icons/icon.ico and b/src-electron/icons/icon.ico differ
diff --git a/src-electron/icons/icon.png b/src-electron/icons/icon.png
new file mode 100644
index 000000000..4347f17cf
Binary files /dev/null and b/src-electron/icons/icon.png differ
diff --git a/src-electron/ipc/electron-hook.ts b/src-electron/ipc/electron-hook.ts
new file mode 100644
index 000000000..268722cf3
--- /dev/null
+++ b/src-electron/ipc/electron-hook.ts
@@ -0,0 +1,20 @@
+import { BrowserWindow, ipcMain, shell, clipboard } from 'electron';
+
+export function hookElectronIpc(browserWindow: BrowserWindow) {
+ ipcMain.on('electron:shell:openExternal', (event, url) => {
+ shell.openExternal(url)
+ });
+
+ ipcMain.on('electron:shell:selectFile', (event, filePath) => {
+ shell.showItemInFolder(filePath)
+ });
+
+ ipcMain.on('electron:shell:openPath', (event, filePath) => {
+ shell.openPath(filePath)
+ });
+
+ ipcMain.on('electron:clipboard:copyText', (event, text) => {
+ clipboard.writeText(text);
+ event.returnValue = true;
+ });
+}
diff --git a/src-electron/ipc/init-ipc.ts b/src-electron/ipc/init-ipc.ts
new file mode 100644
index 000000000..67e802018
--- /dev/null
+++ b/src-electron/ipc/init-ipc.ts
@@ -0,0 +1,16 @@
+import { BrowserWindow } from 'electron';
+import { hookPathIpc } from './node-path-impl';
+import { hookChildProcessIpc } from './node-child-process-impl';
+import { hookFsIpc } from 'app/src-electron/ipc/node-fs-impl';
+import { hookZipIpc } from 'app/src-electron/ipc/zip-hook';
+import { hookElectronIpc } from 'app/src-electron/ipc/electron-hook';
+import {hookOsIpc} from "app/src-electron/ipc/node-os-impl";
+
+export function hookIpc(browserWindow: BrowserWindow) {
+ hookPathIpc(browserWindow);
+ hookChildProcessIpc(browserWindow);
+ hookFsIpc(browserWindow);
+ hookOsIpc(browserWindow);
+ hookZipIpc(browserWindow);
+ hookElectronIpc(browserWindow);
+}
diff --git a/src-electron/ipc/node-child-process-impl.ts b/src-electron/ipc/node-child-process-impl.ts
new file mode 100644
index 000000000..b9f253a41
--- /dev/null
+++ b/src-electron/ipc/node-child-process-impl.ts
@@ -0,0 +1,16 @@
+import { BrowserWindow, ipcMain } from 'electron';
+import ChildProcess from 'child_process';
+
+export function hookChildProcessIpc(browserWindow: BrowserWindow) {
+ ipcMain.on("node:child_process:execSync", (event, path) => {
+ event.returnValue = ChildProcess.execSync(path).toString();
+ })
+
+ ipcMain.handle("node:child_process:exec", (event, path, options) => {
+ return new Promise(resolve => {
+ ChildProcess.exec(path, options, err => {
+ resolve(err);
+ });
+ })
+ })
+}
diff --git a/src-electron/ipc/node-fs-impl.ts b/src-electron/ipc/node-fs-impl.ts
new file mode 100644
index 000000000..c2ada96a4
--- /dev/null
+++ b/src-electron/ipc/node-fs-impl.ts
@@ -0,0 +1,122 @@
+import { BrowserWindow, ipcMain } from 'electron';
+import fs from 'fs';
+import path from 'path';
+
+export function hookFsIpc(browserWindow: BrowserWindow) {
+ ipcMain.handle('node:fs:writeFile', (event, path, content) => {
+ return fs.promises.writeFile(path, content);
+ });
+
+ ipcMain.handle('node:fs:readFile', (event, path) => {
+ return fs.promises.readFile(path, {
+ encoding: 'utf8'
+ });
+ });
+
+ ipcMain.handle('node:fs:exists', async (event, path) => {
+ return exists(path);
+ });
+
+ ipcMain.handle('node:fs:mkdirs', async (event, path) => {
+ return mkdirs(path);
+ });
+
+ ipcMain.handle('node:fs:readdir', (event, path) => {
+ return fs.promises.readdir(path);
+ });
+
+ ipcMain.handle('node:fs:stat', (event, path) => {
+ return fs.promises.stat(path).then(result => generateSerializableStat(result));
+ });
+
+ ipcMain.handle('node:fs:lstat', (event, path) => {
+ return fs.promises.lstat(path).then(result => generateSerializableStat(result));
+ });
+
+ ipcMain.handle('node:fs:rmdir', (event, path) => {
+ return fs.promises.rmdir(path);
+ });
+
+ ipcMain.handle('node:fs:unlink', (event, path) => {
+ return fs.promises.unlink(path);
+ });
+
+ ipcMain.handle('node:fs:realpath', (event, path) => {
+ return fs.promises.realpath(path);
+ });
+
+ ipcMain.handle('node:fs:rename', (event, path, newPath) => {
+ return fs.promises.rename(path, newPath);
+ });
+
+ ipcMain.handle('node:fs:chmod', (event, path, mode) => {
+ return fs.promises.chmod(path, mode);
+ });
+
+ ipcMain.handle('node:fs:copyFile', (event, from, to) => {
+ return copyFile(from, to);
+ });
+
+ ipcMain.handle('node:fs:copyFolder', async (event, from, to) => {
+ return copyFolder(from, to);
+ });
+
+ ipcMain.handle('node:fs:base64FromZip', (event, path) => {
+ return fs.promises.readFile(path, {
+ encoding: 'base64'
+ });
+ });
+
+ ipcMain.handle('node:fs:setModifiedTime', (event, path, time) => {
+ return fs.promises.utimes(path, time, time)
+ });
+}
+
+async function copyFile(from: string, to: string) {
+ return fs.promises.copyFile(from, to)
+}
+
+async function copyFolder(from: string, to: string) {
+ return fs.promises.readdir(from)
+ .then(async result => {
+ for (const item of result) {
+ const fromLstat = await fs.promises.lstat(path.join(from, item));
+ if (fromLstat.isDirectory()) {
+ const toDirectoryExists = await exists(path.join(to, item));
+ if (!toDirectoryExists) {
+ await mkdirs(path.join(to, item));
+ }
+ await copyFolder(path.join(from, item), path.join(to, item));
+ } else {
+ await mkdirs(path.dirname(path.join(to, item)))
+ await copyFile(path.join(from, item), path.join(to, item));
+ }
+ }
+ });
+}
+
+async function mkdirs(mkdirPath: string) {
+ return fs.promises.mkdir(mkdirPath, { recursive: true });
+}
+
+async function exists(path: string) {
+ return fs.promises.access(path, fs.constants.F_OK)
+ .then(() => true)
+ .catch(() => false);
+}
+
+type SerializableStat = Omit & {
+ isDirectory: boolean;
+ isFile: boolean;
+};
+
+function generateSerializableStat(statLike: fs.Stats): SerializableStat {
+ const unpackedStatLike = {
+ ...statLike
+ } as fs.StatsBase;
+ return {
+ ...unpackedStatLike,
+ isDirectory: statLike.isDirectory(),
+ isFile: statLike.isFile(),
+ };
+}
diff --git a/src-electron/ipc/node-os-impl.ts b/src-electron/ipc/node-os-impl.ts
new file mode 100644
index 000000000..394496761
--- /dev/null
+++ b/src-electron/ipc/node-os-impl.ts
@@ -0,0 +1,8 @@
+import {BrowserWindow, ipcMain} from "electron";
+import os from "os";
+
+export function hookOsIpc(browserWindow: BrowserWindow) {
+ ipcMain.on('node:os:homedir', (event) => {
+ event.returnValue = os.homedir();
+ })
+}
diff --git a/src-electron/ipc/node-path-impl.ts b/src-electron/ipc/node-path-impl.ts
new file mode 100644
index 000000000..850f6e281
--- /dev/null
+++ b/src-electron/ipc/node-path-impl.ts
@@ -0,0 +1,23 @@
+import { BrowserWindow, ipcMain } from 'electron';
+import path from 'path';
+
+export function hookPathIpc(browserWindow: BrowserWindow) {
+ ipcMain.on("node:path:join", (event, ...args) => {
+ event.returnValue = path.join(...args);
+ });
+ ipcMain.on("node:path:basename", (event, toResolve) => {
+ event.returnValue = path.basename(toResolve);
+ });
+ ipcMain.on("node:path:resolve", (event, ...args) => {
+ event.returnValue = path.resolve(...args);
+ });
+ ipcMain.on("node:path:extname", (event, pathAsString: string) => {
+ event.returnValue = path.extname(pathAsString);
+ });
+ ipcMain.on("node:path:relative", (event, pathOne: string, pathTwo: string) => {
+ event.returnValue = path.relative(pathOne, pathTwo);
+ });
+ ipcMain.on("node:path:dirname", (event, pathAsString: string) => {
+ event.returnValue = path.dirname(pathAsString);
+ });
+}
diff --git a/src-electron/ipc/zip-hook.ts b/src-electron/ipc/zip-hook.ts
new file mode 100644
index 000000000..95019c760
--- /dev/null
+++ b/src-electron/ipc/zip-hook.ts
@@ -0,0 +1,104 @@
+import { BrowserWindow, ipcMain } from 'electron';
+import AdmZip from 'adm-zip';
+import path from 'path';
+
+let zipCreatorIdentifier = 0;
+const zipCreatorCache = new Map();
+
+export function hookZipIpc(browserWindow: BrowserWindow) {
+ ipcMain.handle('zip:extractAllTo', (event, zip: string, outputFolder: string) => {
+ return new Promise((resolve, reject) => {
+ const adm = new AdmZip(zip);
+ outputFolder = outputFolder.replace(/\\/g, '/');
+ adm.extractAllToAsync(outputFolder, true, error => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(error);
+ }
+ });
+ });
+ });
+
+ ipcMain.handle('zip:readFile', (event, zip: string, fileName: string) => {
+ return new Promise((resolve, reject) => {
+ const adm = new AdmZip(zip);
+ return adm.readFileAsync(fileName, (data, err) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(data?.toString('utf8'));
+ }
+ });
+ });
+ });
+
+ ipcMain.handle('zip:getEntries', (event, zip: string) => {
+ return new Promise((resolve, reject) => {
+ const adm = new AdmZip(zip);
+ try {
+ const entries = adm.getEntries();
+ resolve(JSON.stringify(entries));
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+
+ ipcMain.handle('zip:extractEntryTo', (event, zip: string, target: string, outputPath: string) => {
+ return new Promise((resolve, reject) => {
+ try {
+ const adm = new AdmZip(zip);
+ const safeTarget = target.replace(/\\/g, '/');
+ outputPath = outputPath.replace(/\\/g, '/');
+ var fullPath = path.join(outputPath, safeTarget).replace(/\\/g, '/');
+ if(!path.posix.normalize(fullPath).startsWith(outputPath))
+ {
+ throw new Error("Entry " + target + " would extract outside of expected folder");
+ }
+ adm.extractEntryTo(target, outputPath, true, true);
+ return resolve(undefined);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+
+ ipcMain.on('zip:create:new', (event) => {
+ const identifier = zipCreatorIdentifier++;
+ zipCreatorCache.set(identifier, new AdmZip());
+ event.returnValue = identifier;
+ });
+
+ ipcMain.handle(`zip:create:addBuffer`, async (event, identifier, fileName: string, data: Buffer) => {
+ const zip = zipCreatorCache.get(identifier);
+ if (zip === undefined) {
+ throw new Error(`No zip was present in temporary creator with identifier: ${identifier}`);
+ }
+ zip.addFile(fileName, data);
+ });
+
+ ipcMain.handle(`zip:create:addFolder`, async (event, identifier, zippedFolderName: string, folderNameOnDisk: string) => {
+ const zip = zipCreatorCache.get(identifier);
+ if (zip === undefined) {
+ throw new Error(`No zip was present in temporary creator with identifier: ${identifier}`);
+ }
+ zip.addLocalFolder(folderNameOnDisk, zippedFolderName);
+ });
+
+ ipcMain.handle(`zip:create:finalize`, (event, identifier, outputPath: string) => {
+ return new Promise((resolve, reject) => {
+ const zip = zipCreatorCache.get(identifier);
+ if (zip === undefined) {
+ throw new Error(`No zip was present in temporary creator with identifier: ${identifier}`);
+ }
+ zip.writeZip(outputPath, err => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(undefined);
+ }
+ });
+ });
+ });
+}
diff --git a/src-electron/ipcListeners.ts b/src-electron/ipcListeners.ts
new file mode 100644
index 000000000..6f0d4bfb3
--- /dev/null
+++ b/src-electron/ipcListeners.ts
@@ -0,0 +1,93 @@
+import { ipcMain, dialog, App, BrowserWindow, Menu, MenuItem } from 'electron';
+import electronUpdater from 'electron-updater';
+import os from 'os';
+import { fileURLToPath } from 'url';
+import path from 'path';
+
+let browserWindow: BrowserWindow;
+let app: App;
+
+export class Listeners {
+ constructor(window: BrowserWindow, electronApp: App) {
+ browserWindow = window;
+ app = electronApp;
+ }
+}
+
+ipcMain.on('get-browser-window', () => {
+ browserWindow.webContents.send('receive-browser-window', browserWindow);
+});
+
+ipcMain.handle('update-app', async () => {
+ if (typeof process.env.APPIMAGE !== 'undefined' || !process.execPath.startsWith(os.tmpdir())) {
+ electronUpdater.autoUpdater.autoDownload = true;
+ await electronUpdater.autoUpdater.checkForUpdatesAndNotify();
+ }
+});
+
+ipcMain.on('install-via-thunderstore', (installString) => {
+ browserWindow.webContents.send('install-from-thunderstore-string', installString);
+});
+
+ipcMain.handle('get-appData-directory', () => {
+ return app.getPath('appData');
+});
+
+ipcMain.handle('get-is-portable', async () => {
+ let isPortable = false;
+ switch (process.platform) {
+ case 'win32':
+ isPortable = process.execPath.startsWith(os.tmpdir());
+ break;
+ case 'linux':
+ // The correct way to handle this should be
+ // isPortable = typeof process.env.APPIMAGE !== "undefined";
+ // but since Manager.vue needs a refactor, we do the opposite
+ isPortable = typeof process.env.APPIMAGE === 'undefined';
+ break;
+ }
+ return isPortable;
+});
+
+ipcMain.on('restart', () => {
+ app.relaunch();
+ app.exit();
+});
+
+ipcMain.on('get-assets-path', () => {
+ if (process.env.PROD) {
+ browserWindow.webContents.send('receive-assets-path', global.__statics);
+ } else {
+ browserWindow.webContents.send('receive-assets-path', 'src/statics/');
+ }
+});
+
+ipcMain.handle('show-open-dialog', (event, fileOpts) => {
+ return dialog.showOpenDialog(browserWindow, fileOpts);
+});
+
+ipcMain.on('get-process-platform', (event) => {
+ event.returnValue = process.platform;
+});
+
+ipcMain.on('get-statics-directory', (event) => {
+ const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
+ const __dirname = path.dirname(__filename);
+ event.returnValue = __dirname;
+});
+
+ipcMain.on('electron:showContextMenu', (event, options: any) => {
+ const templateItems: MenuItem[] = [];
+ templateItems.push(new MenuItem({
+ label: 'Copy',
+ role: 'copy'
+ }));
+ if (!options.readonly) {
+ templateItems.push(new MenuItem({
+ label: 'Paste',
+ role: 'paste'
+ }));
+ }
+ const menu = Menu.buildFromTemplate(templateItems);
+ menu.popup();
+})
diff --git a/src-electron/main-process/electron-main.dev.js b/src-electron/main-process/electron-main.dev.js
deleted file mode 100644
index dda445d90..000000000
--- a/src-electron/main-process/electron-main.dev.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * This file is used specifically and only for development. It installs
- * `electron-debug` & `vue-devtools`. There shouldn't be any need to
- * modify this file, but it can be used to extend your development
- * environment.
- */
-
-import electronDebug from 'electron-debug'
-import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
-import { app, BrowserWindow } from 'electron'
-
-app.whenReady().then(() => {
- // allow for a small delay for mainWindow to be created
- setTimeout(() => {
- // Install `electron-debug` with `devtron`
- electronDebug({ showDevTools: false })
-
- // Install vuejs devtools
- installExtension(VUEJS_DEVTOOLS)
- .then(name => {
- console.log(`Added Extension: ${name}`)
- // get main window
- const win = BrowserWindow.getFocusedWindow()
- if (win) {
- win.webContents.on('did-frame-finish-load', () => {
- win.webContents.once('devtools-opened', () => {
- win.webContents.focus()
- })
- // open electron debug
- console.log('Opening dev tools')
- win.webContents.openDevTools()
- })
- }
- })
- .catch(err => {
- console.log('An error occurred: ', err)
- })
- }, 250)
-})
-
-import './electron-main'
diff --git a/src-electron/main-process/ipcListeners.js b/src-electron/main-process/ipcListeners.js
deleted file mode 100644
index 6f64b2793..000000000
--- a/src-electron/main-process/ipcListeners.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { ipcMain, dialog } from 'electron';
-import { autoUpdater } from 'electron-updater';
-import os from 'os';
-
-let browserWindow;
-let app;
-
-export default class Listeners {
- constructor(window, electronApp) {
- browserWindow = window;
- app = electronApp;
- }
-}
-
-ipcMain.on('get-browser-window', ()=>{
- browserWindow.webContents.send('receive-browser-window', browserWindow);
-});
-
-ipcMain.on('update-app', ()=>{
- if (typeof process.env.APPIMAGE !== "undefined" || !process.execPath.startsWith(os.tmpdir())) {
- autoUpdater.autoDownload = true;
- autoUpdater.checkForUpdatesAndNotify();
- browserWindow.webContents.send('update-done');
- } else {
- browserWindow.webContents.send('update-done');
- }
-});
-
-ipcMain.on('install-via-thunderstore', (installString) => {
- browserWindow.webContents.send('install-from-thunderstore-string', installString);
-});
-
-ipcMain.on('get-appData-directory', ()=>{
- browserWindow.webContents.send('receive-appData-directory', app.getPath('appData'));
-});
-
-ipcMain.on('get-is-portable', ()=>{
- let isPortable = false;
- switch(process.platform){
- case "win32":
- isPortable = process.execPath.startsWith(os.tmpdir());
- break;
- case "linux":
- // The correct way to handle this should be
- // isPortable = typeof process.env.APPIMAGE !== "undefined";
- // but since Manager.vue needs a refactor, we do the opposite
- isPortable = typeof process.env.APPIMAGE === "undefined";
- break;
- }
- browserWindow.webContents.send('receive-is-portable', isPortable);
-});
-
-ipcMain.on('restart', ()=>{
- app.relaunch();
- app.exit();
-});
-
-ipcMain.on('get-assets-path', ()=>{
- if (process.env.PROD) {
- browserWindow.webContents.send('receive-assets-path', global.__statics);
- } else {
- browserWindow.webContents.send('receive-assets-path', 'src/statics/');
- }
-});
-
-ipcMain.on('show-open-dialog', (arg, fileOpts) => {
- dialog.showOpenDialog(browserWindow, fileOpts).then(r => {
- browserWindow.webContents.send('receive-open-dialog', r);
- });
-});
-
diff --git a/src-electron/preload/app-preload-globals.ts b/src-electron/preload/app-preload-globals.ts
new file mode 100644
index 000000000..b64e870aa
--- /dev/null
+++ b/src-electron/preload/app-preload-globals.ts
@@ -0,0 +1,32 @@
+import {ipcRenderer} from "electron/renderer";
+
+export async function getAppDataDirectory(): Promise {
+ return ipcRenderer.invoke('get-appData-directory');
+}
+
+export async function isApplicationPortable(): Promise {
+ return ipcRenderer.invoke('get-is-portable');
+}
+
+export function getPlatform(): string {
+ return ipcRenderer.sendSync('get-process-platform');
+}
+
+export async function checkForApplicationUpdates(): Promise {
+ return ipcRenderer.invoke('update-app');
+}
+
+export function getStaticsDirectory(): string {
+ return ipcRenderer.sendSync('get-statics-directory');
+}
+
+export function restart() {
+ ipcRenderer.send('restart');
+}
+
+export function hookModInstallProtocol(callback: (data: any) => void) {
+ ipcRenderer.removeAllListeners('install-from-thunderstore-string');
+ ipcRenderer.on('install-from-thunderstore-string', (_sender: any, data: string) => {
+ callback(data);
+ });
+}
diff --git a/src-electron/preload/electron-ipc-preload.ts b/src-electron/preload/electron-ipc-preload.ts
new file mode 100644
index 000000000..ce835519f
--- /dev/null
+++ b/src-electron/preload/electron-ipc-preload.ts
@@ -0,0 +1,36 @@
+import { ipcRenderer, OpenDialogOptions } from 'electron';
+
+export function openExternal(url: string) {
+ ipcRenderer.send('electron:shell:openExternal', url);
+}
+
+export function selectFile(url: string) {
+ ipcRenderer.send('electron:shell:selectFile', url);
+}
+
+export function openPath(url: string) {
+ ipcRenderer.send('electron:shell:openPath', url);
+}
+export async function selectFolderDialog(options: any) {
+ const fileOpts = options as unknown as OpenDialogOptions;
+ fileOpts.properties = ['openDirectory', 'showHiddenFiles'];
+
+ return ipcRenderer.invoke('show-open-dialog', options)
+ .then(result => result.filePaths);
+}
+
+export async function selectFileDialog(options: any) {
+ const fileOpts = options as unknown as OpenDialogOptions;
+ fileOpts.properties = ['openFile', 'showHiddenFiles'];
+
+ return ipcRenderer.invoke('show-open-dialog', options)
+ .then(result => result.filePaths);
+}
+
+export function copyToClipboard(value: string) {
+ ipcRenderer.sendSync('electron:clipboard:copyText', value);
+}
+
+export function showContextMenu(options: any) {
+ ipcRenderer.send('electron:showContextMenu', options);
+}
diff --git a/src-electron/preload/expose-preload.ts b/src-electron/preload/expose-preload.ts
new file mode 100644
index 000000000..4fc97c54d
--- /dev/null
+++ b/src-electron/preload/expose-preload.ts
@@ -0,0 +1,21 @@
+import { contextBridge } from 'electron';
+import * as path from './node-path';
+import * as child_process from './node-child-process';
+import * as fs from './node-fs';
+import * as buffer from './node-buffer';
+import * as os from './node-os';
+import * as zip from './zip-preload';
+import * as appGlobals from "./app-preload-globals";
+import * as electron from "./electron-ipc-preload";
+
+contextBridge.exposeInMainWorld('node', {
+ path: path,
+ child_process: child_process,
+ fs: fs,
+ buffer: buffer,
+ os: os,
+});
+
+contextBridge.exposeInMainWorld('app', appGlobals);
+contextBridge.exposeInMainWorld('zip', zip);
+contextBridge.exposeInMainWorld('electron', electron);
diff --git a/src-electron/preload/node-buffer.ts b/src-electron/preload/node-buffer.ts
new file mode 100644
index 000000000..5b9f2be6b
--- /dev/null
+++ b/src-electron/preload/node-buffer.ts
@@ -0,0 +1,3 @@
+export function from(data: any, encoding?: 'utf8' | 'base64') {
+ return Buffer.from(data, encoding);
+}
diff --git a/src-electron/preload/node-child-process.ts b/src-electron/preload/node-child-process.ts
new file mode 100644
index 000000000..17769a0bc
--- /dev/null
+++ b/src-electron/preload/node-child-process.ts
@@ -0,0 +1,9 @@
+import { ipcRenderer } from 'electron/renderer';
+
+export function execSync(identifier: string, path: string, options: any) {
+ return ipcRenderer.sendSync('node:child_process:execSync', identifier, path, options);
+}
+
+export function exec(path: string, options: any) {
+ return ipcRenderer.invoke('node:child_process:exec', path, options);
+}
diff --git a/src-electron/preload/node-fs.ts b/src-electron/preload/node-fs.ts
new file mode 100644
index 000000000..168b13503
--- /dev/null
+++ b/src-electron/preload/node-fs.ts
@@ -0,0 +1,65 @@
+import { ipcRenderer } from 'electron/renderer';
+
+export async function writeFile(path: string, content: string | Buffer): Promise {
+ return ipcRenderer.invoke('node:fs:writeFile', path, content);
+}
+
+export async function readFile(path: string) {
+ return ipcRenderer.invoke('node:fs:readFile', path);
+}
+
+export async function readdir(path: string): Promise {
+ return ipcRenderer.invoke('node:fs:readdir', path);
+}
+
+export async function rmdir(path: string) {
+ return ipcRenderer.invoke('node:fs:rmdir', path);
+}
+
+export async function mkdirs(path: string) {
+ return ipcRenderer.invoke('node:fs:mkdirs', path);
+}
+
+export async function exists(path: string) {
+ return ipcRenderer.invoke('node:fs:exists', path);
+}
+
+export async function unlink(path: string) {
+ return ipcRenderer.invoke('node:fs:unlink', path);
+}
+
+export async function stat(path: string) {
+ return ipcRenderer.invoke('node:fs:stat', path);
+}
+
+export async function lstat(path: string) {
+ return ipcRenderer.invoke('node:fs:lstat', path);
+}
+
+export async function realpath(path: string) {
+ return ipcRenderer.invoke('node:fs:realpath', path);
+}
+
+export async function rename(path: string, newPath: string) {
+ return ipcRenderer.invoke('node:fs:rename', path, newPath);
+}
+
+export async function chmod(path: string, mode: string | number) {
+ return ipcRenderer.invoke('node:fs:chmod', path, mode);
+}
+
+export async function copyFile(from: string, to: string) {
+ return ipcRenderer.invoke('node:fs:copyFile', from, to);
+}
+
+export async function copyFolder(from: string, to: string) {
+ return ipcRenderer.invoke('node:fs:copyFolder', from, to);
+}
+
+export async function base64FromZip(path: string) {
+ return ipcRenderer.invoke('node:fs:base64FromZip', path);
+}
+
+export async function setModifiedTime(path: string, time: Date) {
+ return ipcRenderer.invoke('node:fs:setModifiedTime', path, time);
+}
diff --git a/src-electron/preload/node-os.ts b/src-electron/preload/node-os.ts
new file mode 100644
index 000000000..800e1714b
--- /dev/null
+++ b/src-electron/preload/node-os.ts
@@ -0,0 +1,5 @@
+import { ipcRenderer } from 'electron';
+
+export function homedir() {
+ return ipcRenderer.sendSync('node:os:homedir');
+}
diff --git a/src-electron/preload/node-path.ts b/src-electron/preload/node-path.ts
new file mode 100644
index 000000000..1750362b7
--- /dev/null
+++ b/src-electron/preload/node-path.ts
@@ -0,0 +1,23 @@
+import { ipcRenderer } from 'electron/renderer';
+
+export function join(...paths: string[]) {
+ return ipcRenderer.sendSync('node:path:join', ...paths);
+}
+
+export function basename(path: string) {
+ return ipcRenderer.sendSync('node:path:basename', path);
+}
+
+export function resolve(...paths: string[]) {
+ return ipcRenderer.sendSync('node:path:resolve', ...paths);
+}
+
+export function extname(...args: string[]) {
+ return ipcRenderer.sendSync('node:path:extname', ...args)
+}
+export function relative(...args: string[]) {
+ return ipcRenderer.sendSync('node:path:relative', ...args)
+}
+export function dirname(...args: string[]) {
+ return ipcRenderer.sendSync('node:path:dirname', ...args)
+}
diff --git a/src-electron/preload/zip-preload.ts b/src-electron/preload/zip-preload.ts
new file mode 100644
index 000000000..462f5d3f0
--- /dev/null
+++ b/src-electron/preload/zip-preload.ts
@@ -0,0 +1,37 @@
+import { ipcRenderer } from 'electron';
+
+export function extractAllTo(zip: string, outputFolder: string): Promise {
+ return ipcRenderer.invoke('zip:extractAllTo', zip, outputFolder);
+}
+
+export function readFile(zip: string | Buffer, file: string): Promise {
+ return ipcRenderer.invoke('zip:readFile', zip, file);
+}
+
+export function getEntries(zip: string): Promise {
+ return ipcRenderer.invoke('zip:getEntries', zip);
+}
+
+export function extractEntryTo(zip: string | Buffer, target: string, outputPath: string): Promise {
+ return ipcRenderer.invoke('zip:extractEntryTo', zip, target, outputPath);
+}
+
+/**
+ * Create a temporary in-memory zip.
+ * @return number representing identifier for subsequent calls to modify zip.
+ */
+export function createNewTemporaryZip(): number {
+ return ipcRenderer.sendSync(`zip:create:new`);
+}
+
+export function addBufferToTemporaryZip(identifier: number, fileName: string, content: Buffer): Promise {
+ return ipcRenderer.invoke('zip:create:addBuffer', identifier, fileName, content);
+}
+
+export function addFolderToTemporaryZip(identifier: number, zippedFolderName: string, folderNameOnDisk: string): Promise {
+ return ipcRenderer.invoke('zip:create:addFolder', identifier, zippedFolderName, folderNameOnDisk);
+}
+
+export function finalizeTemporaryZip(identifier: number, outputPath: string): Promise {
+ return ipcRenderer.invoke('zip:create:finalize', identifier, outputPath);
+}
diff --git a/src-electron/main-process/window-state-persist.js b/src-electron/window-state-persist.ts
similarity index 96%
rename from src-electron/main-process/window-state-persist.js
rename to src-electron/window-state-persist.ts
index ed9feadd0..9897cd7b8 100644
--- a/src-electron/main-process/window-state-persist.js
+++ b/src-electron/window-state-persist.ts
@@ -1,10 +1,10 @@
-import * as yaml from 'yaml';
-import * as path from 'path';
-import * as fs from 'fs-extra';
+import yaml from 'yaml';
+import path from 'path';
+import fs from 'fs-extra';
let resizeTimeout = undefined;
-export default class Persist {
+export class Persist {
static getSize(app, { defaultWidth, defaultHeight }) {
const configFilePath = path.join(app.getPath('appData'), 'r2modmanPlus-local', 'config', 'window-state.yml');
diff --git a/src/App.vue b/src/App.vue
index 473a2381e..1a53f7d6b 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -16,9 +16,8 @@ import LogOutput from './r2mm/data/LogOutput';
import LogOutputProvider from './providers/ror2/data/LogOutputProvider';
import ThunderstoreDownloaderProvider from './providers/ror2/downloading/ThunderstoreDownloaderProvider';
import BetterThunderstoreDownloader from './r2mm/downloading/BetterThunderstoreDownloader';
-import { ipcRenderer } from 'electron';
import PathResolver from './r2mm/manager/PathResolver';
-import path from 'path';
+import path from './providers/node/path/path';
import ThemeManager from './r2mm/manager/ThemeManager';
import 'bulma-switch/dist/css/bulma-switch.min.css';
import LoggerProvider, { LogSeverity } from './providers/ror2/logging/LoggerProvider';
@@ -30,7 +29,6 @@ import FileUtils from './utils/FileUtils';
import LinkProvider from './providers/components/LinkProvider';
import LinkImpl from './r2mm/component_override/LinkImpl';
import FsProvider from './providers/generic/file/FsProvider';
-import NodeFs from './providers/generic/file/NodeFs';
import { DataFolderProvider } from './providers/ror2/system/DataFolderProvider';
import { DataFolderProviderImpl } from './r2mm/system/DataFolderProviderImpl';
import InteractionProvider from './providers/ror2/system/InteractionProvider';
@@ -47,13 +45,21 @@ import GenericProfileInstaller from './r2mm/installing/profile_installers/Generi
import ErrorModal from './components/modals/ErrorModal.vue';
import { provideStoreImplementation } from './providers/generic/store/StoreProvider';
import baseStore from './store';
-import { getCurrentInstance, onMounted, ref, watchEffect } from 'vue';
+import { onMounted, ref, watchEffect } from 'vue';
import { useUtilityComposable } from './components/composables/UtilityComposable';
-import { Dark } from 'quasar';
-
-const store = baseStore();
+import { useQuasar } from 'quasar';
+import { NodeFsImplementation } from './providers/node/fs/NodeFsImplementation';
+import { useRouter } from 'vue-router';
+import { ProtocolProviderImplementation } from './providers/generic/protocol/ProtocolProviderImplementation';
+import { provideProtocolImplementation } from './providers/generic/protocol/ProtocolProvider';
+import contextMenu from './providers/node/context_menu/context_menu';
+
+const store = baseStore;
+const router = useRouter();
provideStoreImplementation(() => store);
+const quasar = useQuasar();
+
document.addEventListener('auxclick', e => {
const target = e.target! as any;
if (target.localName == 'a') {
@@ -70,7 +76,7 @@ const {
const visible = ref(false);
-FsProvider.provide(() => new NodeFs());
+FsProvider.provide(() => NodeFsImplementation);
ProfileProvider.provide(() => new ProfileImpl());
LogOutputProvider.provide(() => LogOutput.getSingleton());
@@ -88,11 +94,11 @@ DataFolderProvider.provide(() => new DataFolderProviderImpl());
PlatformInterceptorProvider.provide(() => new PlatformInterceptorImpl());
+provideProtocolImplementation(() => ProtocolProviderImplementation)
+
BindLoaderImpl.bind();
onMounted(async () => {
- // Load settings using the default game before the actual game is selected.
- const router = getCurrentInstance()!.proxy.$router;
const settings: ManagerSettings = await store.dispatch('resetActiveGame');
hookBackgroundUpdateThunderstoreModList(router);
@@ -102,7 +108,7 @@ onMounted(async () => {
InstallationRules.apply();
InstallationRules.validate();
- ipcRenderer.once('receive-appData-directory', async (_sender: any, appData: string) => {
+ window.app.getAppDataDirectory().then(async (appData: string) => {
PathResolver.APPDATA_DIR = path.join(appData, 'r2modmanPlus-local');
// Legacy path. Needed for migration.
PathResolver.CONFIG_DIR = path.join(PathResolver.APPDATA_DIR, "config");
@@ -123,21 +129,37 @@ onMounted(async () => {
await FileUtils.ensureDirectory(PathResolver.APPDATA_DIR);
await ThemeManager.apply();
- ipcRenderer.once('receive-is-portable', async (_sender: any, isPortable: boolean) => {
+
+ window.app.isApplicationPortable().then((isPortable: boolean) => {
ManagerInformation.IS_PORTABLE = isPortable;
LoggerProvider.instance.Log(LogSeverity.INFO, `Starting manager on version ${ManagerInformation.VERSION.toString()}`);
visible.value = true;
});
- ipcRenderer.send('get-is-portable');
});
- ipcRenderer.send('get-appData-directory');
store.commit('updateModLoaderPackageNames');
store.dispatch('tsMods/updateExclusions');
});
watchEffect(() => {
- document.documentElement.classList.toggle('html--dark', Dark.isActive);
+ document.documentElement.classList.toggle('html--dark', quasar.dark.isActive);
+});
+
+document.addEventListener('contextmenu', e => {
+ if (e.target) {
+ const target = e.target as HTMLElement;
+ switch (true) {
+ case target instanceof HTMLInputElement: {
+ contextMenu.showContextMenu({ readonly: false });
+ break;
+ }
+ case ['code', 'pre'].includes(target.tagName.toLowerCase()): {
+ contextMenu.showContextMenu({ readonly: true });
+ break;
+ }
+ default: { break; }
+ }
+ }
})
diff --git a/src/AppWrapper.vue b/src/AppWrapper.vue
index 3e909cfac..479eccf8a 100644
--- a/src/AppWrapper.vue
+++ b/src/AppWrapper.vue
@@ -1,9 +1,7 @@
-
+
+
+
diff --git a/src/components/navigation/NavigationMenu.vue b/src/components/navigation/NavigationMenu.vue
index efd1636fb..3afe0c50d 100644
--- a/src/components/navigation/NavigationMenu.vue
+++ b/src/components/navigation/NavigationMenu.vue
@@ -61,7 +61,7 @@
@@ -102,12 +101,12 @@
-
-
+
+
-
+
@@ -151,7 +150,7 @@
-
+
{{ game.displayName }}
@@ -185,13 +184,14 @@ import R2Error from '../model/errors/R2Error';
import { GameInstanceType, GameSelectionDisplayMode, Platform } from '../model/schema/ThunderstoreSchema';
import ProviderUtils from '../providers/generic/ProviderUtils';
import ModalCard from '../components/ModalCard.vue';
-import { computed, getCurrentInstance, onMounted, ref } from 'vue';
+import { computed, onMounted, reactive, ref } from 'vue';
import { getStore } from '../providers/generic/store/StoreProvider';
import { State } from '../store';
-import VueRouter from 'vue-router';
+import { useRouter } from 'vue-router';
+import ProtocolProvider from '../providers/generic/protocol/ProtocolProvider';
const store = getStore();
-let router!: VueRouter;
+const router = useRouter();
const runningMigration = ref(false);
const selectedGame = ref(null);
@@ -203,6 +203,7 @@ const settings = ref(undefined);
const isSettingDefaultPlatform = ref(false);
const viewMode = ref(GameSelectionViewMode.LIST);
const activeTab = ref(GameInstanceType.GAME);
+const gameImages = reactive({});
const filteredGameList = computed(() => {
const displayNameInAdditionalSearch = (game: Game, filterText: string): boolean => {
@@ -232,10 +233,18 @@ const gameList = computed(() => {
});
});
+function getImageHref(image: string) {
+ return ProtocolProvider.getPublicAssetUrl(image);
+}
+
function changeTab(tab: GameInstanceType) {
activeTab.value = tab;
}
+function markAsSelectedGame(game: Game) {
+ selectedGame.value = game;
+}
+
function selectGame(game: Game) {
selectedGame.value = game;
isSettingDefaultPlatform.value = false;
@@ -251,7 +260,7 @@ function selectGame(game: Game) {
});
showPlatformModal.value = true;
} else {
- selectedPlatform.value = game.storePlatformMetadata[0].storePlatform;
+ selectedPlatform.value = game.storePlatformMetadata[0]!.storePlatform;
showPlatformModal.value = false;
proceed();
}
@@ -263,7 +272,7 @@ function selectDefaultGame(game: Game) {
if (game.storePlatformMetadata.length > 1) {
showPlatformModal.value = true;
} else {
- selectedPlatform.value = game.storePlatformMetadata[0].storePlatform;
+ selectedPlatform.value = game.storePlatformMetadata[0]!.storePlatform;
showPlatformModal.value = false;
proceedDefault();
}
@@ -341,9 +350,15 @@ function isFavourited(game: Game) {
}
}
-onMounted(async () => {
- router = getCurrentInstance()!.proxy.$router;
+function isGameSelected(game: Game) {
+ return selectedGame.value !== null && selectedGame.value.internalFolderName === game.internalFolderName;
+}
+
+function isAnyGameSelected() {
+ return selectedGame.value !== null;
+}
+onMounted(async () => {
runningMigration.value = true;
await store.dispatch('checkMigrations');
runningMigration.value = false;
@@ -385,10 +400,6 @@ function toggleViewMode() {
}
}
-function getImage(image: string) {
- return require("../assets/images/game_selection/" + image);
-}
-
function capitalize(str: string) {
return str.slice(0, 1).toUpperCase() + str.slice(1);
}
diff --git a/src/pages/Help.vue b/src/pages/Help.vue
index 3cc0ca290..7b1881ad5 100644
--- a/src/pages/Help.vue
+++ b/src/pages/Help.vue
@@ -71,7 +71,7 @@
That's because you don't legally own the game. The manager only supports legal copies.
A text window appears and closes immediately.
- Try running "Reset {{$store.state.activeGame.displayName}} installation" on the Settings screen.
+ Try running "Reset {{store.state.activeGame.displayName}} installation" on the Settings screen.
If it persists, force exit Steam and start modded with Steam closed.
diff --git a/src/pages/LinuxNativeGameSetup.vue b/src/pages/LinuxNativeGameSetup.vue
index 322a1be77..bca435716 100644
--- a/src/pages/LinuxNativeGameSetup.vue
+++ b/src/pages/LinuxNativeGameSetup.vue
@@ -7,10 +7,10 @@
This needs to be done because of how the BepInEx injection works on Unix systems.
Please copy and paste the following to your {{ activeGame }} launch options:
-
{{ launchArgs }}
+
{{ launchArgs }}
-
Copy to clipboard
+
Copy to clipboard
Continue
@@ -21,37 +21,38 @@ import { Hero } from '../components/all';
import { computed, getCurrentInstance, onMounted, ref } from 'vue';
import { getStore } from '../providers/generic/store/StoreProvider';
import { State } from '../store';
-import VueRouter from 'vue-router';
+import VueRouter, {useRouter} from 'vue-router';
+import path from '../providers/node/path/path';
+import InteractionProviderImpl from "../r2mm/system/InteractionProviderImpl";
import {getWrapperLaunchArgs} from "../utils/LaunchUtils";
const store = getStore
();
-let router!: VueRouter;
-
-onMounted(() => {
- router = getCurrentInstance()!.proxy.$router;
-})
-
-const copyableArgs = ref();
-const copyAction = ref();
+let router = useRouter();
const launchArgs = ref("");
-getWrapperLaunchArgs().then(value => launchArgs.value = value);
+getWrapperLaunchArgs().then(value => {
+ console.log("Wrapper launch args", value)
+ launchArgs.value = value
+});
const activeGame = computed(() => store.state.activeGame.displayName);
const platformName = computed(() => process.platform === 'darwin' ? 'macOS' : process.platform);
function copy(){
let range = document.createRange();
- range.selectNode(copyableArgs.value as Node);
+ range.selectNode(document.getElementById('copyableArgs') as Node);
const selection = window.getSelection();
if(selection !== null) {
selection.removeAllRanges();
selection.addRange(range);
}
- document.execCommand("copy");
- (copyAction.value as Element).innerHTML = "Copied!";
+ InteractionProviderImpl.instance.copyToClipboard(launchArgs.value);
+ document.getElementById('copy-action')!.innerHTML = 'Copied!';
setTimeout(() => {
- (copyAction.value as Element).innerHTML = "Copy to clipboard";
+ const element = document.getElementById('copy-action');
+ if (element) {
+ element.innerHTML = 'Copy to clipboard';
+ }
}, 2000);
}
diff --git a/src/pages/Manager.vue b/src/pages/Manager.vue
index e5c05c266..1a312557c 100644
--- a/src/pages/Manager.vue
+++ b/src/pages/Manager.vue
@@ -139,7 +139,6 @@
diff --git a/src/pages/Splash.vue b/src/pages/Splash.vue
index 27633c5cb..c8ae261ec 100644
--- a/src/pages/Splash.vue
+++ b/src/pages/Splash.vue
@@ -118,31 +118,25 @@