diff --git a/package-lock.json b/package-lock.json index 677781815..efa2f9fe2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,17 @@ { "name": "chatbox", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "chatbox", - "version": "0.1.4", + "version": "0.1.5", "license": "MIT", "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@electron-forge/maker-dmg": "^6.0.5", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", @@ -54,6 +57,8 @@ "eslint-plugin-import": "^2.25.0", "fork-ts-checker-webpack-plugin": "^7.2.13", "node-loader": "^2.0.0", + "sass": "^1.93.2", + "sass-loader": "^13.2.0", "style-loader": "^3.0.0", "ts-loader": "^9.2.2", "ts-node": "^10.0.0", @@ -224,6 +229,55 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@electron-forge/cli": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-6.0.5.tgz", @@ -1717,6 +1771,338 @@ "@octokit/openapi-types": "^12.11.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -7227,6 +7613,13 @@ "node": ">=6.9.0" } }, + "node_modules/immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -10489,6 +10882,95 @@ "devOptional": true, "license": "MIT" }, + "node_modules/sass": { + "version": "1.93.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz", + "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", + "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -12761,6 +13243,41 @@ } } }, + "@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "requires": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "requires": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "requires": { + "tslib": "^2.0.0" + } + }, "@electron-forge/cli": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-6.0.5.tgz", @@ -13780,6 +14297,139 @@ "@octokit/openapi-types": "^12.11.0" } }, + "@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "optional": true, + "requires": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1", + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "dependencies": { + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true + }, + "node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + } + } + }, + "@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "dev": true, + "optional": true + }, "@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -17740,6 +18390,12 @@ "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", "optional": true }, + "immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -19933,6 +20589,44 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "devOptional": true }, + "sass": { + "version": "1.93.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz", + "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", + "dev": true, + "requires": { + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "dependencies": { + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "requires": { + "readdirp": "^4.0.1" + } + }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true + } + } + }, + "sass-loader": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", + "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", + "dev": true, + "requires": { + "neo-async": "^2.6.2" + } + }, "scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", diff --git a/package.json b/package.json index ea4194e1d..103b86f6b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "eslint-plugin-import": "^2.25.0", "fork-ts-checker-webpack-plugin": "^7.2.13", "node-loader": "^2.0.0", - "sass": "^1.59.3", + "sass": "^1.93.2", "sass-loader": "^13.2.0", "style-loader": "^3.0.0", "ts-loader": "^9.2.2", @@ -52,6 +52,9 @@ "typescript": "~4.5.4" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@electron-forge/maker-dmg": "^6.0.5", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", diff --git a/src/devtools/App.tsx b/src/devtools/App.tsx index 111026ff7..0886d60b8 100644 --- a/src/devtools/App.tsx +++ b/src/devtools/App.tsx @@ -1,461 +1,590 @@ -import React from 'react'; -import './App.css'; -import Block from './Block' -import * as client from './client' -import SessionItem from './SessionItem' +import React from "react"; +import "./App.css"; +import Block from "./Block"; +import * as client from "./client"; +import SessionItem from "./SessionItem"; import { - Toolbar, Box, Badge, Snackbar, - List, ListSubheader, ListItemText, MenuList, - IconButton, Button, Stack, Grid, MenuItem, ListItemIcon, Typography, Divider, - TextField, -} from '@mui/material'; -import { Session, createSession, Message, createMessage } from './types' -import ChatIcon from '@mui/icons-material/Chat'; -import useStore, { openLink } from './store' -import SettingWindow from './SettingWindow' -import ChatConfigWindow from './ChatConfigWindow' -import ChatBubbleOutlineOutlinedIcon from '@mui/icons-material/ChatBubbleOutlineOutlined'; -import SettingsIcon from '@mui/icons-material/Settings'; -import AddIcon from '@mui/icons-material/Add'; -import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; -import * as prompts from './prompts' -import CleaningServicesIcon from '@mui/icons-material/CleaningServices'; -import CleanWidnow from './CleanWindow'; -import { ThemeSwitcherProvider } from './theme/ThemeSwitcher'; + Toolbar, + Box, + Badge, + Snackbar, + List, + ListSubheader, + ListItemText, + MenuList, + IconButton, + Button, + Stack, + Grid, + MenuItem, + ListItemIcon, + Typography, + Divider, + TextField, +} from "@mui/material"; +import { DndContext, closestCenter } from "@dnd-kit/core"; +import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"; +import { Session, createSession, Message, createMessage } from "./types"; +import ChatIcon from "@mui/icons-material/Chat"; +import useStore, { openLink } from "./store"; +import SettingWindow from "./SettingWindow"; +import ChatConfigWindow from "./ChatConfigWindow"; +import ChatBubbleOutlineOutlinedIcon from "@mui/icons-material/ChatBubbleOutlineOutlined"; +import SettingsIcon from "@mui/icons-material/Settings"; +import AddIcon from "@mui/icons-material/Add"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +import * as prompts from "./prompts"; +import CleaningServicesIcon from "@mui/icons-material/CleaningServices"; +import CleanWidnow from "./CleanWindow"; +import { ThemeSwitcherProvider } from "./theme/ThemeSwitcher"; -const { useEffect, useState } = React +const { useEffect, useState } = React; function Main() { - const store = useStore() + const store = useStore(); - // 是否展示设置窗口 - const [openSettingWindow, setOpenSettingWindow] = React.useState(false); - useEffect(() => { - if (store.needSetting) { - setOpenSettingWindow(true) - } - }, [store.needSetting]) - - // 是否展示应用更新提示 - const [needCheckUpdate, setNeedCheckUpdate] = useState(true) - - const [scrollToMsg, setScrollToMsg] = useState<{ msgId: string, smooth?: boolean }>(null) - useEffect(() => { - if (!scrollToMsg) { - return - } - const container = document.getElementById('message-list') - const element = document.getElementById(scrollToMsg.msgId) - if (!container || !element) { - return - } - const elementRect = element.getBoundingClientRect(); - const containerRect = container.getBoundingClientRect(); - const isInsideLeft = elementRect.left >= containerRect.left; - const isInsideRight = elementRect.right <= containerRect.right; - const isInsideTop = elementRect.top >= containerRect.top; - const isInsideBottom = elementRect.bottom <= containerRect.bottom; - if (isInsideLeft && isInsideRight && isInsideTop && isInsideBottom) { - return - } - // 平滑滚动 - element.scrollIntoView({ - behavior: scrollToMsg.smooth ? 'smooth' : 'auto', - block: 'end', - inline: 'nearest', - }) - setScrollToMsg(null) - }, [scrollToMsg]) - - // 切换到当前会话,自动滚动到最后一条消息 - useEffect(() => { - if (store.currentSession.messages.length === 0) { - return - } - const last = store.currentSession.messages[store.currentSession.messages.length - 1] - setScrollToMsg({ msgId: last.id, smooth: false }) - }, [store.currentSession]) - - // 会话名称自动生成 - useEffect(() => { - if ( - store.currentSession.name === 'Untitled' - && store.currentSession.messages.findIndex(msg => msg.role === 'assistant') !== -1 - ) { - generateName(store.currentSession) - } - }, [store.currentSession.messages]) + // 是否展示设置窗口 + const [openSettingWindow, setOpenSettingWindow] = React.useState(false); + useEffect(() => { + if (store.needSetting) { + setOpenSettingWindow(true); + } + }, [store.needSetting]); - const [configureChatConfig, setConfigureChatConfig] = React.useState(null); + // 是否展示应用更新提示 + const [needCheckUpdate, setNeedCheckUpdate] = useState(true); - const [sessionClean, setSessionClean] = React.useState(null); + const [scrollToMsg, setScrollToMsg] = useState<{ + msgId: string; + smooth?: boolean; + }>(null); + useEffect(() => { + if (!scrollToMsg) { + return; + } + const container = document.getElementById("message-list"); + const element = document.getElementById(scrollToMsg.msgId); + if (!container || !element) { + return; + } + const elementRect = element.getBoundingClientRect(); + const containerRect = container.getBoundingClientRect(); + const isInsideLeft = elementRect.left >= containerRect.left; + const isInsideRight = elementRect.right <= containerRect.right; + const isInsideTop = elementRect.top >= containerRect.top; + const isInsideBottom = elementRect.bottom <= containerRect.bottom; + if (isInsideLeft && isInsideRight && isInsideTop && isInsideBottom) { + return; + } + // 平滑滚动 + element.scrollIntoView({ + behavior: scrollToMsg.smooth ? "smooth" : "auto", + block: "end", + inline: "nearest", + }); + setScrollToMsg(null); + }, [scrollToMsg]); - const generateName = async (session: Session) => { - client.replay( - store.settings.openaiKey, - store.settings.apiHost, - prompts.nameConversation(session.messages.slice(0, 3)), - (name) => { - name = name.replace(/['"“”]/g, '') - session.name = name - store.updateChatSession(session) - }, - (err) => { - console.log(err) - } - ) + // 切换到当前会话,自动滚动到最后一条消息 + useEffect(() => { + if (store.currentSession.messages.length === 0) { + return; } + const last = + store.currentSession.messages[store.currentSession.messages.length - 1]; + setScrollToMsg({ msgId: last.id, smooth: false }); + }, [store.currentSession]); - const generate = async (session: Session, promptMsgs: Message[], targetMsg: Message) => { - await client.replay( - store.settings.openaiKey, - store.settings.apiHost, - promptMsgs, - (text) => { - for (let i = 0; i < session.messages.length; i++) { - if (session.messages[i].id === targetMsg.id) { - session.messages[i] = { - ...session.messages[i], - content: text, - } - break - } - } - store.updateChatSession(session) - setScrollToMsg({ msgId: targetMsg.id, smooth: false }) - }, - (err) => { - for (let i = 0; i < session.messages.length; i++) { - if (session.messages[i].id === targetMsg.id) { - session.messages[i] = { - ...session.messages[i], - content: 'API Request Failed: \n```\n' + err.message + '\n```', - } - break - } - } - store.updateChatSession(session) - } - ) + // 会话名称自动生成 + useEffect(() => { + if ( + store.currentSession.name === "Untitled" && + store.currentSession.messages.findIndex( + (msg) => msg.role === "assistant" + ) !== -1 + ) { + generateName(store.currentSession); } + }, [store.currentSession.messages]); - const [ messageInput, setMessageInput ] = useState('') - useEffect(() => { - document.getElementById('message-input')?.focus() // better way? - }, [messageInput]) + const [configureChatConfig, setConfigureChatConfig] = + React.useState(null); - return ( - - - - - - - - - - ChatBox - - + const [sessionClean, setSessionClean] = React.useState(null); - + const generateName = async (session: Session) => { + client.replay( + store.settings.openaiKey, + store.settings.apiHost, + prompts.nameConversation(session.messages.slice(0, 3)), + (name) => { + name = name.replace(/['"“”]/g, ""); + session.name = name; + store.updateChatSession(session); + }, + (err) => { + console.log(err); + } + ); + }; - - CHAT - - } - > - { - store.chatSessions.map((session, ix) => ( - { - store.switchCurrentSession(session) - document.getElementById('message-input')?.focus() // better way? - }} - deleteMe={() => store.deleteChatSession(session)} - copyMe={() => { - const newSession = createSession(session.name + ' Copyed') - newSession.messages = session.messages - store.createChatSession(newSession, ix) - }} - editMe={() => setConfigureChatConfig(session)} - /> - )) - } - + const generate = async ( + session: Session, + promptMsgs: Message[], + targetMsg: Message + ) => { + await client.replay( + store.settings.openaiKey, + store.settings.apiHost, + promptMsgs, + (text) => { + for (let i = 0; i < session.messages.length; i++) { + if (session.messages[i].id === targetMsg.id) { + session.messages[i] = { + ...session.messages[i], + content: text, + }; + break; + } + } + store.updateChatSession(session); + setScrollToMsg({ msgId: targetMsg.id, smooth: false }); + }, + (err) => { + for (let i = 0; i < session.messages.length; i++) { + if (session.messages[i].id === targetMsg.id) { + session.messages[i] = { + ...session.messages[i], + content: "API Request Failed: \n```\n" + err.message + "\n```", + }; + break; + } + } + store.updateChatSession(session); + } + ); + }; - + const [messageInput, setMessageInput] = useState(""); + useEffect(() => { + document.getElementById("message-input")?.focus(); // better way? + }, [messageInput]); - store.createEmptyChatSession()} > - - - - - New Chat - - - {/* ⌘N */} - - - { - setOpenSettingWindow(true) - }} - > - - - - - Settings - - - {/* ⌘N */} - - + return ( + + + + + + + + + + ChatBox + + - { - setNeedCheckUpdate(false) - openLink('https://github.com/Bin-Huang/chatbox/releases') - }}> - - - - - - - - - Version: {store.version} - - - - - + - - { + const { active, over } = event; + if (over && active.id !== over.id) { + const oldIndex = store.chatSessions.findIndex(s => s.id === active.id); + const newIndex = store.chatSessions.findIndex(s => s.id === over.id); + if (oldIndex !== -1 && newIndex !== -1) { + store.reorderSessions(oldIndex, newIndex); + } + } + }} + > + + CHAT} > - - - - - - - {store.currentSession.name} - - setSessionClean(store.currentSession)} - > - - - - - - { - store.currentSession.messages.map((msg, ix) => ( - { - store.currentSession.messages = store.currentSession.messages.map((m) => { - if (m.id === updated.id) { - return updated - } - return m - }) - store.updateChatSession(store.currentSession) - }} - delMsg={() => { - store.currentSession.messages = store.currentSession.messages.filter((m) => m.id !== msg.id) - store.updateChatSession(store.currentSession) - }} - refreshMsg={() => { - if (msg.role === 'assistant') { - const promptMsgs = store.currentSession.messages.slice(0, ix) - generate(store.currentSession, promptMsgs, msg) - } else { - const promptsMsgs = store.currentSession.messages.slice(0, ix + 1) - const newAssistantMsg = createMessage('assistant', '....') - const newMessages = [...store.currentSession.messages] - newMessages.splice(ix + 1, 0, newAssistantMsg) - store.currentSession.messages = newMessages - store.updateChatSession(store.currentSession) - generate(store.currentSession, promptsMsgs, newAssistantMsg) - setScrollToMsg({ msgId: newAssistantMsg.id, smooth: true }) - } - }} - copyMsg={() => { - navigator.clipboard.writeText(msg.content) - store.addToast('Copied to clipboard') - }} - quoteMsg={() => { - let input = msg.content.split('\n').map(line => `> ${line}`).join('\n') - input += '\n\n-------------------\n\n' - setMessageInput(input) - }} - /> - )) - } - - - { - const promptsMsgs = [...store.currentSession.messages, newUserMsg] - const newAssistantMsg = createMessage('assistant', '....') - store.currentSession.messages = [...store.currentSession.messages, newUserMsg, newAssistantMsg] - store.updateChatSession(store.currentSession) - generate(store.currentSession, promptsMsgs, newAssistantMsg) - setScrollToMsg({ msgId: newAssistantMsg.id, smooth: true }) - }} - /> - - - + {store.chatSessions.map((session, ix) => ( + { + store.switchCurrentSession(session); + document.getElementById("message-input")?.focus(); // better way? + }} + deleteMe={() => store.deleteChatSession(session)} + copyMe={() => { + const newSession = createSession(session.name + " Copyed"); + newSession.messages = session.messages; + store.createChatSession(newSession); + }} + editMe={() => setConfigureChatConfig(session)} + addToast={store.addToast} + /> + ))} + + + + + + + store.createEmptyChatSession()}> + + + + + + New Chat + + {/* ⌘N */} + + + { + setOpenSettingWindow(true); + }} + > + + + + + + Settings + + {/* ⌘N */} + + - { - store.setSettings(settings) - setOpenSettingWindow(false) - }} - close={() => setOpenSettingWindow(false)} + { + setNeedCheckUpdate(false); + openLink("https://github.com/Bin-Huang/chatbox/releases"); + }} + > + + + + + + + + + Version: {store.version} + + + + + + + + + + + + + + {store.currentSession.name} + + setSessionClean(store.currentSession)} + > + + + + + + {store.currentSession.messages.map((msg, ix) => ( + { + store.currentSession.messages = + store.currentSession.messages.map((m) => { + if (m.id === updated.id) { + return updated; + } + return m; + }); + store.updateChatSession(store.currentSession); + }} + delMsg={() => { + store.currentSession.messages = + store.currentSession.messages.filter( + (m) => m.id !== msg.id + ); + store.updateChatSession(store.currentSession); + }} + refreshMsg={() => { + if (msg.role === "assistant") { + const promptMsgs = store.currentSession.messages.slice( + 0, + ix + ); + generate(store.currentSession, promptMsgs, msg); + } else { + const promptsMsgs = store.currentSession.messages.slice( + 0, + ix + 1 + ); + const newAssistantMsg = createMessage( + "assistant", + "...." + ); + const newMessages = [...store.currentSession.messages]; + newMessages.splice(ix + 1, 0, newAssistantMsg); + store.currentSession.messages = newMessages; + store.updateChatSession(store.currentSession); + generate( + store.currentSession, + promptsMsgs, + newAssistantMsg + ); + setScrollToMsg({ + msgId: newAssistantMsg.id, + smooth: true, + }); + } + }} + copyMsg={() => { + navigator.clipboard.writeText(msg.content); + store.addToast("Copied to clipboard"); + }} + quoteMsg={() => { + let input = msg.content + .split("\n") + .map((line) => `> ${line}`) + .join("\n"); + input += "\n\n-------------------\n\n"; + setMessageInput(input); + }} + addToast={store.addToast} /> - { - configureChatConfig !== null && ( - { - store.updateChatSession(session) - setConfigureChatConfig(null) - }} - close={() => setConfigureChatConfig(null)} - /> - ) - } - { - sessionClean !== null && ( - { - store.updateChatSession(session) - setSessionClean(null) - }} - close={() => setSessionClean(null)} - /> - ) - } - { - store.toasts.map((toast) => ( - store.removeToast(toast.id)} - message={toast.content} - anchorOrigin={{ vertical: 'top', horizontal: 'right' }} - /> - )) + ))} + + + + store.addToast("Please type something before sending") } - - - ); + onSubmit={async (newUserMsg: Message) => { + if (newUserMsg.content.trim().length === 0) { + store.addToast("Empty messages are not allowed"); + return; + } + const promptsMsgs = [ + ...store.currentSession.messages, + newUserMsg, + ]; + const newAssistantMsg = createMessage("assistant", "...."); + store.currentSession.messages = [ + ...store.currentSession.messages, + newUserMsg, + newAssistantMsg, + ]; + store.updateChatSession(store.currentSession); + generate(store.currentSession, promptsMsgs, newAssistantMsg); + setScrollToMsg({ msgId: newAssistantMsg.id, smooth: true }); + }} + /> + + + + + { + store.setSettings(settings); + setOpenSettingWindow(false); + }} + close={() => setOpenSettingWindow(false)} + /> + {configureChatConfig !== null && ( + { + store.updateChatSession(session); + setConfigureChatConfig(null); + }} + close={() => setConfigureChatConfig(null)} + /> + )} + {sessionClean !== null && ( + { + store.updateChatSession(session); + setSessionClean(null); + }} + close={() => setSessionClean(null)} + /> + )} + {store.toasts.map((toast) => ( + store.removeToast(toast.id)} + message={toast.content} + anchorOrigin={{ vertical: "top", horizontal: "right" }} + /> + ))} + + + ); } export default function App() { - return ( - -
- - ) + return ( + +
+ + ); } - function MessageInput(props: { - onSubmit: (newMsg: Message) => void - messageInput: string - setMessageInput: (value: string) => void + onSubmit: (newMsg: Message) => void; + onInvalid?: () => void; + messageInput: string; + setMessageInput: (value: string) => void; }) { - const {messageInput, setMessageInput} = props - const submit = (event?: any) => { - if (event) { - event.preventDefault() - } - if (messageInput.length === 0) { - return - } - props.onSubmit(createMessage('user', messageInput)) - setMessageInput('') + const { messageInput, setMessageInput } = props; + const submit = (event?: any) => { + if (event) { + event.preventDefault(); } - return ( -
- - - setMessageInput(event.target.value)} - fullWidth - maxRows={12} - autoFocus - id='message-input' - onKeyDown={(event) => { - if (event.keyCode === 13 && !event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey) { - event.preventDefault() - submit() - return - } - }} - /> - - - [Enter] send, [Shift+Enter] line break - -
- ) + const trimmed = messageInput.trim(); + if (trimmed.length === 0) { + props.onInvalid && props.onInvalid(); + return; + } + props.onSubmit(createMessage("user", trimmed)); + setMessageInput(""); + }; + return ( +
+ + + setMessageInput(event.target.value)} + fullWidth + maxRows={12} + autoFocus + id="message-input" + onKeyDown={(event) => { + if ( + event.keyCode === 13 && + !event.shiftKey && + !event.ctrlKey && + !event.altKey && + !event.metaKey + ) { + event.preventDefault(); + submit(); + return; + } + }} + /> + + + + [Enter] send, [Shift+Enter] line break + + +
+ ); } diff --git a/src/devtools/Block.tsx b/src/devtools/Block.tsx index 6f6f50174..0b6439723 100644 --- a/src/devtools/Block.tsx +++ b/src/devtools/Block.tsx @@ -59,12 +59,54 @@ export interface Props { refreshMsg: () => void copyMsg: () => void quoteMsg: () => void + addToast: (content: string) => void } function _Block(props: Props) { - const { msg, setMsg } = props + const { msg, setMsg, addToast } = props const [isHovering, setIsHovering] = useState(false) const [isEditing, setIsEditing] = useState(false) + const contentRef = useRef(null); + + // Add copy buttons to code blocks + useEffect(() => { + if (isEditing || !contentRef.current) return; + + // Find all code blocks within this message only + const codeBlocks = contentRef.current.querySelectorAll('pre.hljs'); + + codeBlocks.forEach((block) => { + // Skip if button already exists + if (block.querySelector('.code-copy-btn')) return; + + // Add relative positioning to parent block + (block as HTMLElement).style.position = 'relative'; + + // Create copy button + const button = document.createElement('button'); + button.textContent = 'Copy'; + button.className = 'code-copy-btn'; + + // Add click handler to copy code + button.onclick = () => { + // Get only the code element's text, not the button text + const codeElement = block.querySelector('code'); + const code = codeElement ? codeElement.textContent || '' : ''; + navigator.clipboard.writeText(code); + addToast('Copied'); + }; + + // Add button to code block + block.prepend(button); + }); + + // Cleanup function + return () => { + if (!contentRef.current) return; + const buttons = contentRef.current.querySelectorAll('.code-copy-btn'); + buttons.forEach(button => button.remove()); + }; + }, [msg.content, isEditing, addToast]); const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); @@ -151,6 +193,7 @@ function _Block(props: Props) { /> ) : ( void copyMe: () => void editMe: () => void + addToast: (content: string) => void } export default function SessionItem(props: Props) { - const { session, selected, switchMe, deleteMe, copyMe, editMe } = props + const { session, selected, switchMe, deleteMe, copyMe, editMe, addToast } = props const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); + const [confirmDeleteOpen, setConfirmDeleteOpen] = React.useState(false); + const dragStartedRef = React.useRef(false); + const clickPositionRef = React.useRef<{ x: number; y: number } | null>(null); + const buttonRef = React.useRef(null); + const handleClick = (event: React.MouseEvent) => { - event.preventDefault() - setAnchorEl(event.currentTarget); + // Prevent click from propagating to parent MenuItem + event.stopPropagation(); + event.preventDefault(); }; + const handleClose = () => { setAnchorEl(null); }; + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id: session.id }); + + // Create custom listeners that track drag vs click + const customListeners = React.useMemo(() => { + if (!listeners) return {}; + + const originalOnMouseDown = listeners.onMouseDown; + const originalOnTouchStart = listeners.onTouchStart; + + return { + ...listeners, + onMouseDown: (e: React.MouseEvent) => { + // Prevent this from bubbling to parent MenuItem + e.stopPropagation(); + + dragStartedRef.current = false; + clickPositionRef.current = { x: e.clientX, y: e.clientY }; + + // Track mouse move to detect drag + const handleMouseMove = (moveEvent: MouseEvent) => { + if (clickPositionRef.current) { + const dx = moveEvent.clientX - clickPositionRef.current.x; + const dy = moveEvent.clientY - clickPositionRef.current.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + // If moved more than 5px, consider it a drag + if (distance > 5) { + dragStartedRef.current = true; + } + } + }; + + const cleanup = () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', cleanup); + + // On mouse up, if no drag occurred, open menu + const wasClick = !dragStartedRef.current; + dragStartedRef.current = false; + clickPositionRef.current = null; + + if (wasClick && buttonRef.current) { + setAnchorEl(buttonRef.current); + } + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', cleanup); + + if (originalOnMouseDown) { + originalOnMouseDown(e); + } + }, + onTouchStart: (e: React.TouchEvent) => { + // Prevent this from bubbling to parent MenuItem + e.stopPropagation(); + + dragStartedRef.current = false; + if (e.touches[0]) { + clickPositionRef.current = { x: e.touches[0].clientX, y: e.touches[0].clientY }; + } + + if (originalOnTouchStart) { + originalOnTouchStart(e); + } + }, + }; + }, [listeners]); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + opacity: isDragging ? 0.5 : 1, + }; + return ( switchMe()} @@ -52,7 +147,12 @@ export default function SessionItem(props: Props) { {session.name} - + { buttonRef.current = el; }} + {...attributes} + {...customListeners} + onClick={handleClick} + > - { + { + e.stopPropagation(); editMe() handleClose() }} disableRipple> @@ -71,7 +172,8 @@ export default function SessionItem(props: Props) { Rename - { + { + e.stopPropagation(); copyMe() handleClose() }} disableRipple> @@ -81,10 +183,11 @@ export default function SessionItem(props: Props) { - { + { + e.stopPropagation(); setAnchorEl(null) handleClose() - deleteMe() + setConfirmDeleteOpen(true) }} disableRipple > @@ -92,6 +195,44 @@ export default function SessionItem(props: Props) { + + setConfirmDeleteOpen(false)} + aria-labelledby="delete-dialog-title" + aria-describedby="delete-dialog-description" + > + + Delete Chat Session? + + + + Are you sure you want to delete "{session.name}"? This action cannot be undone. + + + + + + + ) } diff --git a/src/devtools/defaults.ts b/src/devtools/defaults.ts index 2c10451e6..90428dd53 100644 --- a/src/devtools/defaults.ts +++ b/src/devtools/defaults.ts @@ -1,6 +1,11 @@ import { Session } from './types' export const sessions: Session[] = [ + { + "id": "my-first-chat-0000-0000-0000-000000000000", + "name": "My First Chat", + "messages": [] + }, { "id": "1bc7094f-1248-4b51-8ac8-180a5a1470aa", "name": "Random Talk", diff --git a/src/devtools/store.ts b/src/devtools/store.ts index 678485525..5d8c271e5 100644 --- a/src/devtools/store.ts +++ b/src/devtools/store.ts @@ -122,14 +122,48 @@ export default function useStore() { } const deleteChatSession = (target: Session) => { + // Find the index of the session being deleted (for smart navigation) + const targetIndex = chatSessions.findIndex((s) => s.id === target.id) + + // Filter out the target session const sessions = chatSessions.filter((s) => s.id !== target.id) + + // Ensure at least one session exists if (sessions.length === 0) { sessions.push(createSession()) } - if (target.id === currentSession.id) { - switchCurrentSession(sessions[0]) + + // Determine which session to switch to + let newCurrentSession: Session + + // Check if the deleted session was the current session + const wasCurrentSessionDeleted = target.id === currentSession.id + + if (wasCurrentSessionDeleted) { + // Current session was deleted - switch to nearest session + // Prefer the session that was below (next), or above (previous) if it was the last one + if (targetIndex < sessions.length) { + // There's a session at the same index (the next session moved up) + newCurrentSession = sessions[targetIndex] + } else { + // Deleted session was last, use the previous session + newCurrentSession = sessions[sessions.length - 1] + } + } else { + // Current session was not deleted - keep it but update reference + // This ensures currentSession always references a session that exists in chatSessions + const found = sessions.find((s) => s.id === currentSession.id) + newCurrentSession = found || sessions[0] // fallback to first session } - setSessions(sessions) + + // Update sessions list first + _setChatSessions(sessions) + writeSessions(sessions) + + // Then update currentSession (deferred to ensure React state consistency) + setTimeout(() => { + switchCurrentSession(newCurrentSession) + }, 0) } const updateChatSession = (session: Session) => { const sessions = chatSessions.map((s) => { @@ -143,7 +177,7 @@ export default function useStore() { switchCurrentSession(session) } } - const createChatSession = (session: Session, ix?: number) => { + const createChatSession = (session: Session) => { const sessions = [...chatSessions, session] setSessions(sessions) switchCurrentSession(session) @@ -152,6 +186,22 @@ export default function useStore() { createChatSession(createSession()) } + const reorderSessions = (fromIndex: number, toIndex: number) => { + // Create a copy of the sessions array + const newSessions = [...chatSessions] + + // Remove the item from its original position + const [movedSession] = newSessions.splice(fromIndex, 1) + + // Insert it at the new position + newSessions.splice(toIndex, 0, movedSession) + + // Update state and persist + setSessions(newSessions) + + console.log('Sessions reordered:', { fromIndex, toIndex, sessionIds: newSessions.map(s => s.id) }) + } + const setMessages = (session: Session, messages: Message[]) => { updateChatSession({ ...session, @@ -180,6 +230,7 @@ export default function useStore() { updateChatSession, deleteChatSession, createEmptyChatSession, + reorderSessions, currentSession, switchCurrentSession, diff --git a/src/index.scss b/src/index.scss index 29ebd316b..2deaa93b9 100644 --- a/src/index.scss +++ b/src/index.scss @@ -15,6 +15,31 @@ html[data-theme='dark'] { // https://stackoverflow.com/questions/59257368/how-to-dynamically-change-the-theme-using-highlight-js @include meta.load-css('highlight.js/styles/github-dark'); + // ------------ Code copy button --------------- + .code-copy-btn { + position: absolute; + top: 8px; + right: 8px; + padding: 4px 8px; + background-color: #444; + color: #fff; + border: 1px solid #666; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + z-index: 10; + opacity: 0; + transition: opacity 0.2s ease-in-out; + } + + .code-copy-btn:hover { + background-color: #555; + } + + pre.hljs:hover .code-copy-btn { + opacity: 1; + } + // ------------ 滚动条 --------------- /* 设置滚动条的宽度, 背景色与边框 */ @@ -64,6 +89,31 @@ html[data-theme='light'] { // https://stackoverflow.com/questions/59257368/how-to-dynamically-change-the-theme-using-highlight-js @include meta.load-css('highlight.js/styles/github'); + // ------------ Code copy button --------------- + .code-copy-btn { + position: absolute; + top: 8px; + right: 8px; + padding: 4px 8px; + background-color: #f6f8fa; + color: #24292e; + border: 1px solid #d0d7de; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + z-index: 10; + opacity: 0; + transition: opacity 0.2s ease-in-out; + } + + .code-copy-btn:hover { + background-color: #e1e4e8; + } + + pre.hljs:hover .code-copy-btn { + opacity: 1; + } + // ------------ 滚动条 --------------- /* 设置滚动条的宽度, 背景色与边框 */ diff --git a/yarn.lock b/yarn.lock index 4547e9c4d..ea0f85fce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,6 +58,37 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dnd-kit/accessibility@^3.1.1": + "integrity" "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==" + "resolved" "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz" + "version" "3.1.1" + dependencies: + "tslib" "^2.0.0" + +"@dnd-kit/core@^6.3.0", "@dnd-kit/core@^6.3.1": + "integrity" "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==" + "resolved" "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz" + "version" "6.3.1" + dependencies: + "@dnd-kit/accessibility" "^3.1.1" + "@dnd-kit/utilities" "^3.2.2" + "tslib" "^2.0.0" + +"@dnd-kit/sortable@^10.0.0": + "integrity" "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==" + "resolved" "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz" + "version" "10.0.0" + dependencies: + "@dnd-kit/utilities" "^3.2.2" + "tslib" "^2.0.0" + +"@dnd-kit/utilities@^3.2.2": + "integrity" "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==" + "resolved" "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz" + "version" "3.2.2" + dependencies: + "tslib" "^2.0.0" + "@electron-forge/cli@^6.0.5": "integrity" "sha512-3xD4XKyV634cQCR8HobpVnb4LqVdTHDs+KwsU9zgjaBIJMBapCS3ZzpXYbxzPekTaVwu39ojMUg990JVYBhs2A==" "resolved" "https://registry.npmjs.org/@electron-forge/cli/-/cli-6.0.5.tgz" @@ -820,6 +851,40 @@ dependencies: "@octokit/openapi-types" "^12.11.0" +"@parcel/watcher-linux-x64-glibc@2.5.1": + "integrity" "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==" + "resolved" "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz" + "version" "2.5.1" + +"@parcel/watcher-linux-x64-musl@2.5.1": + "integrity" "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==" + "resolved" "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz" + "version" "2.5.1" + +"@parcel/watcher@^2.4.1": + "integrity" "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==" + "resolved" "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz" + "version" "2.5.1" + dependencies: + "detect-libc" "^1.0.3" + "is-glob" "^4.0.3" + "micromatch" "^4.0.5" + "node-addon-api" "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.5.1" + "@parcel/watcher-darwin-arm64" "2.5.1" + "@parcel/watcher-darwin-x64" "2.5.1" + "@parcel/watcher-freebsd-x64" "2.5.1" + "@parcel/watcher-linux-arm-glibc" "2.5.1" + "@parcel/watcher-linux-arm-musl" "2.5.1" + "@parcel/watcher-linux-arm64-glibc" "2.5.1" + "@parcel/watcher-linux-arm64-musl" "2.5.1" + "@parcel/watcher-linux-x64-glibc" "2.5.1" + "@parcel/watcher-linux-x64-musl" "2.5.1" + "@parcel/watcher-win32-arm64" "2.5.1" + "@parcel/watcher-win32-ia32" "2.5.1" + "@parcel/watcher-win32-x64" "2.5.1" + "@popperjs/core@^2.11.6": "integrity" "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz" @@ -1545,23 +1610,6 @@ "normalize-path" "^3.0.0" "picomatch" "^2.0.4" -"appdmg@^0.6.4": - "integrity" "sha512-GRmFKlCG+PWbcYF4LUNonTYmy0GjguDy6Jh9WP8mpd0T6j80XIJyXBiWlD0U+MLNhqV9Nhx49Gl9GpVToulpLg==" - "resolved" "https://registry.npmjs.org/appdmg/-/appdmg-0.6.6.tgz" - "version" "0.6.6" - dependencies: - "async" "^1.4.2" - "ds-store" "^0.1.5" - "execa" "^1.0.0" - "fs-temp" "^1.0.0" - "fs-xattr" "^0.3.0" - "image-size" "^0.7.4" - "is-my-json-valid" "^2.20.0" - "minimist" "^1.1.3" - "parse-color" "^1.0.0" - "path-exists" "^4.0.0" - "repeat-string" "^1.5.4" - "aproba@^1.0.3 || ^2.0.0": "integrity" "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" "resolved" "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" @@ -1653,11 +1701,6 @@ "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" "version" "2.0.0" -"async@^1.4.2": - "integrity" "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==" - "resolved" "https://registry.npmjs.org/async/-/async-1.5.2.tgz" - "version" "1.5.2" - "asynckit@^0.4.0": "integrity" "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" "resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" @@ -1704,13 +1747,6 @@ "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" "version" "1.0.2" -"base32-encode@^0.1.0 || ^1.0.0": - "integrity" "sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==" - "resolved" "https://registry.npmjs.org/base32-encode/-/base32-encode-1.2.0.tgz" - "version" "1.2.0" - dependencies: - "to-data-view" "^1.1.0" - "base64-js@^1.3.1", "base64-js@^1.5.1": "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" "resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -1793,13 +1829,6 @@ "resolved" "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz" "version" "2.19.5" -"bplist-creator@~0.0.3": - "integrity" "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==" - "resolved" "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz" - "version" "0.0.8" - dependencies: - "stream-buffers" "~2.2.0" - "brace-expansion@^1.1.7": "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1970,6 +1999,13 @@ optionalDependencies: "fsevents" "~2.3.2" +"chokidar@^4.0.0": + "integrity" "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==" + "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "readdirp" "^4.0.1" + "chownr@^2.0.0": "integrity" "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" "resolved" "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" @@ -2089,11 +2125,6 @@ dependencies: "color-name" "~1.1.4" -"color-convert@~0.5.0": - "integrity" "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==" - "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz" - "version" "0.5.3" - "color-name@~1.1.4": "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" @@ -2461,6 +2492,11 @@ "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" "version" "1.2.0" +"detect-libc@^1.0.3": + "integrity" "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==" + "resolved" "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" + "version" "1.0.3" + "detect-libc@^2.0.1": "integrity" "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" "resolved" "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" @@ -2577,15 +2613,6 @@ dependencies: "is-obj" "^2.0.0" -"ds-store@^0.1.5": - "integrity" "sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==" - "resolved" "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz" - "version" "0.1.6" - dependencies: - "bplist-creator" "~0.0.3" - "macos-alias" "~0.2.5" - "tn1150" "^0.1.0" - "ee-first@1.1.1": "integrity" "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" @@ -2725,11 +2752,6 @@ "resolved" "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" "version" "3.0.0" -"encode-utf8@^1.0.3": - "integrity" "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" - "resolved" "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz" - "version" "1.0.3" - "encodeurl@~1.0.2": "integrity" "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" @@ -3289,13 +3311,6 @@ "debug" "^4.1.1" "fs-extra" "^7.0.0" -"fmix@^0.1.0": - "integrity" "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==" - "resolved" "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz" - "version" "0.1.0" - dependencies: - "imul" "^1.0.0" - "follow-redirects@^1.0.0", "follow-redirects@^1.14.8": "integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" @@ -3422,28 +3437,11 @@ "resolved" "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz" "version" "1.0.3" -"fs-temp@^1.0.0": - "integrity" "sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==" - "resolved" "https://registry.npmjs.org/fs-temp/-/fs-temp-1.2.1.tgz" - "version" "1.2.1" - dependencies: - "random-path" "^0.1.0" - -"fs-xattr@^0.3.0": - "integrity" "sha512-UVqkrEW0GfDabw4C3HOrFlxKfx0eeigfRne69FxSBdHIP8Qt5Sq6Pu3RM9KmMlkygtC4pPKkj5CiPO5USnj2GA==" - "resolved" "https://registry.npmjs.org/fs-xattr/-/fs-xattr-0.3.1.tgz" - "version" "0.3.1" - "fs.realpath@^1.0.0": "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" "version" "1.0.0" -"fsevents@~2.3.2": - "integrity" "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==" - "resolved" "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - "version" "2.3.2" - "function-bind@^1.1.1": "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -3492,20 +3490,6 @@ "strip-ansi" "^6.0.1" "wide-align" "^1.1.5" -"generate-function@^2.0.0": - "integrity" "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==" - "resolved" "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz" - "version" "2.3.1" - dependencies: - "is-property" "^1.0.2" - -"generate-object-property@^1.1.0": - "integrity" "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==" - "resolved" "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" - "version" "1.2.0" - dependencies: - "is-property" "^1.0.0" - "get-caller-file@^2.0.1", "get-caller-file@^2.0.5": "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" @@ -3986,10 +3970,10 @@ "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" "version" "5.2.4" -"image-size@^0.7.4": - "integrity" "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" - "resolved" "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz" - "version" "0.7.5" +"immutable@^5.0.2": + "integrity" "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==" + "resolved" "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz" + "version" "5.1.3" "import-fresh@^3.0.0", "import-fresh@^3.2.1": "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" @@ -3999,11 +3983,6 @@ "parent-module" "^1.0.0" "resolve-from" "^4.0.0" -"imul@^1.0.0": - "integrity" "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==" - "resolved" "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz" - "version" "1.0.1" - "imurmurhash@^0.1.4": "integrity" "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" @@ -4158,22 +4137,6 @@ "resolved" "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" "version" "1.0.1" -"is-my-ip-valid@^1.0.0": - "integrity" "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==" - "resolved" "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz" - "version" "1.0.1" - -"is-my-json-valid@^2.20.0": - "integrity" "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==" - "resolved" "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz" - "version" "2.20.6" - dependencies: - "generate-function" "^2.0.0" - "generate-object-property" "^1.1.0" - "is-my-ip-valid" "^1.0.0" - "jsonpointer" "^5.0.0" - "xtend" "^4.0.0" - "is-negative-zero@^2.0.2": "integrity" "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" "resolved" "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" @@ -4218,11 +4181,6 @@ "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" "version" "5.0.0" -"is-property@^1.0.0", "is-property@^1.0.2": - "integrity" "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - "resolved" "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" - "version" "1.0.2" - "is-regex@^1.1.4": "integrity" "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==" "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" @@ -4411,11 +4369,6 @@ optionalDependencies: "graceful-fs" "^4.1.6" -"jsonpointer@^5.0.0": - "integrity" "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==" - "resolved" "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz" - "version" "5.0.1" - "junk@^3.1.0": "integrity" "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==" "resolved" "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz" @@ -4621,13 +4574,6 @@ "node-gyp-build" "^4.2.1" "readable-stream" "^3.6.0" -"macos-alias@~0.2.5": - "integrity" "sha512-zIUs3+qpml+w3wiRuADutd7XIO8UABqksot10Utl/tji4UxZzLG4fWDC+yJZoO8/Ehg5RqsvSRE/6TS5AEOeWw==" - "resolved" "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.11.tgz" - "version" "0.2.11" - dependencies: - "nan" "^2.4.0" - "make-error@^1.1.1": "integrity" "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" "resolved" "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" @@ -4741,7 +4687,7 @@ "resolved" "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" "version" "1.1.2" -"micromatch@^4.0.0", "micromatch@^4.0.2", "micromatch@^4.0.4": +"micromatch@^4.0.0", "micromatch@^4.0.2", "micromatch@^4.0.4", "micromatch@^4.0.5": "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" "version" "4.0.5" @@ -4805,7 +4751,7 @@ dependencies: "brace-expansion" "^2.0.1" -"minimist@^1.1.1", "minimist@^1.1.3", "minimist@^1.2.0", "minimist@^1.2.6": +"minimist@^1.1.1", "minimist@^1.2.0", "minimist@^1.2.6": "integrity" "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" "version" "1.2.8" @@ -4904,20 +4850,6 @@ "dns-packet" "^5.2.2" "thunky" "^1.0.2" -"murmur-32@^0.1.0 || ^0.2.0": - "integrity" "sha512-ZkcWZudylwF+ir3Ld1n7gL6bI2mQAzXvSobPwVtu8aYi2sbXeipeSkdcanRLzIofLcM5F53lGaKm2dk7orBi7Q==" - "resolved" "https://registry.npmjs.org/murmur-32/-/murmur-32-0.2.0.tgz" - "version" "0.2.0" - dependencies: - "encode-utf8" "^1.0.3" - "fmix" "^0.1.0" - "imul" "^1.0.0" - -"nan@^2.4.0": - "integrity" "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" - "resolved" "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz" - "version" "2.17.0" - "nanoid@^3.3.4": "integrity" "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" @@ -4973,6 +4905,11 @@ "resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" "version" "3.2.1" +"node-addon-api@^7.0.0": + "integrity" "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==" + "resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz" + "version" "7.1.1" + "node-api-version@^0.1.4": "integrity" "sha512-KGXihXdUChwJAOHO53bv9/vXcLmdUsZ6jIptbvYvkpKfth+r7jw44JkVxQFA3kX5nQjzjmGu1uAu/xNNLNlI5g==" "resolved" "https://registry.npmjs.org/node-api-version/-/node-api-version-0.1.4.tgz" @@ -5307,13 +5244,6 @@ dependencies: "author-regex" "^1.0.0" -"parse-color@^1.0.0": - "integrity" "sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==" - "resolved" "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz" - "version" "1.0.0" - dependencies: - "color-convert" "~0.5.0" - "parse-json@^2.2.0": "integrity" "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==" "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" @@ -5576,14 +5506,6 @@ "resolved" "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" "version" "5.1.1" -"random-path@^0.1.0": - "integrity" "sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==" - "resolved" "https://registry.npmjs.org/random-path/-/random-path-0.1.2.tgz" - "version" "0.1.2" - dependencies: - "base32-encode" "^0.1.0 || ^1.0.0" - "murmur-32" "^0.1.0 || ^0.2.0" - "randombytes@^2.1.0": "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" @@ -5613,7 +5535,7 @@ dependencies: "cross-spawn-windows-exe" "^1.1.0" -"react-dom@^17.0.0 || ^18.0.0", "react-dom@^18.2.0", "react-dom@>=16.6.0": +"react-dom@^17.0.0 || ^18.0.0", "react-dom@^18.2.0", "react-dom@>=16.6.0", "react-dom@>=16.8.0": "integrity" "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==" "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" "version" "18.2.0" @@ -5692,6 +5614,11 @@ "string_decoder" "^1.1.1" "util-deprecate" "^1.0.1" +"readdirp@^4.0.1": + "integrity" "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" + "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz" + "version" "4.1.2" + "readdirp@~3.6.0": "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==" "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" @@ -5741,11 +5668,6 @@ "lodash" "^4.17.21" "strip-ansi" "^6.0.1" -"repeat-string@^1.5.4": - "integrity" "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" - "resolved" "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" - "version" "1.6.1" - "require-directory@^2.1.1": "integrity" "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" @@ -5904,6 +5826,24 @@ "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" "version" "2.1.2" +"sass-loader@^13.2.0": + "integrity" "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==" + "resolved" "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz" + "version" "13.3.3" + dependencies: + "neo-async" "^2.6.2" + +"sass@^1.3.0", "sass@^1.93.2": + "integrity" "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==" + "resolved" "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz" + "version" "1.93.2" + dependencies: + "chokidar" "^4.0.0" + "immutable" "^5.0.2" + "source-map-js" ">=0.6.2 <2.0.0" + optionalDependencies: + "@parcel/watcher" "^2.4.1" + "scheduler@^0.23.0": "integrity" "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==" "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" @@ -6144,7 +6084,7 @@ "ip" "^2.0.0" "smart-buffer" "^4.2.0" -"source-map-js@^1.0.2": +"source-map-js@^1.0.2", "source-map-js@>=0.6.2 <2.0.0": "integrity" "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" "version" "1.0.2" @@ -6238,11 +6178,6 @@ "resolved" "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" "version" "2.0.1" -"stream-buffers@~2.2.0": - "integrity" "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==" - "resolved" "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz" - "version" "2.2.0" - "string_decoder@^1.1.1": "integrity" "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -6446,18 +6381,6 @@ dependencies: "rimraf" "^3.0.0" -"tn1150@^0.1.0": - "integrity" "sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==" - "resolved" "https://registry.npmjs.org/tn1150/-/tn1150-0.1.0.tgz" - "version" "0.1.0" - dependencies: - "unorm" "^1.4.1" - -"to-data-view@^1.1.0": - "integrity" "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==" - "resolved" "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz" - "version" "1.1.0" - "to-fast-properties@^2.0.0": "integrity" "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -6531,7 +6454,7 @@ "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" "version" "1.14.1" -"tslib@^2.0.3", "tslib@^2.1.0": +"tslib@^2.0.0", "tslib@^2.0.3", "tslib@^2.1.0": "integrity" "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" "version" "2.5.0" @@ -6636,11 +6559,6 @@ "resolved" "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" "version" "2.0.0" -"unorm@^1.4.1": - "integrity" "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" - "resolved" "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz" - "version" "1.6.0" - "unpipe@~1.0.0", "unpipe@1.0.0": "integrity" "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" "resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" @@ -6964,11 +6882,6 @@ "resolved" "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz" "version" "15.1.1" -"xtend@^4.0.0": - "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - "resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" - "version" "4.0.2" - "xterm-addon-fit@^0.5.0": "integrity" "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==" "resolved" "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz"