Add filters

This commit is contained in:
Brian Beck 2023-06-23 01:06:56 -07:00
parent 9708095615
commit 5715e2fc03
30 changed files with 360 additions and 37 deletions

View file

@ -24,6 +24,7 @@ module.exports = {
"react/prop-types": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/78e521c3-312593b4f3190cc4.js","static/chunks/95b64a6e-6f3d919198a9be32.js","static/chunks/31664189-b73d5a5994fa8d3b.js","static/chunks/545f34e4-f96cf9e26b6b92a5.js","static/chunks/1bfc9850-6b316c8ef06e5170.js","static/chunks/d7eeaac4-06e64d251e2cbda7.js","static/chunks/f580fadb-a8e2c6896615a304.js","static/chunks/50-cece886aa17c1d5e.js","static/chunks/pages/index-6451d5cede953f2b.js"],"/_error":["static/chunks/pages/_error-479484f6c157e921.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/78e521c3-312593b4f3190cc4.js","static/chunks/95b64a6e-6f3d919198a9be32.js","static/chunks/31664189-f79df42a6a9e05f8.js","static/chunks/545f34e4-f96cf9e26b6b92a5.js","static/chunks/1bfc9850-6b316c8ef06e5170.js","static/chunks/d7eeaac4-06e64d251e2cbda7.js","static/chunks/f580fadb-a8e2c6896615a304.js","static/chunks/50-cece886aa17c1d5e.js","static/chunks/pages/index-dce4039e544712d9.js"],"/_error":["static/chunks/pages/_error-479484f6c157e921.js"],sortedPages:["/","/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View file

@ -1,2 +0,0 @@
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[609],{3990:function(t,n,c){c.d(n,{UIL:function(){return v},rks:function(){return a},yAv:function(){return e}});var r=c(8357);function v(t){return(0,r.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M11.904 16c1.777-3.219 2.076-8.13-4.904-7.966v3.966l-6-6 6-6v3.881c8.359-0.218 9.29 7.378 4.904 12.119z"}}]})(t)}function a(t){return(0,r.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M9 3.881v-3.881l6 6-6 6v-3.966c-6.98-0.164-6.681 4.747-4.904 7.966-4.386-4.741-3.455-12.337 4.904-12.119z"}}]})(t)}function e(t){return(0,r.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M15.5 6h-5.5v-5.5c0-0.276-0.224-0.5-0.5-0.5h-3c-0.276 0-0.5 0.224-0.5 0.5v5.5h-5.5c-0.276 0-0.5 0.224-0.5 0.5v3c0 0.276 0.224 0.5 0.5 0.5h5.5v5.5c0 0.276 0.224 0.5 0.5 0.5h3c0.276 0 0.5-0.224 0.5-0.5v-5.5h5.5c0.276 0 0.5-0.224 0.5-0.5v-3c0-0.276-0.224-0.5-0.5-0.5z"}}]})(t)}}}]);
//# sourceMappingURL=31664189-b73d5a5994fa8d3b.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[609],{3990:function(t,n,r){r.d(n,{J76:function(){return i},UIL:function(){return v},rks:function(){return a},yAv:function(){return e}});var c=r(8357);function v(t){return(0,c.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M11.904 16c1.777-3.219 2.076-8.13-4.904-7.966v3.966l-6-6 6-6v3.881c8.359-0.218 9.29 7.378 4.904 12.119z"}}]})(t)}function a(t){return(0,c.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M9 3.881v-3.881l6 6-6 6v-3.966c-6.98-0.164-6.681 4.747-4.904 7.966-4.386-4.741-3.455-12.337 4.904-12.119z"}}]})(t)}function i(t){return(0,c.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M8 0c-4.418 0-8 3.582-8 8s3.582 8 8 8 8-3.582 8-8-3.582-8-8-8zM2 8c0-3.314 2.686-6 6-6v12c-3.314 0-6-2.686-6-6z"}}]})(t)}function e(t){return(0,c.w_)({tag:"svg",attr:{version:"1.1",viewBox:"0 0 16 16"},child:[{tag:"path",attr:{d:"M15.5 6h-5.5v-5.5c0-0.276-0.224-0.5-0.5-0.5h-3c-0.276 0-0.5 0.224-0.5 0.5v5.5h-5.5c-0.276 0-0.5 0.224-0.5 0.5v3c0 0.276 0.224 0.5 0.5 0.5h5.5v5.5c0 0.276 0.224 0.5 0.5 0.5h3c0.276 0 0.5-0.224 0.5-0.5v-5.5h5.5c0.276 0 0.5-0.224 0.5-0.5v-3c0-0.276-0.224-0.5-0.5-0.5z"}}]})(t)}}}]);
//# sourceMappingURL=31664189-f79df42a6a9e05f8.js.map

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":3,"file":"static/chunks/70.0ba1ca12d54bca2d.js","mappings":"ACAA,aACA,CAACA,KAAK,gBAAmB,CAAGA,KAAK,gBAAmB,EAAI,EAAE,EAAEC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAEjE,KACC,SAASC,CAAuB,CAAEC,CAAmB,CAAEC,CAAmB,CAAE,CAEnFA,EAAoBC,CAAC,CAACF,GACDC,EAAoBE,CAAC,CAACH,EAAqB,CACzC,cAAiB,UAAW,CAAE,OAAqBI,CAAe,EAClE,YAAe,UAAW,CAAE,OAAqBC,CAAa,EAC9D,YAAe,UAAW,CAAE,OAAqBC,CAAa,CAChE,GACA,IAAIC,EAAqCN,EAAoB,MACzDO,EAA0DP,EAAoBQ,CAAC,CAACF,GAChFG,EAA0CT,EAAoB,MDTrF,SACAG,EAAgBO,CAAA,EAChB,IAAKC,EAAM,GAAAJ,CAAAA,GAAe,MACxB,IAAIK,KAAKF,EACXC,EAAAC,IAAA,mBAAAC,MAAA,CAAAD,EAAAE,IAAA,EAAAF,EAAAG,IAAA,EAED,OAAAJ,CAEM,CAAqD,eACpDN,EAAiBM,CAAA,CAAAG,CAAA,EAAc,IAAEE,EAAM,MAAAL,EAAAM,aAAA,EAAOC,KAAA,MACpD,GACD,GAAAT,EAAAU,MAAA,EAAAH,EAAAF,EAEM,CAAqD,SAC1DV,EAAAgB,CAAA,CAAAN,CAAA,EACD,GAAAL,EAAAU,MAAA,EAAAC,EAAAN,EAAA","sources":["webpack://_N_E/./src/exportUtils.ts","webpack://_N_E/<anon>"],"sourcesContent":["import JSZip from \"jszip\";\nimport { saveAs } from \"file-saver\";\n\nexport function createZipFile(\n files: Array<{ name: string; data: ArrayBuffer }>\n) {\n const zip = new JSZip();\n for (const file of files) {\n zip.file(`textures/skins/${file.name}`, file.data);\n }\n return zip;\n}\n\nexport async function saveZipFile(zip: JSZip, name: string) {\n const blob = await zip.generateAsync({ type: \"blob\" });\n saveAs(blob, name);\n}\n\nexport function savePngFile(imageUrl: string, name: string) {\n saveAs(imageUrl, name);\n}\n","\"use strict\";\n(self[\"webpackChunk_N_E\"] = self[\"webpackChunk_N_E\"] || []).push([[70],{\n\n/***/ 8070:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"createZipFile\": function() { return /* binding */ createZipFile; },\n/* harmony export */ \"savePngFile\": function() { return /* binding */ savePngFile; },\n/* harmony export */ \"saveZipFile\": function() { return /* binding */ saveZipFile; }\n/* harmony export */ });\n/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5733);\n/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var file_saver__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3162);\n/* harmony import */ var file_saver__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(file_saver__WEBPACK_IMPORTED_MODULE_1__);\n\n\nfunction createZipFile(files) {\n const zip = new (jszip__WEBPACK_IMPORTED_MODULE_0___default())();\n for (const file of files){\n zip.file(\"textures/skins/\".concat(file.name), file.data);\n }\n return zip;\n}\nasync function saveZipFile(zip, name) {\n const blob = await zip.generateAsync({\n type: \"blob\"\n });\n (0,file_saver__WEBPACK_IMPORTED_MODULE_1__.saveAs)(blob, name);\n}\nfunction savePngFile(imageUrl, name) {\n (0,file_saver__WEBPACK_IMPORTED_MODULE_1__.saveAs)(imageUrl, name);\n}\n\n\n/***/ })\n\n}]);"],"names":["self","push","__unused_webpack_module","__webpack_exports__","__webpack_require__","r","d","createZipFile","savePngFile","saveZipFile","jszip__WEBPACK_IMPORTED_MODULE_0__","jszip__WEBPACK_IMPORTED_MODULE_0___default","n","file_saver__WEBPACK_IMPORTED_MODULE_1__","files","zip","file","concat","name","data","blob","generateAsync","type","saveAs","imageUrl"],"sourceRoot":""}
{"version":3,"file":"static/chunks/70.0ba1ca12d54bca2d.js","mappings":"ACAA,aACA,CAACA,KAAK,gBAAmB,CAAGA,KAAK,gBAAmB,EAAI,EAAE,EAAEC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAEjE,KACC,SAASC,CAAuB,CAAEC,CAAmB,CAAEC,CAAmB,CAAE,CAEnFA,EAAoBC,CAAC,CAACF,GACDC,EAAoBE,CAAC,CAACH,EAAqB,CACzC,cAAiB,UAAW,CAAE,OAAqBI,CAAe,EAClE,YAAe,UAAW,CAAE,OAAqBC,CAAa,EAC9D,YAAe,UAAW,CAAE,OAAqBC,CAAa,CAChE,GACA,IAAIC,EAAqCN,EAAoB,MACzDO,EAA0DP,EAAoBQ,CAAC,CAACF,GAChFG,EAA0CT,EAAoB,MDTrF,SACAG,EAAgBO,CAAA,EAChB,IAAKC,EAAM,GAAAJ,CAAAA,GAAe,MACxB,IAAIK,KAAKF,EACXC,EAAAC,IAAA,mBAAAC,MAAA,CAAAD,EAAAE,IAAA,EAAAF,EAAAG,IAAA,EAED,OAAAJ,CAEM,CAAqD,eACpDN,EAAiBM,CAAA,CAAAG,CAAA,EAAc,IAAEE,EAAM,MAAAL,EAAAM,aAAA,EAAOC,KAAA,MACpD,GACD,GAAAT,EAAAU,MAAA,EAAAH,EAAAF,EAEM,CAAqD,SAC1DV,EAAAgB,CAAA,CAAAN,CAAA,EACD,GAAAL,EAAAU,MAAA,EAAAC,EAAAN,EAAA","sources":["webpack://_N_E/./src/exportUtils.ts","webpack://_N_E/<anon>"],"sourcesContent":["import JSZip from \"jszip\";\r\nimport { saveAs } from \"file-saver\";\r\n\r\nexport function createZipFile(\r\n files: Array<{ name: string; data: ArrayBuffer }>\r\n) {\r\n const zip = new JSZip();\r\n for (const file of files) {\r\n zip.file(`textures/skins/${file.name}`, file.data);\r\n }\r\n return zip;\r\n}\r\n\r\nexport async function saveZipFile(zip: JSZip, name: string) {\r\n const blob = await zip.generateAsync({ type: \"blob\" });\r\n saveAs(blob, name);\r\n}\r\n\r\nexport function savePngFile(imageUrl: string, name: string) {\r\n saveAs(imageUrl, name);\r\n}\r\n","\"use strict\";\n(self[\"webpackChunk_N_E\"] = self[\"webpackChunk_N_E\"] || []).push([[70],{\n\n/***/ 8070:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"createZipFile\": function() { return /* binding */ createZipFile; },\n/* harmony export */ \"savePngFile\": function() { return /* binding */ savePngFile; },\n/* harmony export */ \"saveZipFile\": function() { return /* binding */ saveZipFile; }\n/* harmony export */ });\n/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5733);\n/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var file_saver__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3162);\n/* harmony import */ var file_saver__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(file_saver__WEBPACK_IMPORTED_MODULE_1__);\n\n\nfunction createZipFile(files) {\n const zip = new (jszip__WEBPACK_IMPORTED_MODULE_0___default())();\n for (const file of files){\n zip.file(\"textures/skins/\".concat(file.name), file.data);\n }\n return zip;\n}\nasync function saveZipFile(zip, name) {\n const blob = await zip.generateAsync({\n type: \"blob\"\n });\n (0,file_saver__WEBPACK_IMPORTED_MODULE_1__.saveAs)(blob, name);\n}\nfunction savePngFile(imageUrl, name) {\n (0,file_saver__WEBPACK_IMPORTED_MODULE_1__.saveAs)(imageUrl, name);\n}\n\n\n/***/ })\n\n}]);"],"names":["self","push","__unused_webpack_module","__webpack_exports__","__webpack_require__","r","d","createZipFile","savePngFile","saveZipFile","jszip__WEBPACK_IMPORTED_MODULE_0__","jszip__WEBPACK_IMPORTED_MODULE_0___default","n","file_saver__WEBPACK_IMPORTED_MODULE_1__","files","zip","file","concat","name","data","blob","generateAsync","type","saveAs","imageUrl"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":3,"file":"static/chunks/pages/_app-72df527876dcf2c2.js","mappings":"AKACA,CAAAA,KAAK,gBAAmB,CAAGA,KAAK,gBAAmB,EAAI,EAAE,EAAEC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAElE,KACC,SAASC,CAAM,CAAEC,CAAwB,CAAEC,CAAmB,CAAE,CLH1BF,EAAAG,OAAA,CAAAD,EAAA,qBAAAE,CAAA,CAAAH,CAAA,CAAAC,CAAA,ECE7C,CAAAG,OAAAC,QAAA,CAAAD,OAAAC,QAAA,MAAAP,IAAA,EACA,QACA,UAAe,CACf,OAAAG,EAAA,KACA,EACA,CAKA,gBAAAE,CAAA,CAAAG,CAAA,CAAAL,CAAA,eAAAA,EAAAM,CAAA,CAAAD,GAAA,IAAAE,EAAAP,EAAA,MAAAQ,EAAAR,EAAAS,CAAA,CAAAF,GAAAP,EAAA,MAAAA,EAAA,KCRmBK,EAAA,QAAAG,GAAA,iBCJnB,kBCAA,YAAAR,CAAA,MAAAU,EAAA,SAAAC,CAAA,SAAAX,EAAAA,EAAAY,CAAA,CAAAD,EAAA,EAAAX,EAAAa,CAAA,+BAAAH,EAAA,MAAAA,EAAA,OAAAI,KAAAd,EAAAa,CAAA","sources":["webpack://_N_E/./node_modules/next/app.js","webpack://_N_E/?b089","webpack://_N_E/./src/pages/_app.ts","webpack://_N_E/./node_modules/rc-slider/assets/index.css","webpack://_N_E/./src/styles/global.css","webpack://_N_E/<anon>"],"sourcesContent":["module.exports = require('./dist/pages/_app')\n","\n (window.__NEXT_P = window.__NEXT_P || []).push([\n \"/_app\",\n function () {\n return require(\"private-next-pages/_app.ts\");\n }\n ]);\n if(module.hot) {\n module.hot.dispose(function () {\n window.__NEXT_P.push([\"/_app\"])\n });\n }\n ","import App from \"next/app\";\nimport \"../styles/global.css\";\nimport \"rc-slider/assets/index.css\";\n\nexport default App;\n","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","(self[\"webpackChunk_N_E\"] = self[\"webpackChunk_N_E\"] || []).push([[888],{\n\n/***/ 7544:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(4297)\n\n\n/***/ }),\n\n/***/ 6522:\n/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {\n\n\n (window.__NEXT_P = window.__NEXT_P || []).push([\n \"/_app\",\n function () {\n return __webpack_require__(2416);\n }\n ]);\n if(false) {}\n \n\n/***/ }),\n\n/***/ 2416:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var next_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7544);\n/* harmony import */ var next_app__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_app__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _styles_global_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2968);\n/* harmony import */ var _styles_global_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_styles_global_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(939);\n/* harmony import */ var rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2__);\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ((next_app__WEBPACK_IMPORTED_MODULE_0___default()));\n\n\n/***/ }),\n\n/***/ 939:\n/***/ (function() {\n\n// extracted by mini-css-extract-plugin\n\n/***/ }),\n\n/***/ 2968:\n/***/ (function() {\n\n// extracted by mini-css-extract-plugin\n\n/***/ })\n\n},\n/******/ function(__webpack_require__) { // webpackRuntimeModules\n/******/ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }\n/******/ __webpack_require__.O(0, [774,179], function() { return __webpack_exec__(6522), __webpack_exec__(880); });\n/******/ var __webpack_exports__ = __webpack_require__.O();\n/******/ _N_E = __webpack_exports__;\n/******/ }\n]);"],"names":["self","push","module","__unused_webpack_exports","__webpack_require__","exports","__unused_webpack_module","window","__NEXT_P","__webpack_exports__","r","next_app__WEBPACK_IMPORTED_MODULE_0__","next_app__WEBPACK_IMPORTED_MODULE_0___default","n","__webpack_exec__","moduleId","s","O","_N_E"],"sourceRoot":""}
{"version":3,"file":"static/chunks/pages/_app-72df527876dcf2c2.js","mappings":"AKACA,CAAAA,KAAK,gBAAmB,CAAGA,KAAK,gBAAmB,EAAI,EAAE,EAAEC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAElE,KACC,SAASC,CAAM,CAAEC,CAAwB,CAAEC,CAAmB,CAAE,CLH1BF,EAAAG,OAAA,CAAAD,EAAA,qBAAAE,CAAA,CAAAH,CAAA,CAAAC,CAAA,ECE7C,CAAAG,OAAAC,QAAA,CAAAD,OAAAC,QAAA,MAAAP,IAAA,EACA,QACA,UAAe,CACf,OAAAG,EAAA,KACA,EACA,CAKA,gBAAAE,CAAA,CAAAG,CAAA,CAAAL,CAAA,eAAAA,EAAAM,CAAA,CAAAD,GAAA,IAAAE,EAAAP,EAAA,MAAAQ,EAAAR,EAAAS,CAAA,CAAAF,GAAAP,EAAA,MAAAA,EAAA,KCRmBK,EAAA,QAAAG,GAAA,iBCJnB,kBCAA,YAAAR,CAAA,MAAAU,EAAA,SAAAC,CAAA,SAAAX,EAAAA,EAAAY,CAAA,CAAAD,EAAA,EAAAX,EAAAa,CAAA,+BAAAH,EAAA,MAAAA,EAAA,OAAAI,KAAAd,EAAAa,CAAA","sources":["webpack://_N_E/./node_modules/next/app.js","webpack://_N_E/?b089","webpack://_N_E/./src/pages/_app.ts","webpack://_N_E/./node_modules/rc-slider/assets/index.css","webpack://_N_E/./src/styles/global.css","webpack://_N_E/<anon>"],"sourcesContent":["module.exports = require('./dist/pages/_app')\n","\n (window.__NEXT_P = window.__NEXT_P || []).push([\n \"/_app\",\n function () {\n return require(\"private-next-pages/_app.ts\");\n }\n ]);\n if(module.hot) {\n module.hot.dispose(function () {\n window.__NEXT_P.push([\"/_app\"])\n });\n }\n ","import App from \"next/app\";\r\nimport \"../styles/global.css\";\r\nimport \"rc-slider/assets/index.css\";\r\n\r\nexport default App;\r\n","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","(self[\"webpackChunk_N_E\"] = self[\"webpackChunk_N_E\"] || []).push([[888],{\n\n/***/ 7544:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(4297)\n\n\n/***/ }),\n\n/***/ 6522:\n/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {\n\n\n (window.__NEXT_P = window.__NEXT_P || []).push([\n \"/_app\",\n function () {\n return __webpack_require__(2416);\n }\n ]);\n if(false) {}\n \n\n/***/ }),\n\n/***/ 2416:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var next_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7544);\n/* harmony import */ var next_app__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_app__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _styles_global_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2968);\n/* harmony import */ var _styles_global_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_styles_global_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(939);\n/* harmony import */ var rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(rc_slider_assets_index_css__WEBPACK_IMPORTED_MODULE_2__);\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ((next_app__WEBPACK_IMPORTED_MODULE_0___default()));\n\n\n/***/ }),\n\n/***/ 939:\n/***/ (function() {\n\n// extracted by mini-css-extract-plugin\n\n/***/ }),\n\n/***/ 2968:\n/***/ (function() {\n\n// extracted by mini-css-extract-plugin\n\n/***/ })\n\n},\n/******/ function(__webpack_require__) { // webpackRuntimeModules\n/******/ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }\n/******/ __webpack_require__.O(0, [774,179], function() { return __webpack_exec__(6522), __webpack_exec__(880); });\n/******/ var __webpack_exports__ = __webpack_require__.O();\n/******/ _N_E = __webpack_exports__;\n/******/ }\n]);"],"names":["self","push","module","__unused_webpack_exports","__webpack_require__","exports","__unused_webpack_module","window","__NEXT_P","__webpack_exports__","r","next_app__WEBPACK_IMPORTED_MODULE_0__","next_app__WEBPACK_IMPORTED_MODULE_0___default","n","__webpack_exec__","moduleId","s","O","_N_E"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +1,2 @@
!function(){"use strict";var e,t,n,r,o,u,i,c={},a={};function f(e){var t=a[e];if(void 0!==t)return t.exports;var n=a[e]={exports:{}},r=!0;try{c[e].call(n.exports,n,n.exports,f),r=!1}finally{r&&delete a[e]}return n.exports}f.m=c,e=[],f.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,a=0;a<n.length;a++)i>=o&&Object.keys(f.O).every(function(e){return f.O[e](n[a])})?n.splice(a--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var l=r();void 0!==l&&(t=l)}}return t},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,{a:t}),t},f.d=function(e,t){for(var n in t)f.o(t,n)&&!f.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},f.f={},f.e=function(e){return Promise.all(Object.keys(f.f).reduce(function(t,n){return f.f[n](e,t),t},[]))},f.u=function(e){return"static/chunks/"+(737===e?"fb7d5399":e)+"."+({70:"0ba1ca12d54bca2d",258:"53d25aa602c4d686",354:"3289d8281650c8de",737:"ddae1e8fed13bcfe",990:"ccb4bc1efe5cd94f"})[e]+".js"},f.miniCssF=function(e){return"static/css/43b5c0f72e817aaa.css"},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t={},n="_N_E:",f.l=function(e,r,o,u){if(t[e]){t[e].push(r);return}if(void 0!==o)for(var i,c,a=document.getElementsByTagName("script"),l=0;l<a.length;l++){var s=a[l];if(s.getAttribute("src")==e||s.getAttribute("data-webpack")==n+o){i=s;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,f.nc&&i.setAttribute("nonce",f.nc),i.setAttribute("data-webpack",n+o),i.src=f.tu(e)),t[e]=[r];var d=function(n,r){i.onerror=i.onload=null,clearTimeout(p);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(r)}),n)return n(r)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.tt=function(){return void 0===r&&(r={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(r=trustedTypes.createPolicy("nextjs#bundler",r))),r},f.tu=function(e){return f.tt().createScriptURL(e)},f.p="/t2-model-skinner/_next/",o={272:0},f.f.j=function(e,t){var n=f.o(o,e)?o[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(272!=e){var r=new Promise(function(t,r){n=o[e]=[t,r]});t.push(n[2]=r);var u=f.p+f.u(e),i=Error();f.l(u,function(t){if(f.o(o,e)&&(0!==(n=o[e])&&(o[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;i.message="Loading chunk "+e+" failed.\n("+r+": "+u+")",i.name="ChunkLoadError",i.type=r,i.request=u,n[1](i)}},"chunk-"+e,e)}else o[e]=0}},f.O.j=function(e){return 0===o[e]},u=function(e,t){var n,r,u=t[0],i=t[1],c=t[2],a=0;if(u.some(function(e){return 0!==o[e]})){for(n in i)f.o(i,n)&&(f.m[n]=i[n]);if(c)var l=c(f)}for(e&&e(t);a<u.length;a++)r=u[a],f.o(o,r)&&o[r]&&o[r][0](),o[r]=0;return f.O(l)},(i=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(u.bind(null,0)),i.push=u.bind(null,i.push.bind(i))}();
//# sourceMappingURL=webpack-fe0974dd0529d880.js.map
!function(){"use strict";var e,t,n,r,o,u,i,c={},a={};function f(e){var t=a[e];if(void 0!==t)return t.exports;var n=a[e]={exports:{}},r=!0;try{c[e].call(n.exports,n,n.exports,f),r=!1}finally{r&&delete a[e]}return n.exports}f.m=c,e=[],f.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,a=0;a<n.length;a++)i>=o&&Object.keys(f.O).every(function(e){return f.O[e](n[a])})?n.splice(a--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var l=r();void 0!==l&&(t=l)}}return t},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,{a:t}),t},f.d=function(e,t){for(var n in t)f.o(t,n)&&!f.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},f.f={},f.e=function(e){return Promise.all(Object.keys(f.f).reduce(function(t,n){return f.f[n](e,t),t},[]))},f.u=function(e){return"static/chunks/"+(737===e?"fb7d5399":e)+"."+({70:"0ba1ca12d54bca2d",258:"53d25aa602c4d686",354:"3289d8281650c8de",737:"ddae1e8fed13bcfe",990:"ccb4bc1efe5cd94f"})[e]+".js"},f.miniCssF=function(e){return"static/css/7d1c0438425db85d.css"},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t={},n="_N_E:",f.l=function(e,r,o,u){if(t[e]){t[e].push(r);return}if(void 0!==o)for(var i,c,a=document.getElementsByTagName("script"),l=0;l<a.length;l++){var s=a[l];if(s.getAttribute("src")==e||s.getAttribute("data-webpack")==n+o){i=s;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,f.nc&&i.setAttribute("nonce",f.nc),i.setAttribute("data-webpack",n+o),i.src=f.tu(e)),t[e]=[r];var d=function(n,r){i.onerror=i.onload=null,clearTimeout(p);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(r)}),n)return n(r)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.tt=function(){return void 0===r&&(r={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(r=trustedTypes.createPolicy("nextjs#bundler",r))),r},f.tu=function(e){return f.tt().createScriptURL(e)},f.p="/t2-model-skinner/_next/",o={272:0},f.f.j=function(e,t){var n=f.o(o,e)?o[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(272!=e){var r=new Promise(function(t,r){n=o[e]=[t,r]});t.push(n[2]=r);var u=f.p+f.u(e),i=Error();f.l(u,function(t){if(f.o(o,e)&&(0!==(n=o[e])&&(o[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;i.message="Loading chunk "+e+" failed.\n("+r+": "+u+")",i.name="ChunkLoadError",i.type=r,i.request=u,n[1](i)}},"chunk-"+e,e)}else o[e]=0}},f.O.j=function(e){return 0===o[e]},u=function(e,t){var n,r,u=t[0],i=t[1],c=t[2],a=0;if(u.some(function(e){return 0!==o[e]})){for(n in i)f.o(i,n)&&(f.m[n]=i[n]);if(c)var l=c(f)}for(e&&e(t);a<u.length;a++)r=u[a],f.o(o,r)&&o[r]&&o[r][0](),o[r]=0;return f.O(l)},(i=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(u.bind(null,0)),i.push=u.bind(null,i.push.bind(i))}();
//# sourceMappingURL=webpack-a09c3f76050eda6f.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

28
package-lock.json generated
View file

@ -39,7 +39,7 @@
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^20.0.3",
"typescript": "4.9.3"
"typescript": "5.1.3"
}
},
"node_modules/@babel/runtime": {
@ -513,9 +513,9 @@
"peer": true
},
"node_modules/@types/fabric": {
"version": "4.5.13",
"resolved": "https://registry.npmjs.org/@types/fabric/-/fabric-4.5.13.tgz",
"integrity": "sha512-+K2ce3hH1QfRlp5y8AialFl/rc7fkwzPQ9fK+fswPWTn3djkstCpm8Iou05NTZy3SxRA9dS7puSF+tjpo6ny7Q==",
"version": "4.5.15",
"resolved": "https://registry.npmjs.org/@types/fabric/-/fabric-4.5.15.tgz",
"integrity": "sha512-cjrHhi6R62rFtfqSopPoUEvnidhMngXBaDs6adrVIkY92o3bjWIIQ2InV0vaD262N/GurDrzJS2ih4TgY9gGAQ==",
"dev": true
},
"node_modules/@types/file-saver": {
@ -4114,16 +4114,16 @@
}
},
"node_modules/typescript": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
"integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
"node": ">=14.17"
}
},
"node_modules/unbox-primitive": {
@ -4746,9 +4746,9 @@
"peer": true
},
"@types/fabric": {
"version": "4.5.13",
"resolved": "https://registry.npmjs.org/@types/fabric/-/fabric-4.5.13.tgz",
"integrity": "sha512-+K2ce3hH1QfRlp5y8AialFl/rc7fkwzPQ9fK+fswPWTn3djkstCpm8Iou05NTZy3SxRA9dS7puSF+tjpo6ny7Q==",
"version": "4.5.15",
"resolved": "https://registry.npmjs.org/@types/fabric/-/fabric-4.5.15.tgz",
"integrity": "sha512-cjrHhi6R62rFtfqSopPoUEvnidhMngXBaDs6adrVIkY92o3bjWIIQ2InV0vaD262N/GurDrzJS2ih4TgY9gGAQ==",
"dev": true
},
"@types/file-saver": {
@ -7381,9 +7381,9 @@
"dev": true
},
"typescript": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
"integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
"dev": true
},
"unbox-primitive": {

View file

@ -41,6 +41,6 @@
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^20.0.3",
"typescript": "4.9.3"
"typescript": "5.1.3"
}
}

