Compare commits

..

No commits in common. "topwar" and "master" have entirely different histories.

34 changed files with 470 additions and 1002 deletions

294
package-lock.json generated
View File

@ -5,7 +5,6 @@
"requires": true,
"packages": {
"": {
"name": "playable-preview",
"version": "0.1.0",
"dependencies": {
"@emotion/react": "^11.10.4",
@ -16,21 +15,15 @@
"@testing-library/user-event": "^13.5.0",
"ali-oss": "^6.17.1",
"axios": "^0.24.0",
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"localstorage-slim": "^2.2.0",
"qrcode": "^1.5.0",
"query-string": "^7.1.1",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.4",
"react-dom": "^17.0.2",
"react-i18next": "^14.1.2",
"react-modal-login": "^2.0.7",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.2"
},
"devDependencies": {
"http-proxy-middleware": "^3.0.0"
}
},
"node_modules/@apideck/better-ajv-errors": {
@ -1538,11 +1531,11 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
@ -1560,11 +1553,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/runtime/node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/@babel/template": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz",
@ -3356,9 +3344,9 @@
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
},
"node_modules/@types/http-proxy": {
"version": "1.17.14",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
"integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
"dependencies": {
"@types/node": "*"
}
@ -4708,11 +4696,11 @@
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dependencies": {
"fill-range": "^7.1.1"
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
@ -5618,19 +5606,14 @@
}
},
"node_modules/debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/decamelize": {
@ -7223,9 +7206,9 @@
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -7969,14 +7952,6 @@
"node": ">= 12"
}
},
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/html-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
@ -8080,20 +8055,18 @@
}
},
"node_modules/http-proxy-middleware": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz",
"integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==",
"dev": true,
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz",
"integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==",
"dependencies": {
"@types/http-proxy": "^1.17.10",
"debug": "^4.3.4",
"@types/http-proxy": "^1.17.5",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
"micromatch": "^4.0.5"
"micromatch": "^4.0.2"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
"node": ">=12.0.0"
}
},
"node_modules/https-proxy-agent": {
@ -8124,36 +8097,6 @@
"ms": "^2.0.0"
}
},
"node_modules/i18next": {
"version": "23.11.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz",
"integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
"node_modules/i18next-browser-languagedetector": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -10725,12 +10668,12 @@
}
},
"node_modules/micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
"braces": "^3.0.1",
"picomatch": "^2.2.3"
},
"engines": {
"node": ">=8.6"
@ -11467,14 +11410,11 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pirates": {
@ -13118,27 +13058,6 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
},
"node_modules/react-i18next": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz",
"integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
"i18next": ">= 23.2.3",
"react": ">= 16.8.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -15218,14 +15137,6 @@
"node": ">=0.4.0"
}
},
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@ -15446,29 +15357,6 @@
"node": ">=12"
}
},
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
"integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
"dependencies": {
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
"micromatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"@types/express": "^4.17.13"
},
"peerDependenciesMeta": {
"@types/express": {
"optional": true
}
}
},
"node_modules/webpack-dev-server/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
@ -17297,18 +17185,11 @@
}
},
"@babel/runtime": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"requires": {
"regenerator-runtime": "^0.14.0"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
}
"regenerator-runtime": "^0.13.4"
}
},
"@babel/runtime-corejs3": {
@ -18689,9 +18570,9 @@
"integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
},
"@types/http-proxy": {
"version": "1.17.14",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
"integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
"requires": {
"@types/node": "*"
}
@ -19866,11 +19747,11 @@
}
},
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"requires": {
"fill-range": "^7.1.1"
"fill-range": "^7.0.1"
}
},
"browser-process-hrtime": {
@ -20615,9 +20496,9 @@
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
},
"debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"requires": {
"ms": "2.1.2"
}
@ -21913,9 +21794,9 @@
"integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg=="
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"requires": {
"to-regex-range": "^5.0.1"
}
@ -22514,14 +22395,6 @@
}
}
},
"html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"requires": {
"void-elements": "3.1.0"
}
},
"html-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
@ -22615,17 +22488,15 @@
}
},
"http-proxy-middleware": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz",
"integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==",
"dev": true,
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz",
"integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==",
"requires": {
"@types/http-proxy": "^1.17.10",
"debug": "^4.3.4",
"@types/http-proxy": "^1.17.5",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
"micromatch": "^4.0.5"
"micromatch": "^4.0.2"
}
},
"https-proxy-agent": {
@ -22650,22 +22521,6 @@
"ms": "^2.0.0"
}
},
"i18next": {
"version": "23.11.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz",
"integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==",
"requires": {
"@babel/runtime": "^7.23.2"
}
},
"i18next-browser-languagedetector": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
"requires": {
"@babel/runtime": "^7.23.2"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -24692,12 +24547,12 @@
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
"requires": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
"braces": "^3.0.1",
"picomatch": "^2.2.3"
}
},
"mime": {
@ -25279,9 +25134,9 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
},
"pirates": {
"version": "4.0.4",
@ -26532,15 +26387,6 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
},
"react-i18next": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz",
"integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==",
"requires": {
"@babel/runtime": "^7.23.9",
"html-parse-stringify": "^3.0.1"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -26585,7 +26431,6 @@
"postcss-preset-env": "^7.0.1",
"prompts": "^2.4.2",
"prop-types": "^15.8.0",
"react": "^17.0.2",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.0",
"react-dom": "^17.0.2",
@ -28258,11 +28103,6 @@
}
}
},
"void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
},
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@ -28471,18 +28311,6 @@
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
},
"http-proxy-middleware": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
"integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
"requires": {
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
"micromatch": "^4.0.2"
}
},
"json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",

View File

@ -12,15 +12,12 @@
"@testing-library/user-event": "^13.5.0",
"ali-oss": "^6.17.1",
"axios": "^0.24.0",
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"localstorage-slim": "^2.2.0",
"qrcode": "^1.5.0",
"query-string": "^7.1.1",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.4",
"react-dom": "^17.0.2",
"react-i18next": "^14.1.2",
"react-modal-login": "^2.0.7",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.2"
@ -48,8 +45,5 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"http-proxy-middleware": "^3.0.0"
}
}

View File

@ -46,76 +46,3 @@
.MuiDialog-root {
background-color: white;
}
.pane-btn {
border-radius: 8px;
border: 3px solid #494949;
display: inline-block;
height: 62px;
width: 62px;
cursor: pointer;
outline: none;
font-weight: bold;
background: #494949;
color: #eee;
box-sizing: border-box;
}
.pane-btn.checked {
border: 3px solid #00DE7A;
}
.pane-btn + .pane-btn {
margin-left: 14px;
}
.generate-btn {
border-radius: 4px;
display: inline-block;
height: 40px;
width: 150px;
cursor: pointer;
outline: none;
font-weight: bold;
font-size: 22px;
background-color: rgb(82, 146, 242);
border: 1px #367fed solid;
}
.language-select-container {
display: flex;
align-items: center;
position: fixed;
right: 24px;
top: 24px;
z-index: 1000;
}
.language-select-container .language-select {
width: 156px;
height: 42px;
background-color: #36383A;
color: #EEEEEE;
font-size: 14px;
display: flex;
align-items: center;
}
.language-select-warpper {
position: relative;
border-radius: 5px;
background: #36383A;
border: 1px solid #5B5B5B;
box-shadow: 0px 3px 0px 0px rgba(0, 0, 0, 0.3);
}
.language-select-warpper .language-icon {
position: absolute;
left: 14px;
top: 11px;
z-index: 2000;
}
.language-select-container .language-select fieldset {
display: none;
}

View File

