1
0
Fork 0

Merge branch 'sup39' into deploy

This commit is contained in:
sup39 2022-10-21 13:50:44 +09:00
commit 528539b4be
24 changed files with 378 additions and 53 deletions

View file

@ -297,9 +297,9 @@ module.exports = function (webpackEnv) {
],
},
resolve: {
// fallback: {
// buffer: require.resolve("buffer/")
// },
fallback: {
buffer: require.resolve("buffer/")
},
// 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"
// if there are any conflicts. This matches Node resolution mechanism.
@ -579,6 +579,11 @@ module.exports = function (webpackEnv) {
].filter(Boolean),
},
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.
new HtmlWebpackPlugin(
Object.assign(

View file

@ -1,7 +1,7 @@
{
"files": {
"main.css": "/static/css/main.5f4aee86.css",
"main.js": "/static/js/main.d3d96545.js",
"main.css": "/static/css/main.227156c4.css",
"main.js": "/static/js/main.3703e36b.js",
"static/js/984.b2865733.chunk.js": "/static/js/984.b2865733.chunk.js",
"static/js/941.0c0a870a.chunk.js": "/static/js/941.0c0a870a.chunk.js",
"static/js/911.e40081a5.chunk.js": "/static/js/911.e40081a5.chunk.js",
@ -10,15 +10,15 @@
"static/media/Background.png": "/static/media/Background.0e120fe5fc51d2dee803.png",
"static/media/Calamity-Regular.otf": "/static/media/Calamity-Regular.cbeefc650e6ac39335b6.otf",
"index.html": "/index.html",
"main.5f4aee86.css.map": "/static/css/main.5f4aee86.css.map",
"main.d3d96545.js.map": "/static/js/main.d3d96545.js.map",
"main.227156c4.css.map": "/static/css/main.227156c4.css.map",
"main.3703e36b.js.map": "/static/js/main.3703e36b.js.map",
"984.b2865733.chunk.js.map": "/static/js/984.b2865733.chunk.js.map",
"941.0c0a870a.chunk.js.map": "/static/js/941.0c0a870a.chunk.js.map",
"911.e40081a5.chunk.js.map": "/static/js/911.e40081a5.chunk.js.map",
"787.ada1a5f8.chunk.js.map": "/static/js/787.ada1a5f8.chunk.js.map"
},
"entrypoints": [
"static/css/main.5f4aee86.css",
"static/js/main.d3d96545.js"
"static/css/main.227156c4.css",
"static/js/main.3703e36b.js"
]
}

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="for Breath of the Wild"/><meta property="og:site_name" content="itntpiston.app"/><meta property="og:title" content="Inventory Slot Transfer Simulator"><meta property="og:type" content="website"><meta property="og:url" content="https://ist.botw.sup39.dev/#/"><meta property="og:description" content="for Breath of the Wild"><link rel="manifest" href="/manifest.json"/><title>IST Sim</title><script defer="defer" src="/static/js/main.d3d96545.js"></script><link href="/static/css/main.5f4aee86.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="for Breath of the Wild"/><meta property="og:site_name" content="itntpiston.app"/><meta property="og:title" content="Inventory Slot Transfer Simulator"><meta property="og:type" content="website"><meta property="og:url" content="https://ist.botw.sup39.dev/#/"><meta property="og:description" content="for Breath of the Wild"><link rel="manifest" href="/manifest.json"/><title>IST Simulator</title><script defer="defer" src="/static/js/main.3703e36b.js"></script><link href="/static/css/main.227156c4.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View file

@ -1,2 +1,2 @@
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0;overflow:hidden}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}a{color:#b7f1ff}a:visited{color:#b7afff}h1{margin:0}@font-face{font-family:CalamitySans;src:url(/static/media/Calamity-Regular.cbeefc650e6ac39335b6.otf) format("opentype")}.Calamity{font-family:CalamitySans}.CommandItemSelected{background-color:#eee}.CommandItemContextSelected{background-color:#eaa}.CommandItemComment{color:green;font-size:10pt}.CommandItemInvalid{color:red}.CommandItem{cursor:pointer;padding:2px 2px 2px 10px}.CommandItem:hover{border:1px solid #000}.CommandInput{border:none;border-bottom:2px solid #0074d9;color:#b7f1ff;text-shadow:0 0 5px #3aa0ff,0 0 5px #3aa0ff,0 0 5px #3aa0ff}.CommandInput:focus-visible{border-color:#b7f1ff}.InputError{border-bottom:2px solid #d00;color:#f33;text-shadow:0 0 5px #e77,0 0 5px #e77,0 0 5px #e77}.InputError:focus-visible{border-bottom:2px solid #f33}.ItemSlot{background-color:#333333bb;box-sizing:content-box;display:inline-block;height:64px;margin:4px;position:relative;width:64px}.ItemSlotBroken{background-color:#600}.GameDataBackground{background-color:#030}.ItemSlotEquipped{background-color:#08f}.ItemImage{border:1px solid #999;box-sizing:border-box;display:inline-block;height:62px;margin:1px;padding:1px;width:62px}.ItemLayer{height:72px;left:-4px;position:absolute;top:-4px;width:72px}.ItemCount{left:10px;top:48px}.ItemCount,.ItemDurability{color:#eee;font-size:10pt;position:absolute}.ItemDurability{background-color:#333333bb;border:1px solid #999;bottom:2px;box-sizing:border-box;display:inline-block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;left:2px;padding:0 1px}h3.ListHeader{margin:0;padding:10px}h4.Reference{color:#ccc;margin:0}p.Reference{padding-left:20px}.Example{color:#ee0}h3.Reference{margin-bottom:0;margin-top:30px}h3.Reference2{margin-bottom:0;margin-top:0}button.MainButton{background-color:#00000099;border:2px solid #888;border-radius:0;color:#fff;display:inline-block;font-family:CalamitySans;font-weight:700;margin:5px;padding:5px;width:100px}button.MainButton:hover{border-color:#eee;box-shadow:0 0 5px #eee}button.MainButton:active{background-color:#888}.FullWidth{width:100%!important}div.OtherPage{color:#fff;height:100%;width:100%}div.OtherPageContent{padding:10px}.MainInput{background-color:#00000099;border:2px solid #888;border-radius:0;color:#fff;display:block;margin-bottom:5px;width:100%}input.MainInput{font-family:CalamitySans;font-size:14pt}textarea{height:300px;resize:none}.MainInput:focus-visible{border-color:#eee;box-shadow:0 0 5px #eee;outline:none}.SpecialScreen{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}p.License{font-size:.75em;padding-left:3em}p.License code{white-space:pre}
/*# sourceMappingURL=main.5f4aee86.css.map*/
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0;overflow:hidden}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}a{color:#b7f1ff}a:visited{color:#b7afff}h1{margin:0}@font-face{font-family:CalamitySans;src:url(/static/media/Calamity-Regular.cbeefc650e6ac39335b6.otf) format("opentype")}.Calamity{font-family:CalamitySans}.CommandItemSelected{background-color:#eee}.CommandItemContextSelected{background-color:#eaa}.CommandItemComment{color:green;font-size:10pt}.CommandItemInvalid{color:red}.CommandItem{cursor:pointer;padding:2px 2px 2px 10px}.CommandItem:hover{border:1px solid #000}.CommandInput{border:none;border-bottom:2px solid #0074d9;color:#b7f1ff;text-shadow:0 0 5px #3aa0ff,0 0 5px #3aa0ff,0 0 5px #3aa0ff}.CommandInput:focus-visible{border-color:#b7f1ff}.InputError{border-bottom:2px solid #d00;color:#f33;text-shadow:0 0 5px #e77,0 0 5px #e77,0 0 5px #e77}.InputError:focus-visible{border-bottom:2px solid #f33}.ItemSlot{background-color:#333333bb;box-sizing:content-box;display:inline-block;height:64px;margin:4px;position:relative;width:64px}.ItemSlotBroken{background-color:#600}.GameDataBackground{background-color:#030}.ItemSlotEquipped{background-color:#08f}.ItemImage{border:1px solid #999;box-sizing:border-box;display:inline-block;height:62px;margin:1px;padding:1px;width:62px}.ItemLayer{height:72px;left:-4px;position:absolute;top:-4px;width:72px}.ItemCount{left:10px;top:48px}.ItemCount,.ItemDurability{color:#eee;font-size:10pt;position:absolute}.ItemDurability{background-color:#333333bb;border:1px solid #999;bottom:2px;box-sizing:border-box;display:inline-block;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;left:2px;padding:0 1px}h3.ListHeader{margin:0;padding:10px}h4.Reference{color:#ccc;margin:0}p.Reference{padding-left:20px}.Example{color:#ee0}h3.Reference{margin-bottom:0;margin-top:30px}h3.Reference2{margin-bottom:0;margin-top:0}button.MainButton{background-color:#00000099;border:2px solid #888;border-radius:0;color:#fff;display:inline-block;font-family:CalamitySans;font-weight:700;margin:5px;padding:5px;width:100px}button.MainButton:hover{border-color:#eee;box-shadow:0 0 5px #eee}button.MainButton:active{background-color:#888}button.MainButton:disabled{background-color:#333;border-color:#888;box-shadow:none;color:#888}.FullWidth{width:100%!important}div.OtherPage{color:#fff;height:100%;width:100%}div.OtherPageContent{overflow-wrap:break-word;padding:10px}.MainInput{background-color:#00000099;border:2px solid #888;border-radius:0;color:#fff;display:block;margin-bottom:5px;width:100%}input.MainInput{font-family:CalamitySans;font-size:14pt}textarea{height:300px;resize:none}.MainInput:focus-visible{border-color:#eee;box-shadow:0 0 5px #eee;outline:none}.SpecialScreen{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}p.License{font-size:.75em;padding-left:3em}p.License code{white-space:pre}
/*# sourceMappingURL=main.227156c4.css.map*/

1
docs/static/css/main.227156c4.css.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3
docs/static/js/main.3703e36b.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,12 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**

1
docs/static/js/main.3703e36b.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

97
package-lock.json generated
View file

@ -1,13 +1,12 @@
{
"name": "botw-hundo-dupl",
"version": "2.1.3",
"version": "2.1.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "botw-hundo-dupl",
"version": "2.1.3",
"license": "MIT",
"version": "2.1.5",
"dependencies": {
"@babel/core": "^7.16.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
@ -44,12 +43,14 @@
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"mini-css-extract-plugin": "^2.4.5",
"pako": "^2.0.4",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.0.1",
"prompts": "^2.4.2",
"query-string": "^7.1.1",
"react": "^18.2.0",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.1",
@ -73,6 +74,7 @@
"yaml-loader": "^0.8.0"
},
"devDependencies": {
"@types/pako": "^2.0.0",
"webpack-bundle-analyzer": "^4.5.0"
}
},
@ -3828,6 +3830,12 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz",
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -7653,6 +7661,14 @@
"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": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@ -11963,6 +11979,11 @@
"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": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@ -13456,6 +13477,23 @@
"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": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -14581,6 +14619,14 @@
"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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -14623,6 +14669,14 @@
"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": {
"version": "1.3.0",
"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",
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -21851,6 +21911,11 @@
"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": {
"version": "1.2.0",
"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",
"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": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@ -25848,6 +25918,17 @@
"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": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -26680,6 +26761,11 @@
"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": {
"version": "1.0.3",
"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",
"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": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",

View file

@ -1,8 +1,8 @@
{
"name": "botw-hundo-dupl",
"version": "2.1.3",
"version": "2.1.5",
"homepage": "https://ist.botw.sup39.dev/",
"license": "MIT",
"private": true,
"dependencies": {
"@babel/core": "^7.16.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
@ -39,12 +39,14 @@
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"mini-css-extract-plugin": "^2.4.5",
"pako": "^2.0.4",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.0.1",
"prompts": "^2.4.2",
"query-string": "^7.1.1",
"react": "^18.2.0",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.1",
@ -152,6 +154,7 @@
]
},
"devDependencies": {
"@types/pako": "^2.0.0",
"webpack-bundle-analyzer": "^4.5.0"
}
}

View file

@ -14,7 +14,7 @@
<meta property="og:url" content="https://ist.botw.sup39.dev/#/">
<meta property="og:description" content="for Breath of the Wild">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>IST Sim</title>
<title>IST Simulator</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View file

@ -176,6 +176,13 @@ button.MainButton:active {
background-color: #888888;
}
button.MainButton:disabled{
color: #888888;
background-color: #333333;
border-color: #888888;
box-shadow: none;
}
.FullWidth {
width: 100% !important;
}
@ -188,6 +195,7 @@ div.OtherPage {
div.OtherPageContent{
padding: 10px;
overflow-wrap: break-word;
}
.MainInput {

View file

@ -1,7 +1,12 @@
import { PropsWithChildren } from "react";
type Props = {
multiLine?: boolean,
hasError?: boolean,
}
// an over-engineered loading screen
export const LoadingScreen: React.FC<PropsWithChildren> = ({children})=>{
export const LoadingScreen: React.FC<PropsWithChildren<Props>> = ({multiLine, hasError, children})=>{
return (
<div style={{
textAlign: "center",
@ -13,9 +18,9 @@ export const LoadingScreen: React.FC<PropsWithChildren> = ({children})=>{
backgroundColor: "#262626"
}}>
<span style={{
color: "#00ffcc",
color: hasError? "#ee7777":"#00ffcc",
lineHeight: "100vh",
lineHeight: multiLine?"default":"100vh",
height: "100vh",
}}>
{children}

View file

@ -2,7 +2,7 @@ import { ItemStack, ItemType, createMaterialStack, createEquipmentStack } from "
import { Slots } from "./Slots";
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItem, createMaterialMockItem, equalsExceptEquip } from "./SlotsTestHelpers";
describe("Slots.add", ()=>{
describe("core/Slots.add", ()=>{
describe("sorted", ()=>{
describe("reloading = true", ()=>{
it("should add new stack when empty", ()=>{

View file

@ -2,7 +2,7 @@ import { createEquipmentStack, createMaterialStack, ItemStack, ItemType } from "
import { Slots } from "./Slots";
import { createEquipmentMockItem, createMaterialMockItem } from "./SlotsTestHelpers";
describe("Slots.remove", ()=>{
describe("core/Slots.remove", ()=>{
it("Does nothing if item doesn't exist", ()=>{
const mockItem1 = createMaterialMockItem("MaterialA");
const stackToRemove = createMaterialStack(mockItem1, 1);

View file

@ -2,7 +2,7 @@ import { createEquipmentStack, createMaterialStack, ItemStack, ItemType } from "
import { Slots } from "./Slots";
import { createArrowMockItem, createEquipmentMockItem, createFoodMockItem, createKeyMockItemStackable, createMaterialMockItem } from "./SlotsTestHelpers";
describe.only("Slots.updateLife", ()=>{
describe.only("core/Slots.updateLife", ()=>{
it("should update life", ()=>{
const mockItem1 = createMaterialMockItem("MaterialA");
const slot = createMaterialStack(mockItem1, 1);

View 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
View 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");
};

View file

@ -5,6 +5,7 @@ import {App} from "./App";
import reportWebVitals from "./reportWebVitals";
import { LanguageProvider } from "data/i18n";
import { ItemProvider } from "data/item";
import { DirectLoadPage } from "surfaces/DirectLoadPage";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
@ -12,12 +13,12 @@ const root = ReactDOM.createRoot(
root.render(
<React.StrictMode>
<LanguageProvider>
<ItemProvider>
<App />
</ItemProvider>
<DirectLoadPage>
<ItemProvider>
<App />
</ItemProvider>
</DirectLoadPage>
</LanguageProvider>
</React.StrictMode>
);

View 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>;
};

View file

@ -1,8 +1,12 @@
import { BodyText, SubHeader, SubTitle } from "components/Text";
import { TitledList } from "components/TitledList";
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";
const URL_MAX = 2048;
type OptionPageProps = {
interlaceInventory: boolean,
setInterlaceInventory: (value: boolean)=>void,
@ -22,8 +26,23 @@ export const OptionPage: React.FC<OptionPageProps> = ({
}) => {
const [currentText, setCurrentText] = useState<string>(commandText);
const [fileName, setFileName] = useState<string>("");
const [showDirectUrl, setShowDirectUrl] = useState<boolean>(false);
const [showCopiedMessage, setShowCopiedMessage] = useState<boolean>(false);
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 (
<div className="OtherPage">
@ -42,36 +61,29 @@ export const OptionPage: React.FC<OptionPageProps> = ({
<TitledList title="Options">
<div className="OtherPageContent">
<h3 className="Reference">
<SubHeader>
Interlace Inventory with GameData
<button className="MainButton" onClick={()=>{
setInterlaceInventory(!interlaceInventory);
}}>
{interlaceInventory ? "ON" : "OFF"}
</button>
</h3>
<h4 className="Reference">
Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced.
</h4>
</SubHeader>
<SubTitle>Toggle whether Visible Inventory should be displayed separetely from Game Data or interlaced.</SubTitle>
<h3 className="Reference">
<SubHeader>
Enable Animated Item Icons
<button className="MainButton" onClick={()=>{
setIsIconAnimated(!isIconAnimated);
}}>
{isIconAnimated ? "ON" : "OFF"}
</button>
</h3>
<h4 className="Reference">
Toggle whether items such as the champion abilities or Travel Medallion use animated or still icons.
</h4>
</SubHeader>
<SubTitle>Toggle whether items such as the champion abilities or Travel Medallion use animated or still icons.</SubTitle>
<h3 className="Reference">Import / Export</h3>
<h4 className="Reference">
You can also directly copy, paste, or edit the commands here
</h4>
<p className="Reference">
<SubHeader>Text Import / Export</SubHeader>
<SubTitle>You can also directly copy, paste, or edit the commands here</SubTitle>
<BodyText>
<button className="MainButton" onClick={()=>{
if(uploadRef.current){
uploadRef.current.click();
@ -113,8 +125,54 @@ export const OptionPage: React.FC<OptionPageProps> = ({
<span className="Example">Don't forget to save changes</span>
</>
}
</p>
</BodyText>
<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>
<p className="Reference">