feat: allows node icon to be changed

This commit is contained in:
Mark Mankarious
2023-07-12 12:16:52 +01:00
parent 5cc71d762d
commit fd88787eb1
23 changed files with 876 additions and 162 deletions

555
package-lock.json generated
View File

@@ -22,6 +22,7 @@
"mobx-react": "^7.6.0",
"paper": "^0.12.17",
"react-hook-form": "^7.43.2",
"react-quill": "^2.0.0",
"react-router-dom": "^6.8.1",
"zod": "^3.20.6",
"zustand": "^4.3.3"
@@ -39,6 +40,7 @@
"@types/react-dom": "^18.0.11",
"@types/webpack-env": "^1.18.0",
"concurrently": "^7.6.0",
"css-loader": "^6.8.1",
"html-webpack-plugin": "^5.5.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
@@ -46,6 +48,7 @@
"nodemon": "^2.0.22",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"style-loader": "^3.3.3",
"ts-jest": "^29.0.5",
"ts-loader": "^9.4.2",
"typescript": "^4.9.5",
@@ -2502,6 +2505,14 @@
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
},
"node_modules/@types/quill": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
"dependencies": {
"parchment": "^1.1.2"
}
},
"node_modules/@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
@@ -3453,7 +3464,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
@@ -3615,6 +3625,14 @@
"node": ">=12"
}
},
"node_modules/clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
"engines": {
"node": ">=0.8"
}
},
"node_modules/clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -3947,6 +3965,32 @@
"node": ">= 8"
}
},
"node_modules/css-loader": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
"integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==",
"dev": true,
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.21",
"postcss-modules-extract-imports": "^3.0.0",
"postcss-modules-local-by-default": "^4.0.3",
"postcss-modules-scope": "^3.0.0",
"postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.2.0",
"semver": "^7.3.8"
},
"engines": {
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.0.0"
}
},
"node_modules/css-select": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
@@ -3981,6 +4025,18 @@
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
"dev": true
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"bin": {
"cssesc": "bin/cssesc"
},
"engines": {
"node": ">=4"
}
},
"node_modules/cssom": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
@@ -4139,7 +4195,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
"integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
"dev": true,
"dependencies": {
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
@@ -4814,12 +4869,22 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/fast-diff": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -5021,7 +5086,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -5048,7 +5112,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@@ -5187,7 +5250,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.1.1"
},
@@ -5199,7 +5261,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -5211,7 +5272,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
@@ -5511,6 +5571,18 @@
"node": ">=0.10.0"
}
},
"node_modules/icss-utils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true,
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
@@ -5640,7 +5712,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -5738,7 +5809,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -5870,7 +5940,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -8388,8 +8457,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
@@ -8674,6 +8742,24 @@
"multicast-dns": "cli.js"
}
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -8847,7 +8933,6 @@
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
@@ -8863,7 +8948,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -9038,6 +9122,11 @@
"tslib": "^2.0.3"
}
},
"node_modules/parchment": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -9182,6 +9271,112 @@
"node": ">=8"
}
},
"node_modules/postcss": {
"version": "8.4.25",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-modules-extract-imports": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true,
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-local-by-default": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz",
"integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==",
"dev": true,
"dependencies": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^6.0.2",
"postcss-value-parser": "^4.1.0"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-scope": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
"integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
"dev": true,
"dependencies": {
"postcss-selector-parser": "^6.0.4"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-values": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
"dev": true,
"dependencies": {
"icss-utils": "^5.0.0"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-selector-parser": {
"version": "6.0.13",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
"dev": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
},
"engines": {
"node": ">=4"
}
},
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -9341,6 +9536,69 @@
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true
},
"node_modules/quill": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
"dependencies": {
"clone": "^2.1.1",
"deep-equal": "^1.0.1",
"eventemitter3": "^2.0.3",
"extend": "^3.0.2",
"parchment": "^1.1.4",
"quill-delta": "^3.6.2"
}
},
"node_modules/quill-delta": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
"dependencies": {
"deep-equal": "^1.0.1",
"extend": "^3.0.2",
"fast-diff": "1.1.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/quill-delta/node_modules/deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"dependencies": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/quill/node_modules/deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"dependencies": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/quill/node_modules/eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -9439,6 +9697,20 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"node_modules/react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
"dependencies": {
"@types/quill": "^1.3.10",
"lodash": "^4.17.4",
"quill": "^1.3.7"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18",
"react-dom": "^16 || ^17 || ^18"
}
},
"node_modules/react-router": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
@@ -9544,7 +9816,6 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
@@ -10056,6 +10327,15 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
@@ -10240,6 +10520,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/style-loader": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz",
"integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==",
"dev": true,
"engines": {
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.0.0"
}
},
"node_modules/stylis": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",
@@ -13344,6 +13640,14 @@
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
},
"@types/quill": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
"requires": {
"parchment": "^1.1.2"
}
},
"@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
@@ -14126,7 +14430,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
@@ -14234,6 +14537,11 @@
"wrap-ansi": "^7.0.0"
}
},
"clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="
},
"clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -14495,6 +14803,22 @@
"which": "^2.0.1"
}
},
"css-loader": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
"integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==",
"dev": true,
"requires": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.21",
"postcss-modules-extract-imports": "^3.0.0",
"postcss-modules-local-by-default": "^4.0.3",
"postcss-modules-scope": "^3.0.0",
"postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.2.0",
"semver": "^7.3.8"
}
},
"css-select": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
@@ -14520,6 +14844,12 @@
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
"dev": true
},
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"cssom": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
@@ -14644,7 +14974,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
"integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
"dev": true,
"requires": {
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
@@ -15157,12 +15486,22 @@
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-diff": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -15320,8 +15659,7 @@
"functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
},
"gensync": {
"version": "1.0.0-beta.2",
@@ -15339,7 +15677,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@@ -15442,7 +15779,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
"dev": true,
"requires": {
"get-intrinsic": "^1.1.1"
}
@@ -15450,14 +15786,12 @@
"has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
"has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
"requires": {
"has-symbols": "^1.0.2"
}
@@ -15695,6 +16029,13 @@
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"icss-utils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true,
"requires": {}
},
"ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
@@ -15789,7 +16130,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -15857,7 +16197,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"requires": {
"has-tostringtag": "^1.0.0"
}
@@ -15941,7 +16280,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -17818,8 +18156,7 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.memoize": {
"version": "4.1.2",
@@ -18017,6 +18354,12 @@
"thunky": "^1.0.2"
}
},
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -18152,7 +18495,6 @@
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
@@ -18161,8 +18503,7 @@
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"object.assign": {
"version": "4.1.4",
@@ -18289,6 +18630,11 @@
"tslib": "^2.0.3"
}
},
"parchment": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
},
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -18394,6 +18740,69 @@
"find-up": "^4.0.0"
}
},
"postcss": {
"version": "8.4.25",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
},
"postcss-modules-extract-imports": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true,
"requires": {}
},
"postcss-modules-local-by-default": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz",
"integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==",
"dev": true,
"requires": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^6.0.2",
"postcss-value-parser": "^4.1.0"
}
},
"postcss-modules-scope": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
"integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
"dev": true,
"requires": {
"postcss-selector-parser": "^6.0.4"
}
},
"postcss-modules-values": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
"dev": true,
"requires": {
"icss-utils": "^5.0.0"
}
},
"postcss-selector-parser": {
"version": "6.0.13",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
"dev": true,
"requires": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
}
},
"postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -18519,6 +18928,64 @@
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true
},
"quill": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
"requires": {
"clone": "^2.1.1",
"deep-equal": "^1.0.1",
"eventemitter3": "^2.0.3",
"extend": "^3.0.2",
"parchment": "^1.1.4",
"quill-delta": "^3.6.2"
},
"dependencies": {
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"requires": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
}
},
"eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
}
}
},
"quill-delta": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
"requires": {
"deep-equal": "^1.0.1",
"extend": "^3.0.2",
"fast-diff": "1.1.2"
},
"dependencies": {
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"requires": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
}
}
}
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -18592,6 +19059,16 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
"requires": {
"@types/quill": "^1.3.10",
"lodash": "^4.17.4",
"quill": "^1.3.7"
}
},
"react-router": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
@@ -18668,7 +19145,6 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
"dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
@@ -19071,6 +19547,12 @@
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
@@ -19218,6 +19700,13 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
"style-loader": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz",
"integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==",
"dev": true,
"requires": {}
},
"stylis": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",