View file

@ -8,7 +8,7 @@ import { FaTrashAlt, FaLock, FaUnlock } from "react-icons/fa";
import { GoArrowUp, GoArrowDown } from "react-icons/go";
import { GiArrowCursor } from "react-icons/gi";
import { IoMdBrush } from "react-icons/io";
import { ImPlus, ImUndo2, ImRedo2 } from "react-icons/im";
import { ImPlus, ImUndo2, ImRedo2, ImContrast } from "react-icons/im";
export default function CanvasTools() {
const nameInputRef = useRef<HTMLInputElement | null>(null);
@ -34,6 +34,12 @@ export default function CanvasTools() {
setBrushColor,
brushSize,
setBrushSize,
hueRotate,
setHueRotate,
saturation,
setSaturation,
brightness,
setBrightness,
activeCanvasType,
addImages,
exportSkin,
@ -50,6 +56,7 @@ export default function CanvasTools() {
const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
const [arrowElement, setArrowElement] = useState<HTMLElement | null>(null);
const [isBrushToolsOpen, setBrushToolsOpen] = useState(false);
const [isFilterToolsOpen, setFilterToolsOpen] = useState(false);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
modifiers: [
{ name: "arrow", options: { element: arrowElement } },
@ -62,6 +69,10 @@ export default function CanvasTools() {
],
});
if (isFilterToolsOpen && !selectedObjects.length) {
setFilterToolsOpen(false);
}
const isSelectionLocked = selectedObjects.length
? selectedObjects.every((object) => lockedObjects.has(object))
: false;
@ -163,6 +174,178 @@ export default function CanvasTools() {
>
<ImPlus style={{ fontSize: 14 }} />
</button>
<button
type="button"
ref={setReferenceElement}
data-active={isFilterToolsOpen ? "" : undefined}
disabled={!selectedObjects.length}
aria-label="Filters"
title="Filters"
onClick={() => {
setFilterToolsOpen((isOpen) => !isOpen);
}}
>
<ImContrast />
</button>
{isFilterToolsOpen ? (
<div
className="BrushToolsPopup"
ref={setPopperElement}
style={styles.popper}
tabIndex={-1}
onBlur={(event) => {
const newFocusElement = event.relatedTarget;
const isFocusLeaving =
!newFocusElement ||
!event.currentTarget.contains(newFocusElement);
if (isFocusLeaving) {
setFilterToolsOpen(false);
}
}}
{...attributes.popper}
>
<div className="Fields">
<div className="Field">
<label>
Hue:{" "}
<strong>
{hueRotate == null ? (
"MULTIPLE VALUES"
) : (
<>{Math.round(hueRotate * 180)}&deg;</>
)}
</strong>
</label>
<div className="SliderContainer">
<Slider
min={-180}
max={180}
startPoint={0}
value={Math.round((hueRotate ?? 0) * 180)}
onChange={(value) => {
if (Array.isArray(value)) {
value = value[0];
}
setHueRotate(value / 180);
}}
trackStyle={{
height: 8,
background: "#03fccf",
}}
handleStyle={{
width: 20,
height: 20,
marginTop: -6,
borderColor: "#03fccf",
background: "rgb(5, 69, 76)",
// background: `rgb(${brushColor}, ${brushColor}, ${brushColor})`,
opacity: 1,
}}
railStyle={{
height: 8,
border: "1px solid #555",
background: "rgba(255, 255, 255, 0.3)",
}}
/>
</div>
</div>
<div className="Field">
<label>
Saturation:{" "}
<strong>
{saturation == null
? "MULTIPLE VALUES"
: `${Math.round(saturation * 100 + 100)}%`}
</strong>
</label>
<div className="SliderContainer">
<Slider
min={-100}
max={100}
startPoint={0}
value={Math.round((saturation ?? 0) * 100)}
onChange={(value) => {
if (Array.isArray(value)) {
value = value[0];
}
setSaturation(value / 100);
}}
trackStyle={{
height: 8,
background: "#03fccf",
}}
handleStyle={{
width: 20,
height: 20,
marginTop: -6,
borderColor: "#03fccf",
background: "rgb(5, 69, 76)",
// background: `rgb(${brushColor}, ${brushColor}, ${brushColor})`,
opacity: 1,
}}
railStyle={{
height: 8,
border: "1px solid #555",
background: "rgba(255, 255, 255, 0.3)",
}}
/>
</div>
</div>
<div className="Field">
<label>
Brightness:{" "}
<strong>
{brightness == null
? "MULTIPLE VALUES"
: `${Math.round(brightness * 100 + 100)}%`}
</strong>
</label>
<div className="SliderContainer">
<Slider
min={-100}
max={100}
startPoint={0}
value={Math.round((brightness ?? 0) * 100)}
onChange={(value) => {
if (Array.isArray(value)) {
value = value[0];
}
setBrightness(value / 100);
}}
trackStyle={{
height: 8,
background: "#03fccf",
}}
handleStyle={{
width: 20,
height: 20,
marginTop: -6,
borderColor: "#03fccf",
background: "rgb(5, 69, 76)",
// background: `rgb(${brushColor}, ${brushColor}, ${brushColor})`,
opacity: 1,
}}
railStyle={{
height: 8,
border: "1px solid #555",
background: "rgba(255, 255, 255, 0.3)",
}}
/>
</div>
</div>
</div>
<div
className="PopupArrow"
ref={setArrowElement}
style={styles.arrow}
/>
</div>
) : null}
<button
type="button"
aria-label={isSelectionLocked ? "Unlock" : "Lock"}

View file

@ -36,6 +36,12 @@ function isActiveSelection(
return object.type === "activeSelection";
}
type ObjectFilters = {
HueRotation?: number;
Saturation?: number;
Brightness?: number;
};
export default function ToolsProvider({ children }: { children: ReactNode }) {
const { actualModel, selectedModelType } = useWarrior();
const [selectedMaterialIndex, setSelectedMaterialIndex] = useState(0);
@ -63,6 +69,9 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
);
const [brushColor, setBrushColor] = useState(200);
const [brushSize, setBrushSize] = useState(10);
const [filterMap, setFilterMap] = useState(
() => new Map<fabric.Object, ObjectFilters>()
);
const [selectedObjects, setSelectedObjects] = useState<fabric.Object[]>(
() => []
);
@ -78,6 +87,111 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
const [isDrawingMode, setDrawingMode] = useState(false);
const { combineColorAndAlphaImageUrls } = useImageWorker();
const { canvasPadding } = useSettings();
const [filterChanges, setFilterChanges] = useState<
Array<[fabric.Object, ObjectFilters]>
>(() => []);
const getFilter = (name: keyof ObjectFilters) => {
if (selectedObjects.length) {
const getValue = (i: number) =>
(filterMap.get(selectedObjects[i]) ?? {})[name] ?? 0;
const firstValue = getValue(0);
if (
selectedObjects
.slice(1)
.every((selectedObject, i) => getValue(i + 1) === firstValue)
) {
return firstValue;
}
return null;
} else {
return 0;
}
};
const hueRotate = getFilter("HueRotation");
const saturation = getFilter("Saturation");
const brightness = getFilter("Brightness");
const setFilter = useCallback(
(name: keyof ObjectFilters, value: number) => {
if (!selectedObjects.length) {
setFilterChanges([]);
return;
}
const filterChanges: Array<[fabric.Object, ObjectFilters]> = [];
const newFilterMap = new Map(filterMap);
for (const selectedObject of selectedObjects) {
const existingFilters = filterMap.get(selectedObject) ?? {};
const newFilters = { ...existingFilters, [name]: value };
newFilterMap.set(selectedObject, newFilters);
filterChanges.push([selectedObject, newFilters]);
}
setFilterMap(newFilterMap);
setFilterChanges(filterChanges);
},
[filterMap, selectedObjects]
);
const setHueRotate = useCallback(
(value: number) => setFilter("HueRotation", value),
[setFilter]
);
const setSaturation = useCallback(
(value: number) => setFilter("Saturation", value),
[setFilter]
);
const setBrightness = useCallback(
(value: number) => setFilter("Brightness", value),
[setFilter]
);
useEffect(() => {
if (!filterChanges.length) {
return;
}
for (const [selectedObject, newFilters] of filterChanges) {
if (selectedObject instanceof fabric.Image) {
selectedObject.filters = [];
for (const key in newFilters) {
const filterValue = newFilters[key as keyof ObjectFilters] ?? 0;
if (filterValue !== 0) {
switch (key) {
case "HueRotation":
selectedObject.filters.push(
// @ts-expect-error @types/fabric does not include HueRotation.
new fabric.Image.filters.HueRotation({
rotation: filterValue,
})
);
break;
case "Saturation":
selectedObject.filters.push(
new fabric.Image.filters.Saturation({
saturation: filterValue,
})
);
break;
case "Brightness":
selectedObject.filters.push(
new fabric.Image.filters.Brightness({
brightness: filterValue,
})
);
break;
}
}
}
selectedObject.applyFilters();
}
}
setFilterChanges([]);
if (notifyChange) {
notifyChange();
}
}, [filterChanges, notifyChange]);
const lockSelection = useCallback(() => {
if (selectedObjects.length) {
@ -314,6 +428,12 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
setBrushColor,
brushSize,
setBrushSize,
hueRotate,
setHueRotate,
saturation,
setSaturation,
brightness,
setBrightness,
selectedObjects,
lockSelection,
unlockSelection,
@ -341,6 +461,12 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
lockedObjects,
brushColor,
brushSize,
hueRotate,
saturation,
brightness,
setHueRotate,
setSaturation,
setBrightness,
selectedObjects,
lockSelection,
unlockSelection,
@ -370,6 +496,8 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
canvas.on("selection:updated", handleSelectionUpdated);
canvas.on("selection:created", handleSelectionUpdated);
handleSelectionUpdated();
return () => {
canvas.off("selection:cleared", handleSelectionUpdated);
canvas.off("selection:updated", handleSelectionUpdated);

View file

@ -311,6 +311,11 @@ select {
gap: 10px;
}
.Field label strong {
margin-left: 4px;
color: #d0ffee;
}
@media only screen and (max-width: 899px) {
main {
flex-direction: column;

View file

@ -10,6 +10,12 @@ interface ToolsContextValue {
setBrushSize: (brushSize: number) => void;
brushColor: number;
setBrushColor: (brushColor: number) => void;
hueRotate: number | null;
setHueRotate: (hueRotate: number) => void;
saturation: number | null;
setSaturation: (saturation: number) => void;
brightness: number | null;
setBrightness: (brightness: number) => void;
deleteSelection: () => void;
undo: () => void;
redo: () => void;