diff --git a/package-lock.json b/package-lock.json index 84f438e..506fc9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "playable-preview", "version": "0.1.0", "dependencies": { "@emotion/react": "^11.10.4", @@ -15,15 +16,21 @@ "@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": { @@ -1531,11 +1538,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", + "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -1553,6 +1560,11 @@ "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", @@ -3344,9 +3356,9 @@ "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" }, "node_modules/@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dependencies": { "@types/node": "*" } @@ -4696,11 +4708,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -5606,14 +5618,19 @@ } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -7206,9 +7223,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7952,6 +7969,14 @@ "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", @@ -8055,18 +8080,20 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", + "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, "dependencies": { - "@types/http-proxy": "^1.17.5", + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "micromatch": "^4.0.5" }, "engines": { - "node": ">=12.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/https-proxy-agent": { @@ -8097,6 +8124,36 @@ "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", @@ -10668,12 +10725,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -11410,11 +11467,14 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pirates": { @@ -13058,6 +13118,27 @@ "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", @@ -15137,6 +15218,14 @@ "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", @@ -15357,6 +15446,29 @@ "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", @@ -17185,11 +17297,18 @@ } }, "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", + "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", "requires": { - "regenerator-runtime": "^0.13.4" + "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==" + } } }, "@babel/runtime-corejs3": { @@ -18570,9 +18689,9 @@ "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" }, "@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "requires": { "@types/node": "*" } @@ -19747,11 +19866,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-process-hrtime": { @@ -20496,9 +20615,9 @@ "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "requires": { "ms": "2.1.2" } @@ -21794,9 +21913,9 @@ "integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg==" }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -22395,6 +22514,14 @@ } } }, + "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", @@ -22488,15 +22615,17 @@ } }, "http-proxy-middleware": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", + "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, "requires": { - "@types/http-proxy": "^1.17.5", + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "micromatch": "^4.0.5" } }, "https-proxy-agent": { @@ -22521,6 +22650,22 @@ "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", @@ -24547,12 +24692,12 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" } }, "mime": { @@ -25134,9 +25279,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pirates": { "version": "4.0.4", @@ -26387,6 +26532,15 @@ "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", @@ -26431,6 +26585,7 @@ "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", @@ -28103,6 +28258,11 @@ } } }, + "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", @@ -28311,6 +28471,18 @@ "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", diff --git a/package.json b/package.json index 206c4c6..b7e4f5e 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,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" @@ -45,5 +48,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "http-proxy-middleware": "^3.0.0" } } diff --git a/src/App.css b/src/App.css index 82de5b8..c424f10 100644 --- a/src/App.css +++ b/src/App.css @@ -1,48 +1,100 @@ .App { - text-align: center; - display: flex; - align-items: stretch; + text-align: center; + display: flex; + align-items: stretch; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } .MuiFormControlLabel-label { - font-size: 13px !important; + font-size: 13px !important; } .MuiDialog-root { - background-color: white; -} \ No newline at end of file + background-color: white; +} + +.pane-btn { + border-radius: 4px; + border: 0; + display: inline-block; + height: 30px; + width: 150px; + cursor: pointer; + outline: none; + font-weight: bold; +} + +.pane-btn.checked { + background-color: #02b564; + color: white; +} + +.pane-btn + .pane-btn { + margin-left: 10px; +} + +.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: absolute; + right: 40px; + top: 30px; + z-index: 9999; +} + +.language-select-container .language-select { + margin-left: 10px; + width: 120px; + height: 30px; +} + +.language-select-container .language-select fieldset { + display: none; +} diff --git a/src/App.js b/src/App.js index 487f6a0..cbeb609 100644 --- a/src/App.js +++ b/src/App.js @@ -8,12 +8,9 @@ import waterMarkPng from "./images/water-mark.png"; import React from "react"; import SettingFrame from "./Components/settingsFrame"; import QrCode from "qrcode"; -import { - getLoginInfo, - getProjectSettingValue, - setLoginInfo, - setProjectSetting, -} from "./storage"; +import { getLoginInfo, getProjectSettingValue, 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"; @@ -23,271 +20,271 @@ 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"; class App extends React.Component { - constructor() { - super(); - this.state = { - mode: "normal", - projects: [], - selectedProject: {}, - selectedProjectName: "", - device: "android-h", - htmlUrl: "", - dataUrl: "", - loading: false, - loginOpen: false, - loginErrorMessage: "", - hideLogo: false, - loginForm: { - account: "", - password: "", - keepLogin: false, - }, - }; - } - componentDidMount() { - const loginInfo = getLoginInfo(); - var tenant = utils.getTenant(); - const hideLogo = queryString.parseUrl(window.location.href)?.query - ?.hideLogo; - this.setState({ hideLogo: !!hideLogo }); - if (loginInfo && loginInfo.permissionPages.includes(tenant)) { - this.fetchData(); - this.refreshQrCode(); - } else { - this.setState({ loginOpen: true }); - loginInfo && - this.setState({ loginErrorMessage: "无权限访问,请切换账号" }); - } - } + constructor(props) { + super(); + this.state = { + mode: "normal", + projects: [], + selectedProject: {}, + selectedProjectName: "", + device: "android-h", + htmlUrl: "", + dataUrl: "", + loading: false, + loginOpen: false, + loginErrorMessage: "", + hideLogo: false, + loginForm: { + account: "", + password: "", + keepLogin: false, + }, + language: localStorage.getItem("lang") ?? "zh", + }; + this.t = props.t; + } + componentDidMount() { + const loginInfo = getLoginInfo(); + var tenant = utils.getTenant(); + const hideLogo = queryString.parseUrl(window.location.href)?.query?.hideLogo; + this.setState({ hideLogo: !!hideLogo }); + if (loginInfo && loginInfo.permissionPages.includes(tenant)) { + this.fetchData(); + this.refreshQrCode(); + } else { + this.setState({ loginOpen: true }); + loginInfo && this.setState({ loginErrorMessage: "noAuth" }); + } + } - login = async () => { - var { account, password, keepLogin } = this.state.loginForm; - var user = await LoginApi.UserLogin({ account, password }); - var tenant = utils.getTenant(); + login = async () => { + var { account, password, keepLogin } = this.state.loginForm; + var user = await LoginApi.UserLogin({ account, password }); + var tenant = utils.getTenant(); - if (user && user.permissionPages.includes(tenant)) { - this.setState({ - loginOpen: false, - }); - if (keepLogin) { - setLoginInfo(user); - } - this.fetchData(); - this.refreshQrCode(); - } else { - this.setState({ - loginErrorMessage: user - ? `无权限访问${tenant},请切换账号` - : "账号或密码错误", - }); - } - }; + if (user && user.permissionPages.includes(tenant)) { + this.setState({ + loginOpen: false, + }); + if (keepLogin) { + setLoginInfo(user); + } + this.fetchData(); + this.refreshQrCode(); + } else { + this.setState({ + loginErrorMessage: user ? "noAuth" : "loginError", + }); + } + }; - refreshQrCode() { - var { selectedProject } = this.state; - selectedProject.HtmlUrl && - QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], { - width: 120, - }).then((dataUrl) => { - this.setState({ - dataUrl: dataUrl, - }); - }); - } + refreshQrCode() { + var { selectedProject } = this.state; + selectedProject.HtmlUrl && + QrCode.toDataURL([{ data: this.selectedProjectUrl, mode: "byte" }], { + width: 120, + }).then((dataUrl) => { + this.setState({ + dataUrl: dataUrl, + }); + }); + } - get selectedProjectUrl() { - var { selectedProject } = this.state; - var settingValue = getProjectSettingValue(selectedProject?.Name) || [ - 1, 1, 1, - ]; - var rawUrl = selectedProject?.HtmlUrl - ? encodeURI(selectedProject?.HtmlUrl) - : ""; - if (rawUrl) { - rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`; - } + get selectedProjectUrl() { + var { selectedProject } = this.state; + var settingValue = getProjectSettingValue(selectedProject?.Name) || [1, 1, 1]; + var rawUrl = selectedProject?.HtmlUrl ? encodeURI(selectedProject?.HtmlUrl) : ""; + if (rawUrl) { + rawUrl += `?datanumber=${settingValue[0]}&datanumber1=${settingValue[1]}&datanumber2=${settingValue[2]}&lunaOrHtml=false`; + } - return rawUrl; - } + return rawUrl; + } - async setSelectedProject(selectedProjectName) { - this.setState({ - selectedProjectName: selectedProjectName, - }); - console.log("selected:", selectedProjectName); - await this.updateSelectedProject(selectedProjectName); - } + async setSelectedProject(selectedProjectName) { + this.setState({ + selectedProjectName: selectedProjectName, + }); + console.log("selected:", selectedProjectName); + await this.updateSelectedProject(selectedProjectName); + } - async updateSelectedProject(projectName) { - var projectSetting = await ProjectApi.getProjectSetting(projectName); - this.setState({ - selectedProject: projectSetting, - }); - } + 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, + }); + } - setDevice(selected) { - this.setState({ - device: selected, - }); - } + setDevice(selected) { + this.setState({ + device: selected, + }); + } - setMode(mode) { - this.setState({ - mode: mode, - }); - } + setMode(mode) { + this.setState({ + mode: mode, + }); + } - setLoginForm(form) { - this.setState({ - loginForm: { - ...this.state.loginForm, - ...form, - }, - }); - } + setLoginForm(form) { + this.setState({ + loginForm: { + ...this.state.loginForm, + ...form, + }, + }); + } - async fetchData() { - this.setState({ - loading: true, - }); + async fetchData() { + this.setState({ + loading: true, + }); - var projectNames = (await this.fetchProjects()) || ["无项目"]; - this.setState({ - projects: projectNames, - selectedProjectName: projectNames[0], - loading: false, - }); - await this.updateSelectedProject(projectNames[0]); - this.refreshQrCode(); - } + var projectNames = (await this.fetchProjects()) || ["无项目"]; + this.setState({ + projects: projectNames, + selectedProjectName: projectNames[0], + loading: false, + }); + await this.updateSelectedProject(projectNames[0]); + this.refreshQrCode(); + } - async fetchProjects() { - return await ProjectApi.getProjects(); - } + async fetchProjects() { + return await ProjectApi.getProjects(); + } - get projectSettingValue() { - return getProjectSettingValue(this.state.selectedProjectName); - } + get projectSettingValue() { + return getProjectSettingValue(this.state.selectedProjectName); + } - UpdateSetting(obj) { - setProjectSetting(this.state.selectedProject.Name, [ - +obj.topType, - +obj.centreType, - +obj.middleType, - ]); - } + UpdateSetting(obj) { + setProjectSetting(this.state.selectedProject.Name, [+obj.topType, +obj.centreType, +obj.middleType]); + } - render() { - var { - mode, - device, - projects, - selectedProject, - dataUrl, - loading, - loginOpen, - loginForm, - hideLogo, - } = this.state; + render() { + var { mode, device, projects, selectedProject, dataUrl, loading, loginOpen, loginForm, hideLogo, language } = this.state; + const { t } = this.props; - return ( -
- - 登录 - - this.setLoginForm({ account: e.target.value })} - onKeyDown={(e) => e.keyCode === 13 && this.login()} - /> - this.setLoginForm({ password: e.target.value })} - onKeyDown={(e) => e.keyCode === 13 && this.login()} - /> - - - {this.state.loginErrorMessage && ( - - {this.state.loginErrorMessage} - - )} - - this.setLoginForm({ keepLogin: checked }) - } - /> - } - label="保持登录状态7天" - /> - - - - this.setMode(_mode)} - projects={projects} - device={device} - loading={loading} - hideLogo={hideLogo} - onProjectSelect={(project) => { - this.setSelectedProject(project); - }} - onDeviceChange={(_device) => this.setDevice(_device)} - /> -
- {mode === "normal" ? ( - this.refreshQrCode()} - /> - ) : ( - this.UpdateSetting(value)} - /> - )} -
-
- ); - } + return ( +
+ + {t("login")} + + this.setLoginForm({ account: e.target.value })} + onKeyDown={(e) => e.keyCode === 13 && this.login()} + /> + this.setLoginForm({ password: e.target.value })} + onKeyDown={(e) => e.keyCode === 13 && this.login()} + /> + + + {this.state.loginErrorMessage && ( + + {t(this.state.loginErrorMessage)} + + )} + this.setLoginForm({ keepLogin: checked })} />} + label={t("keepLoginStatus")} + /> + + + + this.setMode(_mode)} + projects={projects} + device={device} + loading={loading} + hideLogo={hideLogo} + onProjectSelect={(project) => { + this.setSelectedProject(project); + }} + onDeviceChange={(_device) => this.setDevice(_device)} + /> +
+
{t("language")}:
+ +
+
+ {mode === "normal" ? ( + this.refreshQrCode()} /> + ) : ( + this.UpdateSetting(value)} /> + )} +
+
+ ); + } } -export default App; +export default withTranslation()(App); diff --git a/src/Components/deviceFrame/index.css b/src/Components/deviceFrame/index.css index 86b34c0..5cfde14 100644 --- a/src/Components/deviceFrame/index.css +++ b/src/Components/deviceFrame/index.css @@ -18,6 +18,6 @@ .qrCode { position: absolute; - right: 30px; - top: 30px; + right: 40px; + top: 100px; } \ No newline at end of file diff --git a/src/Components/deviceFrame/index.js b/src/Components/deviceFrame/index.js index 7f5707b..7fd80ae 100644 --- a/src/Components/deviceFrame/index.js +++ b/src/Components/deviceFrame/index.js @@ -1,117 +1,124 @@ -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' +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"; +import { useTranslation } from "react-i18next"; var configMap = { - "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', - }, -} + "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(''); + var [config, setConfig] = useState({}); + var [cacheKey, setCacheKey] = useState(new Date().getTime()); + var [openPopup, setOpenPopup] = useState(false); + var [absoluteUrl, setAbsoluteUrl] = useState(""); + const { t } = useTranslation(); - useEffect(() => { - setConfig(configMap[props.device]) - }, [props.device, config]) + useEffect(() => { + setConfig(configMap[props.device]); + }, [props.device, config]); - var refresh = () => setCacheKey(new Date().getTime()); + 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]) + useEffect(() => { + console.log("触发更新", props.htmlUrl); + props.htmlUrl && setAbsoluteUrl(!props.htmlUrl.startsWith("http") ? BaseUrl + props.htmlUrl : props.htmlUrl); + refresh(); + props.refreshQrCode(); + }, [props.htmlUrl]); - return ( -
- refresh refresh()} className='refreshButton'/> - { props.qrDataUrl && -
-

扫一扫,手机预览 - setOpenPopup(true)}> - 复制链接 - -

- qr code -
- } - setOpenPopup(false)} autoHideDuration={500} anchorOrigin={{ - vertical: 'top', - horizontal: 'right' - }}> - - 链接复制成功 - - -
- background - { - props.htmlUrl - &&