View File

@@ -29,6 +29,7 @@
"@types/react-dom": "^18.0.11",
"@types/webpack-env": "^1.18.0",
"concurrently": "^7.6.0",
"css-loader": "^6.8.1",
"html-webpack-plugin": "^5.5.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
@@ -36,6 +37,7 @@
"nodemon": "^2.0.22",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"style-loader": "^3.3.3",
"ts-jest": "^29.0.5",
"ts-loader": "^9.4.2",
"typescript": "^4.9.5",
@@ -57,6 +59,7 @@
"mobx-react": "^7.6.0",
"paper": "^0.12.17",
"react-hook-form": "^7.43.2",
"react-quill": "^2.0.0",
"react-router-dom": "^6.8.1",
"zod": "^3.20.6",
"zustand": "^4.3.3"

View File

@@ -12,6 +12,7 @@ import { SceneI } from "./validation/SceneSchema";
import { ModeManagerProvider } from "./contexts/ModeManagerContext";
import { useGlobalState } from "./hooks/useGlobalState";
import { OnSceneChange } from "./types";
import { GlobalStyles } from "./GlobalStyles";
interface Props {
initialScene: SceneI;
@@ -24,6 +25,7 @@ const InnerApp = React.memo(
({ height, width }: Pick<Props, "height" | "width">) => {
return (
<ThemeProvider theme={theme}>
<GlobalStyles />
<ModeManagerProvider>
<Box
sx={{

7
src/GlobalStyles.tsx Normal file
View File

@@ -0,0 +1,7 @@
import React from "react";
import { GlobalStyles as MUIGlobalStyles } from "@mui/material";
import "react-quill/dist/quill.snow.css";
export const GlobalStyles = () => {
return <MUIGlobalStyles styles={{}} />;
};

View File

@@ -0,0 +1,41 @@
import React from "react";
import ReactQuill from "react-quill";
import { Box } from "@mui/material";
interface Props {
value: string;
onChange: (value: string) => void;
}
const style = {
".ql-toolbar.ql-snow": {
border: "none",
pt: 0,
px: 0,
},
".ql-toolbar.ql-snow + .ql-container.ql-snow": {
border: "1px solid",
borderColor: "grey.800",
borderTop: "auto",
borderRadius: 1.5,
height: 200,
},
};
const tools = ["bold", "italic", "underline", "strike", "bullet", "link"];
export const MarkdownEditor = ({ value, onChange }: Props) => {
return (
<Box sx={style}>
<ReactQuill
theme="snow"
value={value}
onChange={onChange}
formats={tools}
modules={{
toolbar: tools,
}}
/>
</Box>
);
};

View File

@@ -1,34 +1,89 @@
import React, { useRef, useEffect, useContext } from "react";
import React, { useRef, useEffect, useContext, useMemo } from "react";
import { observer } from "mobx-react";
import { Box } from "@mui/material";
import { useGlobalState } from "../hooks/useGlobalState";
import { modeManagerContext } from "../contexts/ModeManagerContext";
import { Select } from "../modes/Select";
import { Renderer } from "../renderer/Renderer";
import { Coords } from "../renderer/elements/Coords";
import {
PROJECTED_TILE_WIDTH,
PROJECTED_TILE_HEIGHT,
} from "../renderer/constants";
const UI_OVERLAY_MARGIN = 300;
export const RendererContainer = observer(() => {
const modeManager = useContext(modeManagerContext);
const rendererEl = useRef<HTMLDivElement>(null);
const setRenderer = useGlobalState((state) => state.setRenderer);
const containerRef = useRef<HTMLDivElement>(null);
const onSceneChange = useGlobalState((state) => state.onSceneChange);
const initialScene = useGlobalState((state) => state.initialScene);
const onRendererEvent = useGlobalState((state) => state.onRendererEvent);
const setRenderer = useGlobalState((state) => state.setRenderer);
const renderer = useGlobalState((state) => state.renderer);
useEffect(() => {
if (!rendererEl.current) return;
if (!containerRef.current) return;
const renderer = setRenderer(rendererEl.current);
modeManager.setRenderer(renderer);
modeManager.setEventEmitter(renderer.callbacks.emitEvent);
if (renderer) renderer.destroy();
const _renderer = new Renderer(containerRef.current);
_renderer.setEventHandler(onRendererEvent);
modeManager.setRenderer(_renderer);
_renderer.loadScene(initialScene);
modeManager.setEventEmitter(_renderer.callbacks.emitEvent);
modeManager.activateMode(Select);
}, [setRenderer, modeManager, onSceneChange]);
setRenderer(_renderer);
return () => {
_renderer.destroy();
};
}, [modeManager, onSceneChange, onRendererEvent, initialScene]);
const uiOverlayPosition = useMemo(() => {
return {
size: new Coords(
renderer.sceneElements.grid.size.x * PROJECTED_TILE_WIDTH +
UI_OVERLAY_MARGIN * 2,
renderer.sceneElements.grid.size.y * PROJECTED_TILE_HEIGHT +
UI_OVERLAY_MARGIN * 2
),
};
}, [
{ ...renderer.scroll.position },
renderer.zoom,
{ ...renderer.sceneElements.grid.size },
]);
return (
<div
ref={rendererEl}
style={{
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
}}
/>
>
<Box
ref={containerRef}
sx={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
}}
/>
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
width: "1px",
height: "1px",
}}
/>
</Box>
);
});

View File

@@ -7,18 +7,14 @@ import SettingsIcon from "@mui/icons-material/Settings";
import { useGlobalState } from "../../hooks/useGlobalState";
const menuItems = [
{ name: "Icons", Icon: AddIcon },
{ name: "Project settings", Icon: SettingsIcon },
{ type: "SINGLE_NODE", name: "Icons", Icon: AddIcon },
{ type: "PROJECT_SETTINGS", name: "Project settings", Icon: SettingsIcon },
];
export const SideNav = () => {
const theme = useTheme();
const selectedSideNavItem = useGlobalState(
(state) => state.selectedSideNavItem
);
const setSelectedSideNavItem = useGlobalState(
(state) => state.setSelectedSideNavItem
);
const sidebarState = useGlobalState((state) => state.sidebarState);
const setSidebarState = useGlobalState((state) => state.setSidebarState);
return (
<Box
@@ -31,16 +27,16 @@ export const SideNav = () => {
bgcolor: "grey.900",
}}
>
{menuItems.map((item, index) => (
{/* {menuItems.map((item, index) => (
<MenuItem
key={item.name}
isActive={index === selectedSideNavItem}
onClick={() => setSelectedSideNavItem(index)}
isActive={item.type === sidebarState?.type}
onClick={() => setSidebarState(index)}
size={theme.customVars.sideNav.width}
tooltipPosition="right"
{...item}
/>
))}
))} */}
</Box>
);
};

View File

@@ -12,7 +12,7 @@ interface Props {
export const Section = ({ children, py, px, title }: Props) => {
return (
<Box py={py ?? 3} px={px ?? 4}>
<Box py={py ?? 3} px={px ?? 2}>
<Stack>
{title && <Typography fontWeight={600}>{title}</Typography>}
{children}

View File

@@ -1,25 +0,0 @@
import React from "react";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { IconI } from "../../../validation/SceneSchema";
interface Props {
icon: IconI;
}
export const Icon = ({ icon }: Props) => {
return (
<Stack justifyContent="center" alignItems="center" sx={{ height: "100%" }}>
<Box
component="img"
src={icon.url}
alt={`Icon ${icon.name}`}
sx={{ width: "100%", height: 80 }}
/>
<Typography variant="body2" color="text.secondary">
{icon.name}
</Typography>
</Stack>
);
};

View File

@@ -0,0 +1,32 @@
import React from "react";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import { Button, Typography } from "@mui/material";
import { IconI } from "../../../../validation/SceneSchema";
interface Props {
icon: IconI;
onClick: () => void;
}
export const Icon = ({ icon, onClick }: Props) => {
return (
<Button variant="text" onClick={onClick}>
<Stack
justifyContent="center"
alignItems="center"
sx={{ height: "100%" }}
>
<Box
component="img"
src={icon.url}
alt={`Icon ${icon.name}`}
sx={{ width: "100%", height: 80 }}
/>
<Typography variant="body2" color="text.secondary">
{icon.name}
</Typography>
</Stack>
</Button>
);
};

View File

@@ -1,21 +1,22 @@
import React from "react";
import Grid from "@mui/material/Grid";
import { IconI } from "../../../validation/SceneSchema";
import { IconI } from "../../../../validation/SceneSchema";
import { Icon } from "./Icon";
import { Section } from "../../Sidebar/Section";
import { Section } from "../../../Sidebar/Section";
interface Props {
name?: string;
icons: IconI[];
onClick: (icon: IconI) => void;
}
export const IconCategory = ({ name, icons }: Props) => {
export const IconCategory = ({ name, icons, onClick }: Props) => {
return (
<Section title={name}>
<Grid container spacing={2}>
{icons.map((icon) => (
<Grid item xs={3} key={icon.id}>
<Icon icon={icon} />
<Icon icon={icon} onClick={() => onClick(icon)} />
</Grid>
))}
</Grid>

View File

@@ -2,16 +2,14 @@ import React from "react";
import { useMemo } from "react";
import Grid from "@mui/material/Grid";
import { IconCategory } from "./IconCategory";
import { IconI } from "../../../validation/SceneSchema";
import { Sidebar } from "../../Sidebar";
import { Header } from "../../Sidebar/Header";
import { IconI } from "../../../../validation/SceneSchema";
interface Props {
icons: IconI[];
onClose: () => void;
onClick: (icon: IconI) => void;
}
export const Icons = ({ icons, onClose }: Props) => {
export const Icons = ({ icons, onClick }: Props) => {
const categorisedIcons = useMemo(() => {
const _categories: { name?: string; icons: IconI[] }[] = [];
@@ -39,14 +37,12 @@ export const Icons = ({ icons, onClose }: Props) => {
}, [icons]);
return (
<Sidebar header={<Header title="Icons" onClose={onClose} />}>
<Grid container spacing={4}>
{categorisedIcons.map((cat) => (
<Grid item xs={12} key={`icon-category-${cat.name}`}>
<IconCategory {...cat} />
</Grid>
))}
</Grid>
</Sidebar>
<Grid container spacing={4}>
{categorisedIcons.map((cat) => (
<Grid item xs={12} key={`icon-category-${cat.name}`}>
<IconCategory {...cat} onClick={onClick} />
</Grid>
))}
</Grid>
);
};

View File

@@ -0,0 +1,18 @@
import React, { useState } from "react";
import { Node } from "../../../renderer/elements/Node";
import { MarkdownEditor } from "../../MarkdownEditor";
import { Section } from "../../Sidebar/Section";
interface Props {
node: Node;
}
export const NodeSettings = ({ node }: Props) => {
const [label, setLabel] = useState("");
return (
<Section>
<MarkdownEditor value={label} onChange={setLabel} />
</Section>
);
};

View File

@@ -0,0 +1,47 @@
import React, { useState, useCallback } from "react";
import { Sidebar } from "../../Sidebar";
import { Icons } from "./Icons";
import { Header } from "../../Sidebar/Header";
import { Node } from "../../../renderer/elements/Node";
import { Tabs, Tab, Box } from "@mui/material";
import { useGlobalState } from "../../../hooks/useGlobalState";
import { IconI } from "../../../validation/SceneSchema";
import { NodeSettings } from "./NodeSettings";
interface Props {
node: Node;
onClose: () => void;
}
export const NodeSidebar = ({ node, onClose }: Props) => {
const [tab, setTab] = useState(0);
const icons = useGlobalState((state) => state.initialScene.icons);
const onTabChanged = (event: React.SyntheticEvent, newValue: number) => {
setTab(newValue);
};
const onIconChanged = useCallback(
(icon: IconI) => {
node.update({ iconId: icon.id });
},
[node]
);
return (
<Sidebar
header={
<Box>
<Header title="Node" onClose={onClose} />{" "}
<Tabs value={tab} onChange={onTabChanged}>
<Tab label="Settings" />
<Tab label="Icons" />
</Tabs>
</Box>
}
>
{tab === 0 && <NodeSettings node={node} />}
{tab === 1 && <Icons icons={icons} onClick={onIconChanged} />}
</Sidebar>
);
};

View File

@@ -1,24 +1,37 @@
import React from "react";
import React, { useMemo, useCallback } from "react";
import { useTheme } from "@mui/material";
import Card from "@mui/material/Card";
import Slide from "@mui/material/Slide";
import { Icons } from "./Icons";
import { Transition } from "./Transition";
import { NodeSidebar } from "./NodeSidebar";
import { ProjectSettings } from "./ProjectSettings";
import { useGlobalState } from "../../hooks/useGlobalState";
export const Sidebar = () => {
const theme = useTheme();
const selectedSideNavItem = useGlobalState(
(state) => state.selectedSideNavItem
);
const closeSideNav = useGlobalState((state) => state.closeSideNav);
const icons = useGlobalState((state) => state.renderer.config.icons);
const sidebarState = useGlobalState((state) => state.sidebarState);
const closeSidebar = useGlobalState((state) => state.closeSidebar);
const closeContextMenu = useGlobalState((state) => state.closeContextMenu);
const onClose = useCallback(() => {
closeSidebar();
closeContextMenu();
}, [closeSidebar, closeContextMenu]);
const Component = useMemo(() => {
switch (sidebarState?.type) {
case "SINGLE_NODE":
return <NodeSidebar node={sidebarState.node} onClose={onClose} />;
case "PROJECT_SETTINGS":
return <ProjectSettings onClose={onClose} />;
default:
return null;
}
}, [sidebarState]);
return (
<Slide
direction="right"
in={selectedSideNavItem !== null}
in={sidebarState !== null}
mountOnEnter
unmountOnExit
>
@@ -32,12 +45,7 @@ export const Sidebar = () => {
borderRadius: 0,
}}
>
<Transition isIn={selectedSideNavItem === 0}>
<Icons icons={icons} onClose={closeSideNav} />
</Transition>
<Transition isIn={selectedSideNavItem === 1}>
<ProjectSettings onClose={closeSideNav} />
</Transition>
{Component}
</Card>
</Slide>
);

View File

@@ -5,26 +5,36 @@ import { Coords } from "../renderer/elements/Coords";
import { Renderer } from "../renderer/Renderer";
import { OnSceneChange, SceneEventI } from "../types";
type SidebarState =
| {
type: "SINGLE_NODE";
node: Node;
}
| {
type: "PROJECT_SETTINGS";
};
interface GlobalState {
showContextMenuFor: Node | Coords | null;
onSceneChange: OnSceneChange;
setOnSceneChange: (onSceneChange: OnSceneChange) => void;
initialScene: SceneI;
setInitialScene: (scene: SceneI) => void;
selectedSideNavItem: number | null;
setSelectedElements: (elements: Node[]) => void;
setSelectedSideNavItem: (index: number) => void;
closeSideNav: () => void;
setSidebarState: (state: SidebarState | null) => void;
renderer: Renderer;
selectedElements: Node[];
setRenderer: (containerEl: HTMLDivElement) => Renderer;
setRenderer: (renderer: Renderer) => void;
onRendererEvent: (event: SceneEventI) => void;
sidebarState: SidebarState | null;
closeSidebar: () => void;
closeContextMenu: () => void;
}
export const useGlobalState = create<GlobalState>((set, get) => ({
showContextMenuFor: null,
selectedElements: [],
selectedSideNavItem: null,
sidebarState: null,
onSceneChange: () => {},
setOnSceneChange: (onSceneChange) => set({ onSceneChange }),
initialScene: {
@@ -33,6 +43,9 @@ export const useGlobalState = create<GlobalState>((set, get) => ({
connectors: [],
groups: [],
},
closeContextMenu: () => {
set({ showContextMenuFor: null });
},
setInitialScene: (scene) => {
set({ initialScene: scene });
},
@@ -45,15 +58,18 @@ export const useGlobalState = create<GlobalState>((set, get) => ({
});
set({ selectedElements: elements });
},
setSelectedSideNavItem: (val) => {
set({ selectedSideNavItem: val });
setSidebarState: (val) => {
set({ sidebarState: val });
},
closeSideNav: () => {
set({ selectedSideNavItem: null });
closeSidebar: () => {
const { setSidebarState, setSelectedElements } = get();
setSidebarState(null);
setSelectedElements([]);
},
renderer: new Renderer(document.createElement("div")),
onRendererEvent: (event) => {
const { setSelectedElements } = get();
const { setSelectedElements, renderer } = get();
switch (event.type) {
case "TILE_SELECTED":
@@ -64,14 +80,20 @@ export const useGlobalState = create<GlobalState>((set, get) => ({
setSelectedElements(event.data.nodes);
if (event.data.nodes.length === 1) {
set({ showContextMenuFor: event.data.nodes[0] });
const node = event.data.nodes[0];
set({
showContextMenuFor: event.data.nodes[0],
sidebarState: { type: "SINGLE_NODE", node: event.data.nodes[0] },
});
renderer.scrollToTile(node.position);
}
break;
case "NODE_REMOVED":
setSelectedElements([]);
set({
showContextMenuFor: null,
selectedSideNavItem: null,
sidebarState: null,
});
break;
case "NODE_MOVED":
@@ -89,22 +111,7 @@ export const useGlobalState = create<GlobalState>((set, get) => ({
break;
}
},
setRenderer: (containerEl) => {
set((state) => {
if (state.renderer) {
state.renderer.destroy();
}
const scene = state.initialScene;
const renderer = new Renderer(containerEl);
renderer.setEventHandler(state.onRendererEvent);
renderer.loadScene(scene);
renderer.setZoom(state.renderer.zoom);
return { renderer };
});
return get().renderer;
setRenderer: (renderer) => {
set({ renderer });
},
}));

View File

@@ -9,6 +9,8 @@ const MOUSE_EVENTS = new Map([
["mousemove", "MOUSE_MOVE"],
["mousedown", "MOUSE_DOWN"],
["mouseup", "MOUSE_UP"],
["mouseenter", "MOUSE_ENTER"],
["mouseleave", "MOUSE_LEAVE"],
]);
export class ModeManager {
@@ -52,8 +54,6 @@ export class ModeManager {
Mode: T,
init?: (instance: InstanceType<T>) => void
) {
console.log("ACTIVATING MODE", Mode.name);
if (!this.renderer) return;
if (this.currentMode) {

View File

@@ -1,4 +1,4 @@
import { makeAutoObservable } from "mobx";
import { makeAutoObservable, observable } from "mobx";
import Paper, { Group } from "paper";
import gsap from "gsap";
import { Grid } from "./elements/Grid";
@@ -37,11 +37,16 @@ export class Renderer {
container: HTMLDivElement;
canvas: HTMLCanvasElement;
};
scrollPosition = new Coords(0, 0);
scroll = {
position: new Coords(0, 0),
offset: new Coords(0, 0),
};
rafRef?: number;
constructor(containerEl: HTMLDivElement) {
makeAutoObservable(this);
makeAutoObservable(this, {
scroll: observable,
});
Paper.settings = {
insertItems: false,
@@ -183,7 +188,7 @@ export class Renderer {
const globalItemsGroupPosition = this.groups.elements.globalToLocal([0, 0]);
const screenPosition = new Coords(
(tilePosition.x +
this.scrollPosition.x +
this.scroll.position.x +
globalItemsGroupPosition.x +
this.groups.elements.position.x +
viewW * 0.5) *
@@ -191,7 +196,7 @@ export class Renderer {
offsetX,
(tilePosition.y +
this.scrollPosition.y +
this.scroll.position.y +
globalItemsGroupPosition.y +
this.groups.elements.position.y +
viewH * 0.5) *
@@ -212,7 +217,7 @@ export class Renderer {
duration: 0.3,
zoom: this.zoom,
onComplete: () => {
this.scrollTo(this.scrollPosition);
this.scrollTo(this.scroll.position);
},
});
@@ -222,8 +227,8 @@ export class Renderer {
});
}
scrollTo(coords: Coords) {
this.scrollPosition.set(coords.x, coords.y);
scrollTo(coords: Coords, opts?: { skipAnimation?: boolean }) {
this.scroll.position.set(coords.x, coords.y);
const { center: viewCenter } = Paper.view.bounds;
@@ -233,17 +238,29 @@ export class Renderer {
);
gsap.to(this.groups.elements.position, {
duration: 0,
duration: opts?.skipAnimation ? 0 : 0.25,
...newPosition,
});
}
scrollToDelta(delta: Coords) {
const position = this.scrollPosition.add(delta);
const position = this.scroll.position.add(delta);
this.scrollTo(position);
}
scrollToTile(coords: Coords, opts?: { skipAnimation?: boolean }) {
const tile = this.getTileBounds(coords).center;
this.scrollTo(
new Coords(
-(tile.x - this.scroll.offset.x),
-(tile.y - this.scroll.offset.y)
),
opts
);
}
unfocusAll() {
this.sceneElements.nodes.unfocusAll();
}

View File

@@ -1,8 +1,12 @@
import { makeAutoObservable } from "mobx";
export class Coords {
x: number;
y: number;
x: number = 0;
y: number = 0;
constructor(x: number, y: number) {
makeAutoObservable(this);
this.x = x;
this.y = y;
}

View File

@@ -1,12 +1,13 @@
import { Group, Path, Point } from "paper";
import { makeAutoObservable } from "mobx";
import { applyProjectionMatrix } from "../utils/projection";
import type { Context } from "../../types";
import { TILE_SIZE, PIXEL_UNIT, SCALING_CONST } from "../constants";
import { SceneElement } from "../SceneElement";
import { Coords } from "./Coords";
import { sortByPosition, getBoundingBox } from "../utils/gridHelpers";
export class Grid extends SceneElement {
export class Grid {
ctx: Context;
container = new Group();
renderElements = {
grid: new Group({ applyMatrix: true }),
@@ -15,9 +16,10 @@ export class Grid extends SceneElement {
size: Coords;
constructor(size: Coords, ctx: Context) {
super(ctx);
makeAutoObservable(this);
this.size = size;
this.ctx = ctx;
this.container.addChild(this.renderElements.grid);
for (let x = 0; x <= this.size.x; x++) {

View File

@@ -76,6 +76,12 @@ export class Node {
this.callbacks.onMove(coords, this, opts);
}
update(options: Partial<NodeOptions>) {
if (options.iconId) {
this.icon.update(options.iconId);
}
}
export() {
return {
id: this.id,

View File

@@ -22,6 +22,10 @@ module.exports = {
use: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
resolve: {

View File

@@ -29,6 +29,10 @@ module.exports = {
use: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
resolve: {