@ -14,8 +14,6 @@ import {
setLoginInfo,
setProjectSetting,
} from "./storage";
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Dialog from "@mui/material/Dialog";
@ -25,23 +23,9 @@ import DialogTitle from "@mui/material/DialogTitle";
import Checkbox from "@mui/material/Checkbox";
import FormControlLabel from "@mui/material/FormControlLabel";
import queryString from "query-string";
import { withTranslation } from "react-i18next";
import i18n from "i18next";
import languageImg from "./images/language.png";
import Arrow from './images/arrow.svg'
import SvgIcon from '@mui/material/SvgIcon';
function CustomIcon(props) {
return (
<SvgIcon viewBox="0 0 24 24" {...props}>
<path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" fill="white" />
</SvgIcon>
);
}
class App extends React.Component {
constructor(props) {
constructor() {
super();
this.state = {
mode: "normal",
@ -60,9 +44,7 @@ class App extends React.Component {
password: "",
keepLogin: false,
},
language: localStorage.getItem("lang") ?? "zh",
};
this.t = props.t;
}
componentDidMount() {
const loginInfo = getLoginInfo();
@ -75,7 +57,8 @@ class App extends React.Component {
this.refreshQrCode();
} else {
this.setState({ loginOpen: true });
loginInfo && this.setState({ loginErrorMessage: "noAuth" });
loginInfo &&
this.setState({ loginErrorMessage: "无权限访问,请切换账号" });
}
}
@ -95,7 +78,9 @@ class App extends React.Component {
this.refreshQrCode();
} else {
this.setState({
loginErrorMessage: user ? "noAuth" : "loginError",
loginErrorMessage: user
? `无权限访问${tenant},请切换账号`
: "账号或密码错误",
});
}
};
@ -120,7 +105,6 @@ class App extends React.Component {
var rawUrl = selectedProject?.HtmlUrl
? encodeURI(selectedProject?.HtmlUrl)
: "";
rawUrl = rawUrl.replace("http:", () => "https:");
if (rawUrl) {
rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`;
}
@ -138,18 +122,6 @@ class App extends React.Component {
async updateSelectedProject(projectName) {
var projectSetting = await ProjectApi.getProjectSetting(projectName);
if (projectSetting.TextObjStr) {
const none = `${this.t("none")}|${this.t("none")}|${this.t("none")}`;
if (projectSetting.TextObjStr.CentText === "无|无|无") {
projectSetting.TextObjStr.CentText = none;
}
if (projectSetting.TextObjStr.MiddText === "无|无|无") {
projectSetting.TextObjStr.MiddText = none;
}
if (projectSetting.TextObjStr.TopText === "无|无|无") {
projectSetting.TextObjStr.TopText = none;
}
}
this.setState({
selectedProject: projectSetting,
});
@ -218,20 +190,18 @@ class App extends React.Component {
loginOpen,
loginForm,
hideLogo,
language,
} = this.state;
const { t } = this.props;
return (
<div className="App">
<Dialog open={loginOpen}>
<DialogTitle>{t("login")}</DialogTitle>
<DialogTitle>登录</DialogTitle>
<DialogContent>
<TextField
autoFocus
margin="dense"
id="name"
label={t("account")}
label="账号"
fullWidth
value={loginForm.account}
variant="standard"
@ -242,7 +212,7 @@ class App extends React.Component {
autoFocus
margin="dense"
id="name"
label={t("password")}
label="密码"
type={"password"}
fullWidth
value={loginForm.password}
@ -260,7 +230,7 @@ class App extends React.Component {
margin: "0 auto 0 10px",
}}
>
{t(this.state.loginErrorMessage)}
{this.state.loginErrorMessage}
</span>
)}
<FormControlLabel
@ -272,9 +242,9 @@ class App extends React.Component {
}
/>
}
label={t("keepLoginStatus")}
label="保持登录状态7天"
/>
<Button onClick={() => this.login()}>{t("submit")}</Button>
<Button onClick={() => this.login()}>提交</Button>
</DialogActions>
</Dialog>
<Pane
@ -289,32 +259,6 @@ class App extends React.Component {
}}
onDeviceChange={(_device) => this.setDevice(_device)}
/>
<div className="language-select-container">
<div className="language-select-warpper">
<img className="language-icon" src={languageImg} style={{ width: "18px" }} alt="" />
<Select
className="language-select"
value={language}
label={t("language")}
IconComponent={CustomIcon}
onChange={(e) => {
let lang = e.target.value;
this.setState({
language: lang,
});
i18n.changeLanguage(lang);
localStorage.setItem("lang", lang);
}}
>
<MenuItem style={{ fontSize: "14px" }} value="en">
English
</MenuItem>
<MenuItem style={{ fontSize: "14px" }} value="zh">
简体中文
</MenuItem>
</Select>
</div>
</div>
<div
style={{
display: "flex",
@ -346,4 +290,4 @@ class App extends React.Component {
}
}
export default withTranslation()(App);
export default App;

View File

@ -1,45 +1,23 @@
.deviceFrameContainer {
width: 100%;
height: 100vh;
flex: 1 1 0%;
align-items: center;
position: relative;
display: flex;
justify-content: center;
overflow: hidden;
background: #36383A;
width: 100%;
flex: 1 1 0%;
align-items: center;
position: relative;
display: flex;
height: 100vh;
justify-content: center;
overflow: hidden;
}
.refreshButton {
position: absolute;
right: 24px;
bottom: 24px;
cursor: pointer;
position: absolute;
left: 30px;
bottom: 30px;
cursor: pointer;
}
.qrCode {
position: absolute;
right: 24px;
top: 82px;
background: #DBDBDB;
width: 156px;
text-align: center;
border-radius: 5px;
padding-top: 14px;
padding-bottom: 11px;
}
.qrCode p {
display: flex;
justify-content: center;
align-items: center;
color: #666666;
font-size: 14px;
}
.qrCode img {
}
#deviceFrame {
border-radius: 10px;
position: absolute;
right: 30px;
top: 30px;
}

View File

@ -1,180 +1,117 @@
import "./index.css";
import androidHPng from "../../images/android-h.png";
import androidVPng from "../../images/android-v.png";
import iphoneHPng from "../../images/iphone-h.png";
import iphoneVPng from "../../images/iphone-v.png";
import ipadHPng from "../../images/ipad-horizontal.png";
import ipadVPng from "../../images/iPad-v.png";
import copyPng from "../../images/copy.png";
import refreshButtonPng from "../../images/refresh-button.png";
import { CopyToClipboard } from "react-copy-to-clipboard";
import React, { useEffect, useState } from "react";
import { BaseUrl } from "../../constants";
import { Alert, Snackbar } from "@mui/material";
import { useTranslation } from "react-i18next";
import zIndex from "@mui/material/styles/zIndex";
import './index.css'
import androidHPng from '../../images/android-h.png'
import androidVPng from '../../images/android-v.png'
import iphoneHPng from '../../images/iphone-h.png'
import iphoneVPng from '../../images/iphone-v.png'
import ipadHPng from '../../images/iPad-h.png'
import ipadVPng from '../../images/iPad-v.png'
import copyPng from '../../images/copy.png'
import refreshButtonPng from '../../images/refresh-button.png'
import {CopyToClipboard} from 'react-copy-to-clipboard';
import React, { useEffect, useState } from 'react'
import { BaseUrl } from '../../constants'
import { Alert, Snackbar } from '@mui/material'
var configMap = {
"android-h": {
bkg: androidVPng,
rotate: true,
width: "666px",
height: "321px",
offsetv: "4px",
},
"android-v": {
bkg: androidVPng,
width: "321px",
height: "666px",
offsetv: "5px",
},
"iphone-h": {
bkg: iphoneVPng,
rotate: true,
width: "690px",
height: "325px",
styles: {
borderRadius: '13px'
}
},
"iphone-v": {
bkg: iphoneVPng,
width: "322px",
height: "693px",
styles: {
borderRadius: '13px'
}
},
"ipad-h": {
bkg: ipadHPng,
rotate: true,
width: "646px",
height: "478px",
offsetv: "5px",
imgStyle: {
transform: 'rotate(-90deg) translate(0, -3px)',
},
styles: {
transform: "translate(-50%, -50%)",
}
},
"ipad-v": {
bkg: ipadHPng,
width: "478px",
height: "646px",
offsetv: "5px",
imgStyle: {
transform: 'translate(0, -2px)',
},
styles: {
transform: "translate(-50%, -50%)",
}
},
};
"android-h": {
bkg: androidHPng,
width: '512px',
height: '286px',
offsetv: '5px',
},
"android-v": {
bkg: androidVPng,
width: '286px',
height: '512px',
offsetv: '5px',
},
"iphone-h": {
bkg: iphoneHPng,
width: '628px',
height: '322px'
},
"iphone-v": {
bkg: iphoneVPng,
width: '322px',
height: '628px'
},
"ipad-h": {
bkg: ipadHPng,
width: '433px',
height: '326px',
offsetv: '5px',
},
"ipad-v": {
bkg: ipadVPng,
width: '324px',
height: '433px',
offsetv: '5px',
},
}
function DeviceFrame(props) {
var [config, setConfig] = useState({});
var [cacheKey, setCacheKey] = useState(new Date().getTime());
var [openPopup, setOpenPopup] = useState(false);
var [absoluteUrl, setAbsoluteUrl] = useState("");
const { t } = useTranslation();
var [config, setConfig] = useState({})
var [cacheKey, setCacheKey] = useState(new Date().getTime());
var [openPopup, setOpenPopup] = useState(false);
var [absoluteUrl, setAbsoluteUrl] = useState('');
useEffect(() => {
// 将宽度和高度的值转换为数字并增加10%
const current = JSON.parse(JSON.stringify(configMap[props.device]))
const w = parseFloat(current.width)
const h = parseFloat(current.height)
current.width = (w * 1.1) + 'px';
current.height = (h * 1.1) + 'px';
let bgW = (w * 1.1) + 32;
let bgH = (h * 1.1) + 32;
// 竖屏
if (props.device === 'android-v') {
bgW -= 12;
} else if (props.device === 'android-h') {
// 横屏
bgH -= 12;
}
useEffect(() => {
setConfig(configMap[props.device])
}, [props.device, config])
// 平板
if (props.device === 'ipad-v') {
bgW += 28;
bgH += 28;
} else if (props.device === 'ipad-h') {
// 横屏
bgW += 28;
bgH += 28;
}
var refresh = () => setCacheKey(new Date().getTime());
if (current.rotate) {
current.imgStyle = Object.assign({ height: bgW, width: bgH }, current.imgStyle || {})
} else {
current.imgStyle = Object.assign({ width: bgW, height: bgH }, current.imgStyle || {})
}
setConfig(current);
// setConfig(configMap[props.device]);
}, [props.device]);
useEffect(() => {
console.log('触发更新', props.htmlUrl);
props.htmlUrl && setAbsoluteUrl(!props.htmlUrl.startsWith("http") ? BaseUrl + props.htmlUrl : props.htmlUrl);
refresh()
props.refreshQrCode()
}, [props.htmlUrl])
var refresh = () => setCacheKey(new Date().getTime());
useEffect(() => {
console.log("触发更新", props.htmlUrl);
props.htmlUrl && setAbsoluteUrl(!props.htmlUrl.startsWith("http") ? BaseUrl + props.htmlUrl : props.htmlUrl);
refresh();
props.refreshQrCode();
}, [props.htmlUrl]);
return (
<div className="deviceFrameContainer">
<img src={refreshButtonPng} alt="refresh" onClick={() => refresh()} className="refreshButton" />
{props.qrDataUrl && (
<div className="qrCode">
<img src={props.qrDataUrl} alt="qr code" />
<p style={{ margin: "0", }}>
{t("scan")}
<CopyToClipboard text={absoluteUrl} onCopy={() => setOpenPopup(true)}>
<img style={{ cursor: "pointer", width: "20px", height: "20px", marginLeft: '4px' }} src={copyPng} alt="复制链接" />
</CopyToClipboard>
</p>
</div>
)}
<Snackbar
open={openPopup}
onClose={() => setOpenPopup(false)}
autoHideDuration={500}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}>
<Alert severity="success" sx={{ width: "100%" }}>
{t("copySuccess")}
</Alert>
</Snackbar>
<div>
<img src={config.bkg} alt="background" style={{ position: "relative", zIndex: 100, transform: config.rotate ? "rotate(-90deg)" : "", pointerEvents: 'none', ...config.imgStyle }} />
{props.htmlUrl && (
<iframe
id="deviceFrame"
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%) scale(1.007)",
paddingBottom: config.offsetv,
...config.styles
}}
allow="clipboard-read; clipboard-write *"
title="preview"
src={absoluteUrl + "&cacheKey=" + cacheKey}
width={config.width}
height={config.height}
frameBorder={"0"}
/>
)}
</div>
</div>
);
return (
<div className='deviceFrameContainer'>
<img src={refreshButtonPng} alt='refresh' onClick={() => refresh()} className='refreshButton'/>
{ props.qrDataUrl &&
<div className='qrCode'>
<p style={{ margin: '0' }}>扫一扫,手机预览
<CopyToClipboard text={absoluteUrl} onCopy={() => setOpenPopup(true)}>
<img style={{ cursor: 'pointer', width: '20px', height: '20px' }} src={copyPng} alt='复制链接'/>
</CopyToClipboard>
</p>
<img src={props.qrDataUrl} alt='qr code'/>
</div>
}
<Snackbar open={openPopup} onClose={() => setOpenPopup(false)} autoHideDuration={500} anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}>
<Alert severity="success" sx={{ width: '100%' }}>
链接复制成功
</Alert>
</Snackbar>
<div>
<img src={config.bkg} alt='background'/>
{
props.htmlUrl
&& <iframe
id='deviceFrame'
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
paddingBottom: config.offsetv
}}
allow="clipboard-read; clipboard-write *"
title='preview'
src={absoluteUrl + '&cacheKey=' + cacheKey}
width={config.width}
height={config.height}
frameBorder={'0'}/>
}
</div>
</div>
)
}
export default DeviceFrame;

View File

@ -1,58 +1,43 @@
.Pane {
width: 370px;
background-color: #535353;
min-height: 100vh;
padding: 24px;
box-sizing: border-box;
display: flex;
flex-direction: column;
position: relative;
width: 350px;
background-color: rgb(52, 90, 176);
min-height: 100vh;
display: flex;
flex-direction: column;
}
.modeSelect {
width: 100%;
border: none;
width: 100%;
border: none;
}
.deviceIcon {
width: auto;
height: 76px;
margin-bottom: 10px;
margin-top: 7px;
}
.deviceText {
width: auto;
height: 80px;
margin-right: 10px;
margin-bottom: -24px;
}
.deviceContent {
height: 100%;
color: #eeeeee;
text-align: left;
color: white;
}
.deviceButtons {
height: 100%;
display: flex;
justify-content: space-between;
width: 160px;
display: flex;
justify-content: space-between;
}
.deviceButtons img {
cursor: pointer;
cursor: pointer;
}
.selectPager {
left: 25px !important;
width: 319px !important;
left: 0 !important;
width: 350px;
}
.bottomLogo {
position: absolute;
width: 322px;
bottom: 24px;
text-align: center;
img {
width: 280px;
}
}
.Mui-focused .MuiOutlinedInput-notchedOutline {
border: none;
margin-top: auto;
}

View File

@ -4,170 +4,169 @@ import MenuItem from "@mui/material/MenuItem";
import { useEffect, useState } from "react";
import { CircularProgress, List, ListItem } from "@mui/material";
import ipadPng from "../../images/ipad.png";
import ipadTextPng from "../../images/ipad-text.png";
import iphonePng from "../../images/iphone.png";
import iphoneTextPng from '../../images/iphone-text.png'
import androidPng from "../../images/android.png";
import androidTextPng from '../../images/android-text.png'
import logoPanePng from "../../images/logo-pane.png";
import horizentalChecked from "../../images/horizental-button-checked.png";
import horizentalButton from "../../images/horizental-button.png";
import verticalChecked from "../../images/vertical-button-checked.png";
import verticalButton from "../../images/vertical-button.png";
import modeSelectPng from "../../images/mode-select.png";
import { useTranslation } from "react-i18next";
import SvgIcon from '@mui/material/SvgIcon';
function CustomIcon(props) {
return (
<SvgIcon viewBox="0 0 24 24" {...props}>
<path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" fill="white" />
</SvgIcon>
);
}
var deviceConfigs = [
{
name: "iPhone",
icon: iphonePng,
text: iphoneTextPng,
vertical: "iphone-v",
horizental: "iphone-h",
},
{
name: "Android Phone",
icon: androidPng,
text: androidTextPng,
vertical: "android-v",
horizental: "android-h",
},
{
name: "iPad",
icon: ipadPng,
text: ipadTextPng,
vertical: "ipad-v",
horizental: "ipad-h",
},
{
name: "iPhone",
icon: iphonePng,
vertical: "iphone-v",
horizental: "iphone-h",
},
{
name: "Android Phone",
icon: androidPng,
vertical: "android-v",
horizental: "android-h",
},
{
name: "iPad",
icon: ipadPng,
vertical: "ipad-v",
horizental: "ipad-h",
},
];
function Pane(props) {
var [mode, setMode] = useState(props.mode);
var [device, setDevice] = useState(props.device);
var [project, setProject] = useState(props.project);
const { t } = useTranslation();
var [mode, setMode] = useState(props.mode);
var [device, setDevice] = useState(props.device);
var [project, setProject] = useState(props.project);
var modeChange = (e) => {
var _mode = e.target.value;
setMode(_mode);
props.onModeChange(e.target.value);
};
var modeChange = (e) => {
var _mode = e.target.value;
setMode(_mode);
props.onModeChange(e.target.value);
};
var deviceChange = (_device) => {
setDevice(_device);
props.onDeviceChange(_device);
};
var deviceChange = (_device) => {
setDevice(_device);
props.onDeviceChange(_device);
};
var projectSelect = (e) => {
var projectName = e.target.value;
setProject(projectName);
props.onProjectSelect(projectName);
};
var projectSelect = (e) => {
var projectName = e.target.value;
setProject(projectName);
props.onProjectSelect(projectName);
};
useEffect(() => {
props.projects.length && !project && setProject(props.projects[0]);
}, [props.projects]);
useEffect(() => {
props.projects.length && !project && setProject(props.projects[0]);
}, [props.projects]);
return (
<div className="Pane">
<div>
{props.loading ? (
<CircularProgress color="inherit" />
) : (
project && (
<Select
id="project-select"
value={project}
onChange={(e) => projectSelect(e)}
IconComponent={CustomIcon}
placeholder="选择项目"
sx={{
width: "100%",
height: '42px',
border: "1px solid #757575",
background: "#535353",
borderRadius: '5px',
color: "white",
boxShadow: '0px 3px 0px 0px rgba(0, 0, 0, 0.3)',
// '&.MuiOutlinedInput-notchedOutline': {
// borderColor: '#757575', // 设置焦点时的边框颜色为红色
// },
'&.Mui-focused': {
borderColor: '#757575',
'&.MuiOutlinedInput-notchedOutline': {
borderColor: '#757575 !important',
},
},
}}
MenuProps={{
classes: {
paper: "selectPager",
},
}}
>
{props.projects.map((pName, i) => (
<MenuItem key={i} value={pName}>
{pName}
</MenuItem>
))}
</Select>
)
)}
</div>
<List
sx={{
paddingTop: '20px'
}}
>
{deviceConfigs.map((_device) => (
<ListItem
key={_device.name}
sx={{
display: "flex",
textAlign: "center",
justifyContent: "space-between",
borderRadius: '5px',
background: '#535353',
border: '1px solid #757575',
boxShadow: '0px 3px 0px 0px rgba(0, 0, 0, 0.3)',
paddingLeft: '23px',
paddingRight: '20px',
marginBottom: '14px'
}}>
<div style={{ display: "flex", flexDirection: 'column', justifyContent: 'center', alignItems: "center", width: '98px' }}>
<img className="deviceIcon" style={{ height: _device.name === 'iPad' ? '54px' : '76px' }} src={_device.icon} alt={_device.name} />
<img className="deviceText" src={_device.text} alt={_device.name} />
</div>
<div className="deviceContent">
<div className="deviceButtons">
<button className={`pane-btn ${device === _device.horizental ? "checked" : ""}`} onClick={() => deviceChange(_device.horizental)}>
{t("horizontal")}
</button>
<button className={`pane-btn ${device === _device.vertical ? "checked" : ""}`} onClick={() => deviceChange(_device.vertical)}>
{t("vertical")}
</button>
{/* <img src={device === _device.horizental ? horizentalChecked : horizentalButton} alt="horizental" onClick={() => deviceChange(_device.horizental)} />
<img src={device === _device.vertical ? verticalChecked : verticalButton} alt="vertical" onClick={() => deviceChange(_device.vertical)} /> */}
</div>
</div>
</ListItem>
))}
</List>
{!props.hideLogo && <div className="bottomLogo"><img src={logoPanePng} alt="logo" width={"100%"} /></div>}
</div>
);
return (
<div className="Pane">
<Select
id="mode-select"
value={mode}
onChange={(e) => modeChange(e)}
startAdornment={
<img src={modeSelectPng} height={"30px"} alt="selected" />
}
sx={{
width: "100%",
border: "none",
background: "rgb(69, 115, 191)",
color: "white",
fontWeight: "bold",
}}
MenuProps={{
classes: {
paper: "selectPager",
},
}}
>
<MenuItem value={"normal"}>Normal Preview</MenuItem>
<MenuItem value={"dynamic"}>Dynamic Preview</MenuItem>
</Select>
<List>
{deviceConfigs.map((_device) => (
<ListItem
key={_device.name}
sx={{
display: "flex",
textAlign: "center",
}}
>
<div style={{ width: "120px", alignItems: "center" }}>
<img
className="deviceIcon"
src={_device.icon}
alt={_device.name}
/>
</div>
<div className="deviceContent">
<p style={{ margin: "14px 0" }}>{_device.name}</p>
<div className="deviceButtons">
<img
src={
device === _device.horizental
? horizentalChecked
: horizentalButton
}
alt="horizental"
onClick={() => deviceChange(_device.horizental)}
/>
<img
src={
device === _device.vertical
? verticalChecked
: verticalButton
}
alt="vertical"
onClick={() => deviceChange(_device.vertical)}
/>
</div>
</div>
</ListItem>
))}
</List>
<div
style={{
marginTop: "50px",
color: "white",
}}
>
{props.loading ? (
<CircularProgress color="inherit" />
) : (
project && (
<Select
id="project-select"
value={project}
onChange={(e) => projectSelect(e)}
placeholder="选择项目"
sx={{
background: "rgb(115, 158, 211)",
width: "80%",
color: "white",
}}
>
{props.projects.map((pName, i) => (
<MenuItem key={i} value={pName}>
{pName}
</MenuItem>
))}
</Select>
)
)}
</div>
{!props.hideLogo && (
<img
src={logoPanePng}
alt="logo"
width={"100%"}
className="bottomLogo"
/>
)}
</div>
);
}
export default Pane;

View File

@ -1,118 +1,96 @@
import { Alert, Grid, List, ListItem, Snackbar } from "@mui/material";
import { useEffect, useState } from "react";
import "./index.css";
import checkPng from "../../images/check.png";
import { useTranslation } from "react-i18next";
import { Alert, Grid, List, ListItem, Snackbar } from '@mui/material';
import { useEffect, useState } from 'react'
import './index.css'
import checkPng from '../../images/check.png';
import generateButtonPng from '../../images/generate-button.png';
var rows = ["TopText", "CentText", "MiddText"];
var rowTitles = ["start", "middle", "end"];
var rows = ['TopText', 'CentText', 'MiddText']
var rowTitles = ['开头', '中间', '结尾']
function SettingFrame(props) {
var [settingArr, setSettingArr] = useState([1, 2, 3]);
var [openPopup, setOpenPopup] = useState(false);
const { t } = useTranslation();
var [settingArr, setSettingArr] = useState([1, 2, 3])
var [openPopup, setOpenPopup] = useState(false);
console.log(props.settingValue)
useEffect(() => {
setSettingArr(props.settingValue)
}, [props.settingValue])
useEffect(() => {
setSettingArr(props.settingValue);
}, [props.settingValue]);
return (
<div style={{
flex: 1
}}>
<Snackbar open={openPopup} onClose={() => setOpenPopup(false)} autoHideDuration={3000} anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}>
<Alert severity="success" sx={{ width: '100%' }}>
保存成功
</Alert>
</Snackbar>
<List>
{
rows.map((rowKey, rowIndex) => (
<ListItem key={rowIndex}>
<span>{rowTitles[rowIndex]}</span>
<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
{(props.setting && props.setting[rowKey]
? Array.from(props.setting[rowKey].split('|'))
: ['无', '无', '无'])
.map((text, index) => (
<Grid item xs={2} sm={4} md={4} key={index}>
<div className='setting-card' style={{
position: 'relative',
height: '120px',
textAlign: 'center',
justifyContent: 'center',
display: 'flex',
alignItems: 'center',
cursor: 'pointer'
}}
onClick={() => {
var newSetting = settingArr.slice()
newSetting[rowIndex] = index + 1;
setSettingArr(newSetting);
}}>
{text}
<img src={checkPng} alt='check' style={{
position: 'absolute',
right: '10px',
top: '10px',
display: (index + 1) === settingArr[rowIndex] ? 'block' : 'none'
}}/>
</div>
</Grid>
))}
</Grid>
</ListItem>
))
}
</List>
<div style={{
alignItems: 'center',
cursor: 'pointer',
marginTop: '30px'
}}>
{
props.setting && <img
src={generateButtonPng}
alt='generate'
style={{
cursor: 'pointer'
}}
onClick={async () => {
await props.generate({
topType: settingArr[0]+'',
centreType: settingArr[1]+'',
middleType: settingArr[2]+''
})
return (
<div
style={{
flex: 1,
}}
>
<Snackbar
open={openPopup}
onClose={() => setOpenPopup(false)}
autoHideDuration={3000}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
>
<Alert severity="success" sx={{ width: "100%" }}>
{t("saveSuccess")}
</Alert>
</Snackbar>
<List style={{ width: "80%", margin: "auto", minWidth: "500px" }}>
{rows.map((rowKey, rowIndex) => (
<ListItem key={rowIndex}>
<span style={{ display: "inline-block", width: "40px" }}>
{t(rowTitles[rowIndex])}
</span>
<Grid
container
spacing={{ xs: 2, md: 3 }}
columns={{ xs: 4, sm: 8, md: 12 }}
>
{(props.setting && props.setting[rowKey]
? Array.from(t(props.setting[rowKey]).split("|"))
: [t("none"), t("none"), t("none")]
).map((text, index) => (
<Grid item xs={4} sm={4} md={4} key={index}>
<div
className="setting-card"
style={{
position: "relative",
height: "120px",
textAlign: "center",
justifyContent: "center",
display: "flex",
alignItems: "center",
cursor: "pointer",
}}
onClick={() => {
var newSetting = settingArr.slice();
newSetting[rowIndex] = index + 1;
setSettingArr(newSetting);
}}
>
{text}
<img
src={checkPng}
alt="check"
style={{
position: "absolute",
right: "10px",
top: "10px",
display:
index + 1 === settingArr[rowIndex] ? "block" : "none",
}}
/>
</div>
</Grid>
))}
</Grid>
</ListItem>
))}
</List>
<div
style={{
width: "80%",
alignItems: "center",
cursor: "pointer",
margin: "30px auto 0",
}}
>
{props.setting && (
<button
className="generate-btn"
onClick={async () => {
await props.generate({
topType: settingArr[0] + "",
centreType: settingArr[1] + "",
middleType: settingArr[2] + "",
});
setOpenPopup(true);
}}
>
{t("generate")}
</button>
)}
</div>
</div>
);
setOpenPopup(true);
}}/>
}
</div>
</div>
)
}
export default SettingFrame;

View File

@ -1,6 +1,4 @@
var BaseUrl = "https://api.soyootech.com/";
// var BaseUrl = "api/";
var BaseUrl = "http://api.soyootech.com/";
export async function UserLogin(loginForm) {
try {
var response = await fetch(BaseUrl + "SoyooUser/previewlogin", {

View File

@ -10,7 +10,7 @@ var client = new aliOss({
bucket: 'web-preview',
});
const baseBucketUrl = `https://web-preview.soyootech.com/`
const baseBucketUrl = `http://web-preview.soyootech.com/`
function getTenantPrefix () {
var tenant = utils.getTenant()

View File

@ -1,32 +0,0 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import en from "./locales/en.json";
import zh from "./locales/zh.json";
const resources = {
en: {
translation: en,
},
zh: {
translation: zh,
},
};
const lang = localStorage.getItem("lang") ?? "zh";
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: lang,
lng: lang,
debug: true,
resources: resources,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
});
export default i18n;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="13.435028612613678" height="13.435028612613678" viewBox="0 0 13.435028612613678 13.435028612613678"><g transform="matrix(0.7071067690849304,-0.7071067690849304,0.7071067690849304,0.7071067690849304,-4.335786265016024,2.9675144346638707)"><path d="M0.41421353816986084,15.217514306306839L8.91421353816986,15.217514306306839L8.91421353816986,13.217514306306839L2.414213538169861,13.217514306306839L2.414213538169861,6.717514306306839L0.41421353816986084,6.717514306306839L0.41421353816986084,15.217514306306839Z" fill-rule="evenodd" fill="#D8D8D8" fill-opacity="1"/></g></svg>

Before

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,10 +0,0 @@
import SvgIcon from '@mui/material/SvgIcon';
import React from "react";
export function ArrowIcon(props) {
return (
<SvgIcon viewBox="0 0 24 24" {...props}>
<path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" fill="white" />
</SvgIcon>
);
}

View File

@ -1,19 +1,14 @@
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import "./i18n";
import { I18nextProvider } from "react-i18next";
import i18n from "./i18n";
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>
</React.StrictMode>,
document.getElementById("root")
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function

View File

@ -1,20 +0,0 @@
{
"login": "Login",
"account": "Account",
"password": "Password",
"keepLoginStatus": "Keep the login status for 7 days",
"submit": "Submit",
"noAuth": "No permission",
"loginError": "Account or password is incorrect",
"horizontal": "Hor",
"vertical": "Vertical",
"scan": "Mobile preview",
"none": "None",
"start": "Start",
"middle": "Mid",
"end": "End",
"generate": "Generate",
"copySuccess": "link copy success",
"saveSuccess": "save success",
"language": "language"
}

View File

@ -1,20 +0,0 @@
{
"login": "登录",
"account": "账号",
"password": "密码",
"keepLoginStatus": "保持登录状态7天",
"submit": "提交",
"loginError": "账号或密码错误",
"noAuth": "无权限访问,请切换账号",
"horizontal": "横屏",
"vertical": "竖屏",
"scan": "手机预览",
"none": "无",
"start": "开头",
"middle": "中间",
"end": "结尾",
"generate": "一键生成",
"copySuccess": "链接复制成功",
"saveSuccess": "保存成功",
"language": "语言"
}

View File

@ -1,12 +0,0 @@
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
// app.use(
// "/api",
// createProxyMiddleware({
// target: "https://api.soyootech.com/",
// changeOrigin: true,
// pathRewrite: { "^/api": "" },
// })
// );
};