Merge branch 'main' into sup39
This commit is contained in:
commit
964994eef9
14 changed files with 355 additions and 39 deletions
|
@ -297,9 +297,9 @@ module.exports = function (webpackEnv) {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
// fallback: {
|
fallback: {
|
||||||
// buffer: require.resolve("buffer/")
|
buffer: require.resolve("buffer/")
|
||||||
// },
|
},
|
||||||
// This allows you to set a fallback for where webpack should look for modules.
|
// This allows you to set a fallback for where webpack should look for modules.
|
||||||
// We placed these paths second because we want `node_modules` to "win"
|
// We placed these paths second because we want `node_modules` to "win"
|
||||||
// if there are any conflicts. This matches Node resolution mechanism.
|
// if there are any conflicts. This matches Node resolution mechanism.
|
||||||
|
@ -579,6 +579,11 @@ module.exports = function (webpackEnv) {
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
// Work around for Buffer is undefined:
|
||||||
|
// https://github.com/webpack/changelog-v5/issues/10
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
}),
|
||||||
// Generates an `index.html` file with the <script> injected.
|
// Generates an `index.html` file with the <script> injected.
|
||||||
new HtmlWebpackPlugin(
|
new HtmlWebpackPlugin(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
|
|
97
package-lock.json
generated
97
package-lock.json
generated
|
@ -1,13 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "botw-hundo-dupl",
|
"name": "botw-hundo-dupl",
|
||||||
"version": "2.1.3",
|
"version": "2.1.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "botw-hundo-dupl",
|
"name": "botw-hundo-dupl",
|
||||||
"version": "2.1.3",
|
"version": "2.1.5",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.16.0",
|
"@babel/core": "^7.16.0",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
||||||
|
@ -44,12 +43,14 @@
|
||||||
"jest-resolve": "^27.4.2",
|
"jest-resolve": "^27.4.2",
|
||||||
"jest-watch-typeahead": "^1.0.0",
|
"jest-watch-typeahead": "^1.0.0",
|
||||||
"mini-css-extract-plugin": "^2.4.5",
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
|
"pako": "^2.0.4",
|
||||||
"postcss": "^8.4.4",
|
"postcss": "^8.4.4",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
"postcss-loader": "^6.2.1",
|
"postcss-loader": "^6.2.1",
|
||||||
"postcss-normalize": "^10.0.1",
|
"postcss-normalize": "^10.0.1",
|
||||||
"postcss-preset-env": "^7.0.1",
|
"postcss-preset-env": "^7.0.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
|
"query-string": "^7.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-app-polyfill": "^3.0.0",
|
"react-app-polyfill": "^3.0.0",
|
||||||
"react-dev-utils": "^12.0.1",
|
"react-dev-utils": "^12.0.1",
|
||||||
|
@ -73,6 +74,7 @@
|
||||||
"yaml-loader": "^0.8.0"
|
"yaml-loader": "^0.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/pako": "^2.0.0",
|
||||||
"webpack-bundle-analyzer": "^4.5.0"
|
"webpack-bundle-analyzer": "^4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -3828,6 +3830,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
|
||||||
"integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ=="
|
"integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/pako": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
|
@ -7653,6 +7661,14 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filter-obj": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||||
|
@ -11963,6 +11979,11 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
|
||||||
|
},
|
||||||
"node_modules/param-case": {
|
"node_modules/param-case": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
||||||
|
@ -13456,6 +13477,23 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/query-string": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
|
||||||
|
"dependencies": {
|
||||||
|
"decode-uri-component": "^0.2.0",
|
||||||
|
"filter-obj": "^1.1.0",
|
||||||
|
"split-on-first": "^1.0.0",
|
||||||
|
"strict-uri-encode": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
@ -14581,6 +14619,14 @@
|
||||||
"wbuf": "^1.7.3"
|
"wbuf": "^1.7.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/split-on-first": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sprintf-js": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
@ -14623,6 +14669,14 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strict-uri-encode": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
@ -19049,6 +19103,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
|
||||||
"integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ=="
|
"integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ=="
|
||||||
},
|
},
|
||||||
|
"@types/pako": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/parse-json": {
|
"@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
|
@ -21851,6 +21911,11 @@
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"filter-obj": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ=="
|
||||||
|
},
|
||||||
"finalhandler": {
|
"finalhandler": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||||
|
@ -24930,6 +24995,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||||
},
|
},
|
||||||
|
"pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
|
||||||
|
},
|
||||||
"param-case": {
|
"param-case": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
||||||
|
@ -25848,6 +25918,17 @@
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"query-string": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
|
||||||
|
"requires": {
|
||||||
|
"decode-uri-component": "^0.2.0",
|
||||||
|
"filter-obj": "^1.1.0",
|
||||||
|
"split-on-first": "^1.0.0",
|
||||||
|
"strict-uri-encode": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"queue-microtask": {
|
"queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
@ -26680,6 +26761,11 @@
|
||||||
"wbuf": "^1.7.3"
|
"wbuf": "^1.7.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"split-on-first": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
|
||||||
|
},
|
||||||
"sprintf-js": {
|
"sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
@ -26715,6 +26801,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
||||||
},
|
},
|
||||||
|
"strict-uri-encode": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
|
||||||
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "botw-hundo-dupl",
|
"name": "botw-hundo-dupl",
|
||||||
"version": "2.1.3",
|
"version": "2.1.5",
|
||||||
"homepage": "https://ist.botw.sup39.dev/",
|
"homepage": "https://ist.botw.sup39.dev/",
|
||||||
"license": "MIT",
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.16.0",
|
"@babel/core": "^7.16.0",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
||||||
|
@ -39,12 +39,14 @@
|
||||||
"jest-resolve": "^27.4.2",
|
"jest-resolve": "^27.4.2",
|
||||||
"jest-watch-typeahead": "^1.0.0",
|
"jest-watch-typeahead": "^1.0.0",
|
||||||
"mini-css-extract-plugin": "^2.4.5",
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
|
"pako": "^2.0.4",
|
||||||
"postcss": "^8.4.4",
|
"postcss": "^8.4.4",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
"postcss-loader": "^6.2.1",
|
"postcss-loader": "^6.2.1",
|
||||||
"postcss-normalize": "^10.0.1",
|
"postcss-normalize": "^10.0.1",
|
||||||
"postcss-preset-env": "^7.0.1",
|
"postcss-preset-env": "^7.0.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
|
"query-string": "^7.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-app-polyfill": "^3.0.0",
|
"react-app-polyfill": "^3.0.0",
|
||||||
"react-dev-utils": "^12.0.1",
|
"react-dev-utils": "^12.0.1",
|
||||||
|
@ -152,6 +154,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/pako": "^2.0.0",
|
||||||
"webpack-bundle-analyzer": "^4.5.0"
|
"webpack-bundle-analyzer": "^4.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<meta property="og:url" content="https://ist.botw.sup39.dev/#/">
|
<meta property="og:url" content="https://ist.botw.sup39.dev/#/">
|
||||||
<meta property="og:description" content="for Breath of the Wild">
|
<meta property="og:description" content="for Breath of the Wild">
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<title>IST Sim</title>
|
<title>IST Simulator</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|
|
@ -176,6 +176,13 @@ button.MainButton:active {
|
||||||
background-color: #888888;
|
background-color: #888888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.MainButton:disabled{
|
||||||
|
color: #888888;
|
||||||
|
background-color: #333333;
|
||||||
|
border-color: #888888;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
.FullWidth {
|
.FullWidth {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +195,7 @@ div.OtherPage {
|
||||||
|
|
||||||
div.OtherPageContent{
|
div.OtherPageContent{
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MainInput {
|
.MainInput {
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import { PropsWithChildren } from "react";
|
import { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
multiLine?: boolean,
|
||||||
|
hasError?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
// an over-engineered loading screen
|
// an over-engineered loading screen
|
||||||
export const LoadingScreen: React.FC<PropsWithChildren> = ({children})=>{
|
export const LoadingScreen: React.FC<PropsWithChildren<Props>> = ({multiLine, hasError, children})=>{
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
|
@ -13,9 +18,9 @@ export const LoadingScreen: React.FC<PropsWithChildren> = ({children})=>{
|
||||||
backgroundColor: "#262626"
|
backgroundColor: "#262626"
|
||||||
}}>
|
}}>
|
||||||
<span style={{
|
<span style={{
|
||||||
color: "#00ffcc",
|
color: hasError? "#ee7777":"#00ffcc",
|
||||||
|
|
||||||
lineHeight: "100vh",
|
lineHeight: multiLine?"default":"100vh",
|
||||||
height: "100vh",
|
height: "100vh",
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ItemStack, ItemType, createMaterialStack, createEquipmentStack } from "
|
||||||
import { Slots } from "./Slots";
|
import { Slots } from "./Slots";
|
||||||
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItem, createMaterialMockItem, equalsExceptEquip } from "./SlotsTestHelpers";
|
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItem, createMaterialMockItem, equalsExceptEquip } from "./SlotsTestHelpers";
|
||||||
|
|
||||||
describe("Slots.add", ()=>{
|
describe("core/Slots.add", ()=>{
|
||||||
describe("sorted", ()=>{
|
describe("sorted", ()=>{
|
||||||
describe("reloading = true", ()=>{
|
describe("reloading = true", ()=>{
|
||||||
it("should add new stack when empty", ()=>{
|
it("should add new stack when empty", ()=>{
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { createEquipmentStack, createMaterialStack, ItemStack, ItemType } from "
|
||||||
import { Slots } from "./Slots";
|
import { Slots } from "./Slots";
|
||||||
import { createEquipmentMockItem, createMaterialMockItem } from "./SlotsTestHelpers";
|
import { createEquipmentMockItem, createMaterialMockItem } from "./SlotsTestHelpers";
|
||||||
|
|
||||||
describe("Slots.remove", ()=>{
|
describe("core/Slots.remove", ()=>{
|
||||||
it("Does nothing if item doesn't exist", ()=>{
|
it("Does nothing if item doesn't exist", ()=>{
|
||||||
const mockItem1 = createMaterialMockItem("MaterialA");
|
const mockItem1 = createMaterialMockItem("MaterialA");
|
||||||
const stackToRemove = createMaterialStack(mockItem1, 1);
|
const stackToRemove = createMaterialStack(mockItem1, 1);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { createEquipmentStack, createMaterialStack, ItemStack, ItemType } from "
|
||||||
import { Slots } from "./Slots";
|
import { Slots } from "./Slots";
|
||||||
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItemStackable, createMaterialMockItem } from "./SlotsTestHelpers";
|
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItemStackable, createMaterialMockItem } from "./SlotsTestHelpers";
|
||||||
|
|
||||||
describe.only("Slots.updateLife", ()=>{
|
describe.only("core/Slots.updateLife", ()=>{
|
||||||
it("should update life", ()=>{
|
it("should update life", ()=>{
|
||||||
const mockItem1 = createMaterialMockItem("MaterialA");
|
const mockItem1 = createMaterialMockItem("MaterialA");
|
||||||
const slot = createMaterialStack(mockItem1, 1);
|
const slot = createMaterialStack(mockItem1, 1);
|
||||||
|
|
33
src/data/serialize.test.ts
Normal file
33
src/data/serialize.test.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { compressString, decompressString } from "./serialize";
|
||||||
|
|
||||||
|
const runCompressDecompressTest = (input: string) => {
|
||||||
|
const compressed = compressString(input);
|
||||||
|
expect(compressed).not.toEqual(input);
|
||||||
|
expect(decompressString(compressed)).toEqual(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe.only("data/serialize.compress", ()=>{
|
||||||
|
it("Should compress and decompress empty string", ()=>{
|
||||||
|
runCompressDecompressTest("");
|
||||||
|
});
|
||||||
|
it("Should compress and decompress one character", ()=>{
|
||||||
|
runCompressDecompressTest("a");
|
||||||
|
});
|
||||||
|
it("Should compress and decompress single command", ()=>{
|
||||||
|
const input = "Break 5 Slots";
|
||||||
|
runCompressDecompressTest(input);
|
||||||
|
});
|
||||||
|
it("Should compress and decompress large command", ()=>{
|
||||||
|
const input = "Initialize 1 Tree Branch[equip] 1 Hammer 1 Travel Bow[Equip] 3 NormalArrow[Equip] 1 potlid 1 potlid[equip] 1 Fairy 1 SpeedFood 3 EnduraFood 1 Slate 9 SpiritOrb 1 Glider";
|
||||||
|
runCompressDecompressTest(input);
|
||||||
|
});
|
||||||
|
it("Should compress and decompress multiple commands", ()=>{
|
||||||
|
const inputArray = [
|
||||||
|
"Break 5 Slots",
|
||||||
|
"Save",
|
||||||
|
"Eat 3 EnduraFood",
|
||||||
|
"Eat SpeedFood"
|
||||||
|
];
|
||||||
|
runCompressDecompressTest(inputArray.join("\n"));
|
||||||
|
});
|
||||||
|
});
|
40
src/data/serialize.ts
Normal file
40
src/data/serialize.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { gzip, ungzip } from "pako";
|
||||||
|
|
||||||
|
const ZLIB_OPTIONS = {
|
||||||
|
level: 9
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type SerializedCommands = { r: string } | { c: string }; // r for raw and c for compressed
|
||||||
|
|
||||||
|
export const serialize = (commandsString: string): SerializedCommands => {
|
||||||
|
const compressed = compressString(commandsString);
|
||||||
|
if (commandsString.length < compressed.length){
|
||||||
|
return { r: commandsString };
|
||||||
|
}
|
||||||
|
return { c: compressed };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deserialize = (serializedCommands: Partial<SerializedCommands>): string | null => {
|
||||||
|
if ( "r" in serializedCommands && serializedCommands.r){
|
||||||
|
return serializedCommands.r;
|
||||||
|
}
|
||||||
|
if ( "c" in serializedCommands && serializedCommands.c){
|
||||||
|
return decompressString(serializedCommands.c);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const compressString = (uncompressedString: string): string => {
|
||||||
|
const uncompressedBytes = Buffer.from(uncompressedString, "utf8");
|
||||||
|
const compressedBytes = gzip(uncompressedBytes, ZLIB_OPTIONS);
|
||||||
|
return Buffer.from(compressedBytes).toString("base64");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decompressString = (decompressedString: string): string => {
|
||||||
|
const compressedBytes = Buffer.from(decompressedString, "base64");
|
||||||
|
const uncompressedBytes = ungzip(compressedBytes, {
|
||||||
|
to: "string",
|
||||||
|
...ZLIB_OPTIONS
|
||||||
|
});
|
||||||
|
return Buffer.from(uncompressedBytes).toString("utf8");
|
||||||
|
};
|
|
@ -5,6 +5,7 @@ import {App} from "./App";
|
||||||
import reportWebVitals from "./reportWebVitals";
|
import reportWebVitals from "./reportWebVitals";
|
||||||
import { LanguageProvider } from "data/i18n";
|
import { LanguageProvider } from "data/i18n";
|
||||||
import { ItemProvider } from "data/item";
|
import { ItemProvider } from "data/item";
|
||||||
|
import { DirectLoadPage } from "surfaces/DirectLoadPage";
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById("root") as HTMLElement
|
document.getElementById("root") as HTMLElement
|
||||||
|
@ -12,12 +13,12 @@ const root = ReactDOM.createRoot(
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<LanguageProvider>
|
<LanguageProvider>
|
||||||
<ItemProvider>
|
<DirectLoadPage>
|
||||||
<App />
|
<ItemProvider>
|
||||||
</ItemProvider>
|
<App />
|
||||||
|
</ItemProvider>
|
||||||
|
</DirectLoadPage>
|
||||||
</LanguageProvider>
|
</LanguageProvider>
|
||||||
|
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
72
src/surfaces/DirectLoadPage.tsx
Normal file
72
src/surfaces/DirectLoadPage.tsx
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { PropsWithChildren, useMemo } from "react";
|
||||||
|
import { parse } from "query-string";
|
||||||
|
import { deserialize } from "data/serialize";
|
||||||
|
import { LoadingScreen } from "components/LoadingScreen";
|
||||||
|
import { BodyText, Header, SubHeader } from "components/Text";
|
||||||
|
|
||||||
|
const redirectToMainApp = ()=>{
|
||||||
|
window.location.href = window.location.origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DirectLoadPage: React.FC<PropsWithChildren> = ({children}) => {
|
||||||
|
const query = parse(window.location.search);
|
||||||
|
const [commandTextToLoad, errorText] = useMemo(()=>{
|
||||||
|
try {
|
||||||
|
return [deserialize(query), false];
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return [null, "Fail to deserialize. The URL may be corrupted."];
|
||||||
|
}
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
|
if(errorText){
|
||||||
|
return (
|
||||||
|
<LoadingScreen hasError multiLine>
|
||||||
|
<Header>Error loading direct URL</Header>
|
||||||
|
<SubHeader>{errorText}</SubHeader>
|
||||||
|
<BodyText>The browser console may have useful information for debugging</BodyText>
|
||||||
|
<BodyText emphasized>Press Continue to load existing data in the simulator instead</BodyText>
|
||||||
|
<button className="MainButton" onClick={()=>{
|
||||||
|
redirectToMainApp();
|
||||||
|
}}>Continue</button>
|
||||||
|
</LoadingScreen>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commandTextToLoad){
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!localStorage.getItem("HDS.CurrentCommandsText")){
|
||||||
|
// If no data is in simulator (i.e. first time use), load data without warning
|
||||||
|
localStorage.setItem("HDS.CurrentCommandsText", commandTextToLoad);
|
||||||
|
redirectToMainApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <LoadingScreen multiLine>
|
||||||
|
<div className="OtherPageContent">
|
||||||
|
<Header>Open Direct URL?</Header>
|
||||||
|
<SubHeader>You are trying to open a direct URL. This will automatically load data into the simulator.</SubHeader>
|
||||||
|
<BodyText emphasized>This will override existing data and cannot be reversed</BodyText>
|
||||||
|
<button className="MainButton" onClick={()=>{
|
||||||
|
localStorage.setItem("HDS.CurrentCommandsText", commandTextToLoad);
|
||||||
|
redirectToMainApp();
|
||||||
|
}}>Yes</button>
|
||||||
|
<button className="MainButton" onClick={()=>{
|
||||||
|
|
||||||
|
redirectToMainApp();
|
||||||
|
}}>No</button>
|
||||||
|
|
||||||
|
<div style={{marginTop: "50px", marginLeft: "10%", marginRight: "10%"}}>
|
||||||
|
<BodyText>(Below is what the incoming data looks like)</BodyText>
|
||||||
|
<textarea
|
||||||
|
className="MainInput"
|
||||||
|
spellCheck={false}
|
||||||
|
value={commandTextToLoad}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</LoadingScreen>;
|
||||||
|
};
|
|
@ -1,8 +1,12 @@
|
||||||
|
import { BodyText, SubHeader, SubTitle } from "components/Text";
|
||||||
import { TitledList } from "components/TitledList";
|
import { TitledList } from "components/TitledList";
|
||||||
import { saveAs } from "data/FileSaver";
|
import { saveAs } from "data/FileSaver";
|
||||||
import { useRef, useState } from "react";
|
import { serialize } from "data/serialize";
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import license from "./License";
|
import license from "./License";
|
||||||
|
|
||||||
|
const URL_MAX = 2048;
|
||||||
|
|
||||||
type OptionPageProps = {
|
type OptionPageProps = {
|
||||||
interlaceInventory: boolean,
|
interlaceInventory: boolean,
|
||||||
setInterlaceInventory: (value: boolean)=>void,
|
setInterlaceInventory: (value: boolean)=>void,
|
||||||
|
@ -22,8 +26,23 @@ export const OptionPage: React.FC<OptionPageProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [currentText, setCurrentText] = useState<string>(commandText);
|
const [currentText, setCurrentText] = useState<string>(commandText);
|
||||||
const [fileName, setFileName] = useState<string>("");
|
const [fileName, setFileName] = useState<string>("");
|
||||||
|
const [showDirectUrl, setShowDirectUrl] = useState<boolean>(false);
|
||||||
|
const [showCopiedMessage, setShowCopiedMessage] = useState<boolean>(false);
|
||||||
|
|
||||||
const uploadRef = useRef<HTMLInputElement>(null);
|
const uploadRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const directUrl = useMemo(()=>{
|
||||||
|
const serializedCommands = serialize(commandText);
|
||||||
|
const query = new URLSearchParams(serializedCommands).toString();
|
||||||
|
return `${window.location.origin}/?${query}`;
|
||||||
|
}, [commandText]);
|
||||||
|
|
||||||
|
const directUrlLength = directUrl.length;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setShowCopiedMessage(false);
|
||||||
|
}, [currentText]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="OtherPage">
|
<div className="OtherPage">
|
||||||
|
|
||||||
|
@ -42,36 +61,29 @@ export const OptionPage: React.FC<OptionPageProps> = ({
|
||||||
|
|
||||||
<TitledList title="Options">
|
<TitledList title="Options">
|
||||||
<div className="OtherPageContent">
|
<div className="OtherPageContent">
|
||||||
|
<SubHeader>
|
||||||
<h3 className="Reference">
|
|
||||||
Interlace Inventory with GameData
|
Interlace Inventory with GameData
|
||||||
<button className="MainButton" onClick={()=>{
|
<button className="MainButton" onClick={()=>{
|
||||||
setInterlaceInventory(!interlaceInventory);
|
setInterlaceInventory(!interlaceInventory);
|
||||||
}}>
|
}}>
|
||||||
{interlaceInventory ? "ON" : "OFF"}
|
{interlaceInventory ? "ON" : "OFF"}
|
||||||
</button>
|
</button>
|
||||||
</h3>
|
</SubHeader>
|
||||||
<h4 className="Reference">
|
<SubTitle>Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced.</SubTitle>
|
||||||
Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced.
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<h3 className="Reference">
|
<SubHeader>
|
||||||
Enable Animated Item Icons
|
Enable Animated Item Icons
|
||||||
<button className="MainButton" onClick={()=>{
|
<button className="MainButton" onClick={()=>{
|
||||||
setIsIconAnimated(!isIconAnimated);
|
setIsIconAnimated(!isIconAnimated);
|
||||||
}}>
|
}}>
|
||||||
{isIconAnimated ? "ON" : "OFF"}
|
{isIconAnimated ? "ON" : "OFF"}
|
||||||
</button>
|
</button>
|
||||||
</h3>
|
</SubHeader>
|
||||||
<h4 className="Reference">
|
<SubTitle>Toggle whether items such as the champion abilities or Travel Medallion use animated or still icons.</SubTitle>
|
||||||
Toggle whether items such as the champion abilities or Travel Medallion use animated or still icons.
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<h3 className="Reference">Import / Export</h3>
|
<SubHeader>Text Import / Export</SubHeader>
|
||||||
<h4 className="Reference">
|
<SubTitle>You can also directly copy, paste, or edit the commands here</SubTitle>
|
||||||
You can also directly copy, paste, or edit the commands here
|
<BodyText>
|
||||||
</h4>
|
|
||||||
<p className="Reference">
|
|
||||||
<button className="MainButton" onClick={()=>{
|
<button className="MainButton" onClick={()=>{
|
||||||
if(uploadRef.current){
|
if(uploadRef.current){
|
||||||
uploadRef.current.click();
|
uploadRef.current.click();
|
||||||
|
@ -113,8 +125,54 @@ export const OptionPage: React.FC<OptionPageProps> = ({
|
||||||
<span className="Example">Don't forget to save changes</span>
|
<span className="Example">Don't forget to save changes</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
</BodyText>
|
||||||
</p>
|
|
||||||
|
<SubHeader>Direct URL</SubHeader>
|
||||||
|
<SubTitle>Use this to open the simulator with the steps automatically loaded.</SubTitle>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
currentText !== commandText ?
|
||||||
|
<BodyText emphasized>
|
||||||
|
You must save the changes above to access the updated URL
|
||||||
|
</BodyText>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
directUrlLength > URL_MAX && <BodyText emphasized>
|
||||||
|
Warning: The URL is too long ({directUrlLength} characters) and may not work in certain browsers. Export as file instead if you encounter any problems.
|
||||||
|
</BodyText>
|
||||||
|
}
|
||||||
|
<p className="Reference" style={{
|
||||||
|
fontSize: "10pt",
|
||||||
|
color: "#aaaaaa",
|
||||||
|
|
||||||
|
...!showDirectUrl && {
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
overflowX: "hidden",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{directUrl}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<BodyText>
|
||||||
|
<button className="MainButton" onClick={()=>{
|
||||||
|
setShowDirectUrl(!showDirectUrl);
|
||||||
|
}}>{showDirectUrl ? "Hide" : "Expand"}</button>
|
||||||
|
<button className="MainButton" disabled={currentText !== commandText} onClick={()=>{
|
||||||
|
window.navigator.clipboard.writeText(directUrl);
|
||||||
|
setShowCopiedMessage(true);
|
||||||
|
}}>
|
||||||
|
Copy
|
||||||
|
</button>
|
||||||
|
{
|
||||||
|
showCopiedMessage && <span className="Example">Link copied!</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
</BodyText>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 className="Reference">Credits</h3>
|
<h3 className="Reference">Credits</h3>
|
||||||
<p className="Reference">
|
<p className="Reference">
|
||||||
|
|
Reference in a new issue