u
This commit is contained in:
174
package-lock.json
generated
174
package-lock.json
generated
@@ -34,12 +34,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@vitejs/plugin-react": "6.1.1",
|
"@vitejs/plugin-react": "6.1.1",
|
||||||
"eslint": "^10.11.0",
|
"eslint": "^10.12.0",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"globals": "^17.12.0",
|
"globals": "^17.13.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"vite": "^8.3.1",
|
"vite": "^8.3.2",
|
||||||
"vite-plugin-pwa": "^1.3.0"
|
"vite-plugin-pwa": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"../automat": {
|
"../automat": {
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"@vitejs/plugin-react": "6.1.1",
|
"@vitejs/plugin-react": "6.1.1",
|
||||||
"react": "^19.3.0",
|
"react": "^19.3.0",
|
||||||
"react-dom": "^19.3.0",
|
"react-dom": "^19.3.0",
|
||||||
"vite": "^8.3.1"
|
"vite": "^8.3.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
@@ -2931,9 +2931,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.150.0",
|
"version": "0.152.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.152.0.tgz",
|
||||||
"integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==",
|
"integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -2951,9 +2951,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm-eabi": {
|
"node_modules/@rolldown/binding-android-arm-eabi": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz",
|
||||||
"integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==",
|
"integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -2968,9 +2968,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz",
|
||||||
"integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==",
|
"integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -2985,9 +2985,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz",
|
||||||
"integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==",
|
"integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -3002,9 +3002,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz",
|
||||||
"integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==",
|
"integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -3019,9 +3019,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz",
|
||||||
"integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==",
|
"integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -3036,9 +3036,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz",
|
||||||
"integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==",
|
"integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -3053,9 +3053,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz",
|
||||||
"integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==",
|
"integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -3073,9 +3073,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz",
|
||||||
"integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==",
|
"integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -3093,9 +3093,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz",
|
||||||
"integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==",
|
"integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -3113,9 +3113,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz",
|
||||||
"integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==",
|
"integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -3133,9 +3133,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz",
|
||||||
"integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==",
|
"integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -3153,9 +3153,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz",
|
||||||
"integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==",
|
"integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -3173,9 +3173,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz",
|
||||||
"integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==",
|
"integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -3190,9 +3190,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz",
|
||||||
"integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==",
|
"integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -3207,9 +3207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz",
|
||||||
"integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==",
|
"integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -4926,9 +4926,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "10.11.0",
|
"version": "10.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.12.0.tgz",
|
||||||
"integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==",
|
"integrity": "sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -5528,9 +5528,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "17.12.0",
|
"version": "17.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz",
|
||||||
"integrity": "sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==",
|
"integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -7666,13 +7666,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.12.tgz",
|
||||||
"integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==",
|
"integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.150.0",
|
"@oxc-project/types": "=0.152.0",
|
||||||
"@rolldown/pluginutils": "^1.0.0"
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -7682,21 +7682,21 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm-eabi": "1.2.9",
|
"@rolldown/binding-android-arm-eabi": "1.2.12",
|
||||||
"@rolldown/binding-android-arm64": "1.2.9",
|
"@rolldown/binding-android-arm64": "1.2.12",
|
||||||
"@rolldown/binding-darwin-arm64": "1.2.9",
|
"@rolldown/binding-darwin-arm64": "1.2.12",
|
||||||
"@rolldown/binding-darwin-x64": "1.2.9",
|
"@rolldown/binding-darwin-x64": "1.2.12",
|
||||||
"@rolldown/binding-freebsd-x64": "1.2.9",
|
"@rolldown/binding-freebsd-x64": "1.2.12",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.2.9",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.2.12",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.2.9",
|
"@rolldown/binding-linux-arm64-gnu": "1.2.12",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.2.9",
|
"@rolldown/binding-linux-arm64-musl": "1.2.12",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.2.9",
|
"@rolldown/binding-linux-ppc64-gnu": "1.2.12",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.2.9",
|
"@rolldown/binding-linux-s390x-gnu": "1.2.12",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.2.9",
|
"@rolldown/binding-linux-x64-gnu": "1.2.12",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.2.9",
|
"@rolldown/binding-linux-x64-musl": "1.2.12",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.2.9",
|
"@rolldown/binding-openharmony-arm64": "1.2.12",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.2.9",
|
"@rolldown/binding-win32-arm64-msvc": "1.2.12",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.2.9"
|
"@rolldown/binding-win32-x64-msvc": "1.2.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
@@ -8736,16 +8736,16 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.3.1",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.2.tgz",
|
||||||
"integrity": "sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==",
|
"integrity": "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.33.0",
|
"lightningcss": "^1.33.0",
|
||||||
"picomatch": "^4.0.7",
|
"picomatch": "^4.0.7",
|
||||||
"postcss": "^8.5.28",
|
"postcss": "^8.5.28",
|
||||||
"rolldown": "~1.2.9",
|
"rolldown": "~1.2.11",
|
||||||
"tinyglobby": "^0.2.17"
|
"tinyglobby": "^0.2.17"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -8814,9 +8814,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite-plugin-pwa": {
|
"node_modules/vite-plugin-pwa": {
|
||||||
"version": "1.3.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-2.0.0.tgz",
|
||||||
"integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==",
|
"integrity": "sha512-6G9dsPKT9QKYpeTuTLJM28zZL3HsXUTUM/QUZBEgQk2jbfrPJDq2i8gTewAKqi1c9Mt6MiidrL4SFI+HthiQMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -8827,13 +8827,13 @@
|
|||||||
"workbox-window": "^7.4.1"
|
"workbox-window": "^7.4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0"
|
"node": ">=20.19.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vite-pwa/assets-generator": "^1.0.0",
|
"@vite-pwa/assets-generator": "^1.0.0 || ^2.0.0",
|
||||||
"vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
"vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||||
"workbox-build": "^7.4.1",
|
"workbox-build": "^7.4.1",
|
||||||
"workbox-window": "^7.4.1"
|
"workbox-window": "^7.4.1"
|
||||||
|
|||||||
@@ -41,12 +41,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@vitejs/plugin-react": "6.1.1",
|
"@vitejs/plugin-react": "6.1.1",
|
||||||
"eslint": "^10.11.0",
|
"eslint": "^10.12.0",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"globals": "^17.12.0",
|
"globals": "^17.13.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"vite": "^8.3.1",
|
"vite": "^8.3.2",
|
||||||
"vite-plugin-pwa": "^1.3.0"
|
"vite-plugin-pwa": "^2.0.0"
|
||||||
},
|
},
|
||||||
"allowScripts": {
|
"allowScripts": {
|
||||||
"canvas@3.2.3": true,
|
"canvas@3.2.3": true,
|
||||||
|
|||||||
@@ -34,6 +34,36 @@ const initialState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let categoryAutomat;
|
let categoryAutomat;
|
||||||
|
let _treeLoadingPromise = null;
|
||||||
|
|
||||||
|
function waitForCategoryTree() {
|
||||||
|
if (categoryAutomat.state.treeStatus === 'succeeded') {
|
||||||
|
return Promise.resolve(categoryAutomat.state);
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let unsubCat = null;
|
||||||
|
let unsubAuth = null;
|
||||||
|
const cleanup = () => {
|
||||||
|
unsubCat?.();
|
||||||
|
unsubAuth?.();
|
||||||
|
};
|
||||||
|
unsubCat = categoryAutomat.subscribe((state) => {
|
||||||
|
if (state.treeStatus === 'succeeded') {
|
||||||
|
cleanup();
|
||||||
|
resolve(state);
|
||||||
|
} else if (state.treeStatus === 'failed') {
|
||||||
|
cleanup();
|
||||||
|
reject(new Error(state.error || 'Fehler beim Laden des Kategoriebaums'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
unsubAuth = authAutomat.subscribe((auth) => {
|
||||||
|
if (auth.status === 'anon') {
|
||||||
|
cleanup();
|
||||||
|
reject(new Error('Nicht authentifiziert.'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KeyedAutomat holding per-route category views indexed by slug path.
|
* KeyedAutomat holding per-route category views indexed by slug path.
|
||||||
@@ -50,7 +80,10 @@ export const categoryViews = new KeyedAutomat(
|
|||||||
|
|
||||||
// Ensure tree is loaded before resolving slug -> categoryId
|
// Ensure tree is loaded before resolving slug -> categoryId
|
||||||
if (categoryAutomat.state.treeStatus !== 'succeeded') {
|
if (categoryAutomat.state.treeStatus !== 'succeeded') {
|
||||||
await categoryAutomat.actions.loadTree();
|
if (categoryAutomat.state.treeStatus === 'idle') {
|
||||||
|
void categoryAutomat.actions.loadTree();
|
||||||
|
}
|
||||||
|
await waitForCategoryTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { categories, rootCategoryId } = categoryAutomat.state;
|
const { categories, rootCategoryId } = categoryAutomat.state;
|
||||||
@@ -117,31 +150,43 @@ export function disposeAllCategoryViewAutomats() {
|
|||||||
const actions = {
|
const actions = {
|
||||||
/** Load the category tree for the currently selected company. */
|
/** Load the category tree for the currently selected company. */
|
||||||
async loadTree() {
|
async loadTree() {
|
||||||
const company = companyAutomat.state.current;
|
let company = companyAutomat.state.current;
|
||||||
|
if (!company && companyAutomat.state.status === 'idle') {
|
||||||
|
await companyAutomat.actions.load();
|
||||||
|
company = companyAutomat.state.current;
|
||||||
|
}
|
||||||
if (!company) return;
|
if (!company) return;
|
||||||
const { id: companyId, rootCategoryId: companyRootId } = company;
|
const { id: companyId, rootCategoryId: companyRootId } = company;
|
||||||
if (!companyRootId) return;
|
if (!companyRootId) return;
|
||||||
|
|
||||||
|
if (_treeLoadingPromise) return _treeLoadingPromise;
|
||||||
|
|
||||||
categoryAutomat.setState({ treeStatus: 'loading', error: null });
|
categoryAutomat.setState({ treeStatus: 'loading', error: null });
|
||||||
try {
|
_treeLoadingPromise = (async () => {
|
||||||
const data = await categoryApi.getTree();
|
try {
|
||||||
const parsed = parseCategoryTreeResponse(data, companyRootId);
|
const data = await categoryApi.getTree();
|
||||||
categoryAutomat.setState({
|
const parsed = parseCategoryTreeResponse(data, companyRootId);
|
||||||
treeStatus: 'succeeded',
|
categoryAutomat.setState({
|
||||||
companyId,
|
treeStatus: 'succeeded',
|
||||||
languageId: parsed.languageId,
|
companyId,
|
||||||
categories: parsed.categories,
|
languageId: parsed.languageId,
|
||||||
rootCategoryId: parsed.rootCategoryId,
|
categories: parsed.categories,
|
||||||
error: null,
|
rootCategoryId: parsed.rootCategoryId,
|
||||||
});
|
error: null,
|
||||||
refreshLoadedCategoryViewChildren(parsed.categories);
|
});
|
||||||
} catch (err) {
|
refreshLoadedCategoryViewChildren(parsed.categories);
|
||||||
categoryAutomat.setState({
|
} catch (err) {
|
||||||
treeStatus: 'failed',
|
categoryAutomat.setState({
|
||||||
error: err?.message ?? String(err),
|
treeStatus: 'failed',
|
||||||
});
|
error: err?.message ?? String(err),
|
||||||
throw err;
|
});
|
||||||
}
|
throw err;
|
||||||
|
}
|
||||||
|
})().finally(() => {
|
||||||
|
_treeLoadingPromise = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return _treeLoadingPromise;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Toggle rename/edit mode for the category grid. */
|
/** Toggle rename/edit mode for the category grid. */
|
||||||
@@ -429,8 +474,11 @@ companyAutomat.subscribe((company) => {
|
|||||||
const id = company.current?.id ?? null;
|
const id = company.current?.id ?? null;
|
||||||
const rootCategoryId = company.current?.rootCategoryId ?? null;
|
const rootCategoryId = company.current?.rootCategoryId ?? null;
|
||||||
if (id && rootCategoryId && id !== _lastCompanyId) {
|
if (id && rootCategoryId && id !== _lastCompanyId) {
|
||||||
|
const isCompanySwitch = _lastCompanyId !== null;
|
||||||
_lastCompanyId = id;
|
_lastCompanyId = id;
|
||||||
disposeAllCategoryViewAutomats();
|
if (isCompanySwitch) {
|
||||||
|
disposeAllCategoryViewAutomats();
|
||||||
|
}
|
||||||
void categoryAutomat.actions.loadTree();
|
void categoryAutomat.actions.loadTree();
|
||||||
}
|
}
|
||||||
if (!id && _lastCompanyId) {
|
if (!id && _lastCompanyId) {
|
||||||
|
|||||||
@@ -1,6 +1,48 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { thumbHashToRGBA } from 'thumbhash';
|
import { thumbHashToRGBA, thumbHashToDataURL } from 'thumbhash';
|
||||||
|
|
||||||
|
const dataUrlCache = (globalThis.__THUMB_DATA_URL_CACHE__ ??= new Map());
|
||||||
|
const loadedImageHashes = (globalThis.__LOADED_IMAGE_HASHES__ ??= new Set());
|
||||||
|
export const imageCache = (globalThis.__IMAGE_CACHE__ ??= new Map());
|
||||||
|
|
||||||
|
export function isImageLoaded(fullHash) {
|
||||||
|
if (!fullHash) return false;
|
||||||
|
return loadedImageHashes.has(fullHash) || imageCache.has(fullHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function markImageLoaded(fullHash, img) {
|
||||||
|
if (!fullHash) return;
|
||||||
|
loadedImageHashes.add(fullHash);
|
||||||
|
if (img) {
|
||||||
|
imageCache.set(fullHash, img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCachedImage(fullHash) {
|
||||||
|
if (!fullHash) return null;
|
||||||
|
const img = imageCache.get(fullHash);
|
||||||
|
if (img && img.complete && img.naturalWidth) {
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getThumbHashDataUrl(thumbHash) {
|
||||||
|
if (!thumbHash || typeof thumbHash !== 'string') return null;
|
||||||
|
let url = dataUrlCache.get(thumbHash);
|
||||||
|
if (!url) {
|
||||||
|
try {
|
||||||
|
const bytes = Uint8Array.from(atob(thumbHash), (c) => c.charCodeAt(0));
|
||||||
|
url = thumbHashToDataURL(bytes);
|
||||||
|
dataUrlCache.set(thumbHash, url);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[ThumbHashImage] thumbHashToDataURL failed:', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
export function decodeThumbHash(thumbHash) {
|
export function decodeThumbHash(thumbHash) {
|
||||||
if (!thumbHash || typeof thumbHash !== 'string') return null;
|
if (!thumbHash || typeof thumbHash !== 'string') return null;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Typography from '@mui/material/Typography';
|
|||||||
import { Tile, tileBaseSx } from 'dashgui/tiles';
|
import { Tile, tileBaseSx } from 'dashgui/tiles';
|
||||||
import { formatPrice } from '../../utils/price';
|
import { formatPrice } from '../../utils/price';
|
||||||
import { articleSku } from '../article/articleRoute';
|
import { articleSku } from '../article/articleRoute';
|
||||||
import { decodeThumbHash } from '../article/ThumbHashImage';
|
import { getThumbHashDataUrl, getCachedImage, imageCache } from '../article/ThumbHashImage';
|
||||||
import { BrandLabel } from '../brand';
|
import { BrandLabel } from '../brand';
|
||||||
import { thumb } from '../../api';
|
import { thumb } from '../../api';
|
||||||
|
|
||||||
@@ -100,12 +100,22 @@ class ArticleTileBackdrop extends PureComponent {
|
|||||||
img = null;
|
img = null;
|
||||||
observer = null;
|
observer = null;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.thumbUrl = getThumbHashDataUrl(props.thumbHash);
|
||||||
|
this.img = getCachedImage(props.fullHash);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.loadImage();
|
this.loadImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
|
if (prevProps.thumbHash !== this.props.thumbHash) {
|
||||||
|
this.thumbUrl = getThumbHashDataUrl(this.props.thumbHash);
|
||||||
|
}
|
||||||
if (prevProps.fullHash !== this.props.fullHash) {
|
if (prevProps.fullHash !== this.props.fullHash) {
|
||||||
|
this.img = getCachedImage(this.props.fullHash);
|
||||||
this.loadImage();
|
this.loadImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,8 +128,15 @@ class ArticleTileBackdrop extends PureComponent {
|
|||||||
loadImage() {
|
loadImage() {
|
||||||
const { fullHash } = this.props;
|
const { fullHash } = this.props;
|
||||||
if (fullHash) {
|
if (fullHash) {
|
||||||
|
const cached = getCachedImage(fullHash);
|
||||||
|
if (cached) {
|
||||||
|
this.img = cached;
|
||||||
|
this.paint();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
|
imageCache.set(fullHash, img);
|
||||||
if (this.img === img) {
|
if (this.img === img) {
|
||||||
this.paint();
|
this.paint();
|
||||||
}
|
}
|
||||||
@@ -127,15 +144,18 @@ class ArticleTileBackdrop extends PureComponent {
|
|||||||
img.src = thumb.url(fullHash);
|
img.src = thumb.url(fullHash);
|
||||||
this.img = img;
|
this.img = img;
|
||||||
if (img.complete && img.naturalWidth) {
|
if (img.complete && img.naturalWidth) {
|
||||||
|
imageCache.set(fullHash, img);
|
||||||
this.paint();
|
this.paint();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.paint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setCanvas = (canvas) => {
|
setCanvas = (canvas) => {
|
||||||
this.canvasRef = canvas;
|
this.canvasRef = canvas;
|
||||||
|
if (!this.img && this.props.fullHash) {
|
||||||
|
this.img = getCachedImage(this.props.fullHash);
|
||||||
|
}
|
||||||
if (canvas && typeof ResizeObserver !== 'undefined') {
|
if (canvas && typeof ResizeObserver !== 'undefined') {
|
||||||
this.observer?.disconnect();
|
this.observer?.disconnect();
|
||||||
this.observer = new ResizeObserver(() => this.paint());
|
this.observer = new ResizeObserver(() => this.paint());
|
||||||
@@ -157,8 +177,9 @@ class ArticleTileBackdrop extends PureComponent {
|
|||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
const img = this.img;
|
const img = this.img || getCachedImage(this.props.fullHash);
|
||||||
if (img && img.complete && img.naturalWidth && img.naturalHeight) {
|
if (img && img.complete && img.naturalWidth && img.naturalHeight) {
|
||||||
|
this.img = img;
|
||||||
drawContainedWithStretchedEdges(
|
drawContainedWithStretchedEdges(
|
||||||
ctx,
|
ctx,
|
||||||
img,
|
img,
|
||||||
@@ -167,41 +188,49 @@ class ArticleTileBackdrop extends PureComponent {
|
|||||||
dstW,
|
dstW,
|
||||||
dstH,
|
dstH,
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { thumbHash } = this.props;
|
|
||||||
if (thumbHash) {
|
|
||||||
const decoded = decodeThumbHash(thumbHash);
|
|
||||||
if (decoded) {
|
|
||||||
const { w, h, rgba } = decoded;
|
|
||||||
const temp = document.createElement('canvas');
|
|
||||||
temp.width = w;
|
|
||||||
temp.height = h;
|
|
||||||
temp.getContext('2d').putImageData(
|
|
||||||
new ImageData(new Uint8ClampedArray(rgba), w, h),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
drawContainedWithStretchedEdges(ctx, temp, w, h, dstW, dstH);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const hasCachedImage = Boolean(this.img && this.img.complete && this.img.naturalWidth);
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
component="canvas"
|
|
||||||
ref={this.setCanvas}
|
|
||||||
aria-hidden
|
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
inset: 0,
|
inset: 0,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'block',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
{!hasCachedImage && this.thumbUrl ? (
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={this.thumbUrl}
|
||||||
|
alt=""
|
||||||
|
aria-hidden
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
inset: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: 'cover',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<Box
|
||||||
|
component="canvas"
|
||||||
|
ref={this.setCanvas}
|
||||||
|
aria-hidden
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
inset: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'block',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import SettingsIcon from '@mui/icons-material/Settings';
|
|||||||
import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
|
import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
|
||||||
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
|
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
|
||||||
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
|
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
|
||||||
import ThumbHashImage from '../article/ThumbHashImage';
|
import { getThumbHashDataUrl, getCachedImage, imageCache } from '../article/ThumbHashImage';
|
||||||
import { thumb } from '../../api';
|
import { thumb } from '../../api';
|
||||||
import { tileBaseSx } from 'dashgui/tiles';
|
import { tileBaseSx } from 'dashgui/tiles';
|
||||||
|
|
||||||
@@ -195,36 +195,56 @@ function MiddleBand({ settingsTab, nameInput, terminals, categoryPosterminalIds,
|
|||||||
* ThumbHash is shown immediately as a placeholder; the thumb fades in once loaded.
|
* ThumbHash is shown immediately as a placeholder; the thumb fades in once loaded.
|
||||||
*/
|
*/
|
||||||
class CategoryBackdrop extends PureComponent {
|
class CategoryBackdrop extends PureComponent {
|
||||||
state = { thumbLoaded: false };
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.thumbUrl = getThumbHashDataUrl(props.thumbHash);
|
||||||
|
this.isCached = Boolean(getCachedImage(props.fullHash));
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
|
if (prevProps.thumbHash !== this.props.thumbHash) {
|
||||||
|
this.thumbUrl = getThumbHashDataUrl(this.props.thumbHash);
|
||||||
|
}
|
||||||
if (prevProps.fullHash !== this.props.fullHash) {
|
if (prevProps.fullHash !== this.props.fullHash) {
|
||||||
this.setState({ thumbLoaded: false });
|
this.isCached = Boolean(getCachedImage(this.props.fullHash));
|
||||||
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleThumbLoad = () => {
|
handleLoad = (e) => {
|
||||||
this.setState({ thumbLoaded: true });
|
if (this.props.fullHash && e.target) {
|
||||||
};
|
imageCache.set(this.props.fullHash, e.target);
|
||||||
|
}
|
||||||
handleThumbError = () => {
|
|
||||||
this.setState({ thumbLoaded: false });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { thumbHash, fullHash } = this.props;
|
const { fullHash } = this.props;
|
||||||
const { thumbLoaded } = this.state;
|
if (!this.thumbUrl && !fullHash) return null;
|
||||||
if (!thumbHash && !fullHash) return null;
|
const isCached = this.isCached || Boolean(getCachedImage(fullHash));
|
||||||
return (
|
return (
|
||||||
<Box sx={{ position: 'absolute', inset: 0, zIndex: 0, overflow: 'hidden' }}>
|
<Box sx={{ position: 'absolute', inset: 0, zIndex: 0, overflow: 'hidden' }}>
|
||||||
{thumbHash && !thumbLoaded ? <ThumbHashImage thumbHash={thumbHash} /> : null}
|
{!isCached && this.thumbUrl ? (
|
||||||
{fullHash ? (
|
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src={thumb.url(fullHash)}
|
src={this.thumbUrl}
|
||||||
alt=""
|
alt=""
|
||||||
onLoad={this.handleThumbLoad}
|
aria-hidden
|
||||||
onError={this.handleThumbError}
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
inset: 0,
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: 'cover',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{fullHash ? (
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={thumb.url(fullHash)}
|
||||||
|
alt=""
|
||||||
|
onLoad={this.handleLoad}
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
inset: 0,
|
inset: 0,
|
||||||
@@ -232,7 +252,6 @@ class CategoryBackdrop extends PureComponent {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
objectFit: 'cover',
|
objectFit: 'cover',
|
||||||
opacity: thumbLoaded ? 1 : 0,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import PeopleIcon from '@mui/icons-material/People';
|
|||||||
import InfoIcon from '@mui/icons-material/Info';
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
import ViewListIcon from '@mui/icons-material/ViewList';
|
import ViewListIcon from '@mui/icons-material/ViewList';
|
||||||
import CategoryIcon from '@mui/icons-material/Category';
|
import CategoryIcon from '@mui/icons-material/Category';
|
||||||
|
import GridViewIcon from '@mui/icons-material/GridView';
|
||||||
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||||
import CopyrightIcon from '@mui/icons-material/Copyright';
|
import CopyrightIcon from '@mui/icons-material/Copyright';
|
||||||
import ListAltIcon from '@mui/icons-material/ListAlt';
|
import ListAltIcon from '@mui/icons-material/ListAlt';
|
||||||
@@ -16,7 +17,6 @@ import StorefrontIcon from '@mui/icons-material/Storefront';
|
|||||||
import RequestQuoteIcon from '@mui/icons-material/RequestQuote';
|
import RequestQuoteIcon from '@mui/icons-material/RequestQuote';
|
||||||
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
|
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
|
||||||
import LabelIcon from '@mui/icons-material/Label';
|
import LabelIcon from '@mui/icons-material/Label';
|
||||||
import TuneIcon from '@mui/icons-material/Tune';
|
|
||||||
import HistoryIcon from '@mui/icons-material/History';
|
import HistoryIcon from '@mui/icons-material/History';
|
||||||
import PublicIcon from '@mui/icons-material/Public';
|
import PublicIcon from '@mui/icons-material/Public';
|
||||||
import BarChartIcon from '@mui/icons-material/BarChart';
|
import BarChartIcon from '@mui/icons-material/BarChart';
|
||||||
@@ -142,7 +142,7 @@ export const SUB_NAV = {
|
|||||||
segment: 'kategorien',
|
segment: 'kategorien',
|
||||||
label: 'Kategorieen',
|
label: 'Kategorieen',
|
||||||
title: 'Kategorien',
|
title: 'Kategorien',
|
||||||
icon: CategoryIcon,
|
icon: GridViewIcon,
|
||||||
help: 'Hierarchischer Kategoriebaum zur Sortimentsgliederung',
|
help: 'Hierarchischer Kategoriebaum zur Sortimentsgliederung',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -167,7 +167,7 @@ export const SUB_NAV = {
|
|||||||
segment: 'merkmale',
|
segment: 'merkmale',
|
||||||
label: 'Merkmale',
|
label: 'Merkmale',
|
||||||
title: 'Merkmale & Attribute',
|
title: 'Merkmale & Attribute',
|
||||||
icon: TuneIcon,
|
icon: CategoryIcon,
|
||||||
help: 'Globale Merkmale, Attribute und Werte verwalten',
|
help: 'Globale Merkmale, Attribute und Werte verwalten',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -238,11 +238,22 @@ class ArtikelKategorienPage extends PureComponent {
|
|||||||
routeError: view?.error ?? null,
|
routeError: view?.error ?? null,
|
||||||
});
|
});
|
||||||
this.subscribeViewHandle();
|
this.subscribeViewHandle();
|
||||||
} else if (resolvedId !== resolvedCategoryId) {
|
} else {
|
||||||
this.setState({
|
const view = this.handle?.state;
|
||||||
resolvedCategoryId: resolvedId,
|
const updates = {};
|
||||||
childCategories: getCategoryChildren(categories, resolvedId),
|
if (resolvedId !== resolvedCategoryId) {
|
||||||
});
|
updates.resolvedCategoryId = resolvedId;
|
||||||
|
updates.childCategories = view?.data?.childCategories ?? getCategoryChildren(categories, resolvedId);
|
||||||
|
}
|
||||||
|
if (view?.data?.articles && view.data.articles !== this.state.articles) {
|
||||||
|
updates.articles = view.data.articles;
|
||||||
|
}
|
||||||
|
if (Object.keys(updates).length > 0) {
|
||||||
|
this.setState(updates);
|
||||||
|
}
|
||||||
|
if (!this.handle?.loaded && !this.handle?.loading) {
|
||||||
|
void this.handle?.load().catch(() => {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user