diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9f1f131d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vite \ No newline at end of file diff --git a/Client/package-lock.json b/Client/package-lock.json index 2ad129bd4..fe3d684f5 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -527,358 +527,6 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", @@ -975,9 +623,9 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.4.tgz", - "integrity": "sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", + "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", "dependencies": { "@floating-ui/core": "^1.0.0", "@floating-ui/utils": "^0.2.0" @@ -1476,208 +1124,13 @@ } }, "node_modules/@remix-run/router": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz", - "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", "engines": { "node": ">=14.0.0" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", @@ -2981,20 +2434,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4186,9 +3625,9 @@ ] }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -4197,15 +3636,15 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^18.2.0" } }, "node_modules/react-is": { @@ -4223,11 +3662,11 @@ } }, "node_modules/react-router": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.0.tgz", - "integrity": "sha512-wPMZ8S2TuPadH0sF5irFGjkNLIcRvOSaEe7v+JER8508dyJumm6XZB1u5kztlX0RVq6AzRVndzqcUh6sFIauzA==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", "dependencies": { - "@remix-run/router": "1.16.0" + "@remix-run/router": "1.16.1" }, "engines": { "node": ">=14.0.0" @@ -4237,12 +3676,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.0.tgz", - "integrity": "sha512-Q9YaSYvubwgbal2c9DJKfx6hTNoBp3iJDsl+Duva/DwxoJH+OTXkxGpql4iUK2sla/8z4RpjAm6EWx1qUDuopQ==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", "dependencies": { - "@remix-run/router": "1.16.0", - "react-router": "6.23.0" + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" }, "engines": { "node": ">=14.0.0" diff --git a/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx new file mode 100644 index 000000000..f3363e866 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx @@ -0,0 +1,71 @@ +import "./announcementUpdateSubscription.css"; +import React from "react"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - Title text for the update subscription dialog (required) + * @param {string} props.text - Body text for the update subscription dialog (required) + * @param {string} props.cancel - Text for the negative (cancel) button (required) + * @param {string} props.positive - Text for the positive button (required) + * @param {string} props.header - Title text for the email subscription section (required) + * @param {string} props.button - Text for the subscribe button (required) + * @returns {JSX.Element} - Renders the announcement update subscription component + */ + +const AnnouncementUpdateSubscription = ({ + title, + text, + cancel, + positive, + header, + button, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{title}
+
+
{text}
+
+
+ + +
+
+
+
+
{header}
+
+ + +
+
+
+ ); +}; + +AnnouncementUpdateSubscription.propTypes = { + title: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + cancel: PropTypes.string.isRequired, + positive: PropTypes.string.isRequired, + header: PropTypes.string.isRequired, + button: PropTypes.string.isRequired, +}; + +export default AnnouncementUpdateSubscription; diff --git a/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css new file mode 100644 index 000000000..7974ee799 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css @@ -0,0 +1,99 @@ +:root { + --update-subscription-color-0: #101828; + --update-subscription-color-1: #475467; + --update-subscription-color-2: #fff; + --update-subscription-color-3: #eaecf0; + --update-subscription-color-4: #7f56d9; + --update-subscription-color-5: #1570ef; + --update-subscription-color-6: #344054; + --update-subscription-color-7: #d0d5dd; + --update-subscription-padding-0: 12px 16px; + --update-subscription-margin-right: 12px; + --update-subscription-font-size: 13px; + --update-subscription-radius-0: 4px; + --spacing-1: 16px; + --spacing-2: 20px; +} + +.update-subscription, +.update-subscription-dialog { + max-width: 770px; + border-radius: 4px; + border: 1px solid #eaecf0; +} + +.update-subscription-dialog { + padding: 15px 30px; +} + +.subscription-dialog-title { + font-size: 1rem; + font-weight: 700; + color: var(--update-subscription-color-0); +} + +.v-spacing-small { + height: 10px; +} + +.v-spacing-medium { + height: 15px; +} + +.subscription-dialog-text { + font-size: 13px; + color: var(--update-subscription-color-1); +} + +.subscription-dialog-controls { + display: flex; +} + +.controls-negative { + padding: var(--update-subscription-padding-0); + margin-right: var(--update-subscription-margin-right); + border-radius: var(--update-subscription-radius-0); + border: 1px solid var(--update-subscription-color-3); + background-color: var(--update-subscription-color-2); + font-size: var(--update-subscription-font-size); +} + +.controls-positive, +.subscribe-button { + padding: var(--update-subscription-padding-0); + margin-right: var(--update-subscription-margin-right); + border-radius: var(--update-subscription-radius-0); + border: 1px solid var(--update-subscription-color-4); + background-color: var(--update-subscription-color-5); + color: var(--update-subscription-color-2); + font-size: var(--update-subscription-font-size); +} + +.update-subscription-title { + color: var(--update-subscription-color-6); + padding: 0 var(--spacing-2); + font-weight: 700; + font-size: 13px; + margin-bottom: 10px; +} + +.subscription-email { + display: flex; + padding: 0 var(--spacing-2); +} + +.subscription-email-field { + width: 290px; + height: 24px; + border-radius: var(--update-subscription-radius-0); + border: 1px solid var(--update-subscription-color-7); + box-shadow: 0px 1px 2px 0px rgba(101, 182, 28, 0.05); + padding: 5px 15px; + margin-right: var(--spacing-2); +} + +.subscribe-button { + width: 100px; + height: 34px; + padding: 2px 15px; +} diff --git a/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx b/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx new file mode 100644 index 000000000..2abbadb1e --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx @@ -0,0 +1,55 @@ +import "./announcementsDualButton.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.subject - The announcement subject text + * @param {string} props.body - The announcement body text content + * @param {string} props.esc - The text for the escape button + * @param {string} props.primary - The text for the primary button + * @returns {JSX.Element} - Renders the announcement dual button component + */ + +const AnnouncementsDualButton = ({ subject, body, esc, primary }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{subject}
+
+
{body}
+
+
{esc}
+
{primary}
+
+
+
+
+ +
+
+ ); +}; + +AnnouncementsDualButton.propTypes = { + subject: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + primary: PropTypes.string.isRequired, +}; + +export default AnnouncementsDualButton; diff --git a/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css b/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css new file mode 100644 index 000000000..837fd0bb5 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css @@ -0,0 +1,38 @@ +:root { + --announcement-border-color: #d0d5dd; + --announcement-border-radius: 4px; + --announcement-border-radius-2: 8px; + /* --announcement-font-family: "Roboto", "Helvetica", "Arial", sans-serif; */ + --announcement-font-size-0: 13px; + --announcement-font-color-0: #344054; + --announcement-font-color-1: #475467; + --announcement-font-color-2: #1570ef; + --announcement-padding: 16px; + --info-icon-frame-color: #eaecf0; +} + +.announcement-without-tile { + max-width: 343px; + width: fit-content; + display: flex; + border: 1px solid var(--announcement-border-color); + /* font-family: var(--announcement-font-family); */ + padding: var(--announcement-padding); + border-radius: var(--announcement-border-radius); +} + +.h-spacing { + width: 20px; +} + +.announcement-without-content-subject { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-0); + font-weight: 700; + margin-bottom: 10px; +} + +.announcement-without-content-body { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-1); +} diff --git a/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon.jsx b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon.jsx new file mode 100644 index 000000000..574c255a0 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon.jsx @@ -0,0 +1,65 @@ +import "./announcementsDualButtonWithIcon.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {React.ReactNode} props.icon - Optional React node for an announcement icon + * @param {string} props.subject - The announcement subject text + * @param {string} props.body - The announcement body text content + * @param {string} props.esc - The text for the escape button (usually "Close") + * @param {string} props.primary - The text for the primary button + * @returns {JSX.Element} - Renders the announcement dual button with icon component + */ + +const AnnouncementsDualButtonWithIcon = ({ + icon, + subject, + body, + esc, + primary, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+ {icon &&
{icon}
} +
+ {subject && ( +
{subject}
+ )} + {body &&
{body}
} + {(esc || primary) && ( +
+ {esc &&
{esc}
} + {primary && ( +
{primary}
+ )} +
+ )} +
+
+ +
+
+ ); +}; + +AnnouncementsDualButtonWithIcon.propTypes = { + icon: PropTypes.object, + subject: PropTypes.string, + body: PropTypes.string, + esc: PropTypes.string, + primary: PropTypes.string, +}; + +export default AnnouncementsDualButtonWithIcon; diff --git a/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css new file mode 100644 index 000000000..80c6ae265 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css @@ -0,0 +1,69 @@ +:root { + --announcement-border-color: #d0d5dd; + --announcement-border-radius: 4px; + --announcement-border-radius-2: 8px; + --announcement-font-size-0: 13px; + --announcement-font-color-0: #344054; + --announcement-font-color-1: #475467; + --announcement-font-color-2: #1570ef; + --announcement-padding: 16px; + --info-icon-frame-color: #eaecf0; +} + +.announcement-tile { + width: fit-content; + display: flex; + border: 1px solid var(--announcement-border-color); + padding: var(--announcement-padding); + border-radius: var(--announcement-border-radius); +} + +.info-icon-frame { + display: flex; + width: 40px; + height: 40px; + border: 1px solid var(--info-icon-frame-color); + border-radius: var(--announcement-border-radius-2); + justify-content: center; + align-items: center; +} + +.announcement-content { + padding: 0 var(--announcement-padding); +} + +.announcement-content-subject { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-0); + font-weight: 700; + margin-bottom: 10px; +} + +.announcement-content-body { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-1); + font-weight: 300; +} + +.announcement-content-controllers { + display: flex; + font-size: var(--announcement-font-size-0); + margin-top: 15px; +} + +.controllers-button-esc { + font-size: var(--announcement-font-size-0); + font-weight: 600; + margin-right: 12px; +} + +.controllers-button-primary { + font-size: var(--announcement-font-size-0); + font-weight: 600; + color: var(--announcement-font-color-2); +} + +.announcement-close { + width: 24px; + height: 24px; +} diff --git a/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx b/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx new file mode 100644 index 000000000..20a179052 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx @@ -0,0 +1,36 @@ +import "./announcementsMessageBar.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.message - The announcement message text content (required) + * @returns {JSX.Element} - Renders the announcement message bar component + */ +const AnnouncementsMessageBar = ({ message }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{message}
+
+ +
+
+ ); +}; + +AnnouncementsMessageBar.propTypes = { + message: PropTypes.string.isRequired, +}; + +export default AnnouncementsMessageBar; diff --git a/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css b/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css new file mode 100644 index 000000000..2e9f95e83 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css @@ -0,0 +1,12 @@ +:root { + --announcement-font-size-0: 13px; + --announcement-padding: 16px; +} + +.announcement-messagebar-body { + font-size: var(--announcement-font-size-0); + padding: 0 var(--announcement-padding) 0 0; + justify-content: center; + align-items: center; + margin: auto; +} diff --git a/Client/src/Components/Charts/Servers/ServerStatus.jsx b/Client/src/Components/Charts/Servers/ServerStatus.jsx new file mode 100644 index 000000000..f910abf27 --- /dev/null +++ b/Client/src/Components/Charts/Servers/ServerStatus.jsx @@ -0,0 +1,37 @@ +import React from "react"; +import "./serverStatus.css"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the server status (required) + * @param {string} props.value - The value text to be displayed (required) + * @param {string} props.state - The state of the server (e.g., "online", "offline", "warning") (required) + * @returns {JSX.Element} - Renders the server status component + */ +const ServerStatus = ({ title, value, state }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+
{value}
+
+ ); +}; + +ServerStatus.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + state: PropTypes.string.isRequired, +}; + +export default ServerStatus; diff --git a/Client/src/Components/Charts/Servers/serverStatus.css b/Client/src/Components/Charts/Servers/serverStatus.css new file mode 100644 index 000000000..9126d9b3b --- /dev/null +++ b/Client/src/Components/Charts/Servers/serverStatus.css @@ -0,0 +1,44 @@ +:root { + --spacing-general-0: 10px 25px; + --spacing-general-1: 20px; + --color-border-0: #eaecf0; + --border-radius-0: 4px; + --font-size-0: 1rem; + --font-size-2: 36px; + + --color-up: #17b26a; + --color-down: #f04438; + --color-pause: #fdb022; +} + +.server-status-tile { + width: 230px; + margin: var(--spacing-general-0); + margin-left: 10px; + padding: var(--spacing-general-1); + border: 1px solid var(--color-border-0); + border-radius: var(--border-radius-0); +} + +.server-status-tile-title { + font-size: var(--font-size-0); + font-weight: bold; + margin-bottom: 25px; +} + +.server-status-tile-value { + font-size: var(--font-size-2); + font-weight: bolder; +} + +.up { + color: var(--color-up); +} + +.down { + color: var(--color-down); +} + +.pause { + color: var(--color-pause); +} diff --git a/Client/src/Components/Charts/Statistics/Statistic.jsx b/Client/src/Components/Charts/Statistics/Statistic.jsx new file mode 100644 index 000000000..99ad2066f --- /dev/null +++ b/Client/src/Components/Charts/Statistics/Statistic.jsx @@ -0,0 +1,35 @@ +import React from "react"; +import "./statistic.css"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the statistic (required) + * @param {string} props.value - The numerical or textual value for the statistic (required) + * @returns {JSX.Element} - Renders the statistic component + */ +const Statistic = ({ title, value }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+
{value}
+
+ ); +}; + +Statistic.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, +}; + +export default Statistic; diff --git a/Client/src/Components/Charts/Statistics/statistic.css b/Client/src/Components/Charts/Statistics/statistic.css new file mode 100644 index 000000000..a8834199d --- /dev/null +++ b/Client/src/Components/Charts/Statistics/statistic.css @@ -0,0 +1,31 @@ +:root { + --stats-spacing-general-0: 5px 10px; + --color-border-0: #eaecf0; + --border-radius-0: 4px; + --font-size-0: 1rem; + --font-size-1: 13px; + --font-color-0: #344054; + --margin-bottom-0: 10px; +} + +.statistic-tile { + margin: var(--stats-spacing-general-0); + padding: var(--stats-spacing-general-0); + border: 1px solid var(--color-border-0); + border-radius: var(--border-radius-0); + + width: 180px; +} + +.statistic-tile-title { + font-size: var(--font-size-0); + color: var(--font-color-0); + margin-bottom: var(--margin-bottom-0); +} + +.statistic-tile-value { + font-size: var(--font-size-1); + color: var(--font-color-0); + font-weight: 700; + margin-bottom: var(--margin-bottom-0); +} diff --git a/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx b/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx new file mode 100644 index 000000000..67af3ab88 --- /dev/null +++ b/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx @@ -0,0 +1,36 @@ +import "./complexAlert.css"; +import React from "react"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import PropTypes from "prop-types"; + +/** + * @component + * @param {Object} props + * @param {"red" | "green"} props.theme - The color theme for the alert (required) - must be either "red" or "green" + * @returns {JSX.Element} - Renders the complex alert component with dynamic color theme + */ +const ComplexAlert = ({ theme }) => { + if (theme === "red") { + return ( +
+
+ +
+
+ ); + } else if (theme === "green") { + return ( +
+
+ +
+
+ ); + } +}; + +ComplexAlert.propTypes = { + theme: PropTypes.string.isRequired, +}; + +export default ComplexAlert; diff --git a/Client/src/Components/Icons/ComplexAlert/complexAlert.css b/Client/src/Components/Icons/ComplexAlert/complexAlert.css new file mode 100644 index 000000000..ab3cea714 --- /dev/null +++ b/Client/src/Components/Icons/ComplexAlert/complexAlert.css @@ -0,0 +1,44 @@ +.icon-holder-outer-red { + width: 38px; + height: 38px; + border-radius: 50%; + border: 2px solid #d92d2019; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-inner-red { + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid #d92d204d; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-outer-green { + width: 38px; + height: 38px; + border-radius: 50%; + border: 2px solid #07945519; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-inner-green { + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid #0794554d; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-core { + width: 20px; + height: 20px; +} diff --git a/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx b/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx new file mode 100644 index 000000000..42a3f2a8a --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx @@ -0,0 +1,55 @@ +import "./dualButtonPopupModal.css"; +import React from "react"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {boolean} [props.open=true] - Controls the visibility of the modal (defaults to true) + * @param {string} props.subject - The title text for the modal (required) + * @param {string} props.description - The description text for the modal (required) + * @param {string} props.esc - The text for the discard button (usually "Cancel", "Dismiss" or "Discard") (required) + * @param {string} props.save - The text for the save button (required) + * @returns {JSX.Element} - Renders the dual button popup modal component + */ +const DualButtonPopupModal = ({ + open = true, + subject, + description, + esc, + save, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{subject}
+
{description}
+
+
+ + +
+
+ ); +}; + +DualButtonPopupModal.propTypes = { + open: PropTypes.bool, + subject: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + save: PropTypes.string.isRequired, +}; + +export default DualButtonPopupModal; diff --git a/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css b/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css new file mode 100644 index 000000000..92ac7f5d6 --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css @@ -0,0 +1,60 @@ +:root { + --popup-color-border-0: #f2f2f2; + --popup-color-0: #101828; + --popup-color-1: #475467; + --color-0: #1570ef; + --color-1: #175cd3; +} + +.dual-button-popup-modal-holder { + width: 380px; + height: 130px; + margin: 10px 20px; + padding: 30px; + box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03), + 0px 20px 24px -4px rgba(16, 24, 40, 0.08); + border: 1px solid var(--popup-color-border-0); + border-radius: 4px; +} + +.dual-button-popup-modal-subject { + color: var(--popup-color-0); + font-weight: bolder; + font-size: 16px; +} + +.dual-button-popup-modal-description { + color: var(--popup-color-1); + font-size: 13px; + margin-top: 10px; +} + +.dual-modal-spacing { + height: 40px; +} + +.dual-button-popup-modal-controllers { + display: flex; + justify-content: end; +} + +.blue-save-button { + width: 145px; + height: 35px; + padding: 5px 20px; + background-color: var(--color-0); + border: 1px solid var(--color-1); + border-radius: 4px; + margin: 5px 0; + margin-left: 20px; + color: white; + cursor: pointer; + font-size: 13px; +} + +.transparent-discard-button { + border: none; + background-color: transparent; + margin: 5px 10px; + font-size: 13px; +} diff --git a/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx new file mode 100644 index 000000000..b8b424323 --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx @@ -0,0 +1,73 @@ +import "./dualButtonPopupModalWithTextfields.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the modal (required) + * @returns {JSX.Element} - Renders a single text field component within a popup modal + */ +const PopupModalTextfield = ({ title }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+ +
+ ); +}; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the modal (required) + * @param {string} props.esc - The text for the cancel button (required) + * @param {string} props.save - The text for the save button (required) + * @returns {JSX.Element} - Renders the dual button popup modal component with text fields + */ +const DualButtonPopupModalWithTextfields = ({ title, esc, save }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{title}
+
+ +
+
+
+ +
+
+
+ + +
+
+ ); +}; + +DualButtonPopupModalWithTextfields.propTypes = { + title: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + save: PropTypes.string.isRequired, +}; + +export default DualButtonPopupModalWithTextfields; diff --git a/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css new file mode 100644 index 000000000..a1be3cd3a --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css @@ -0,0 +1,61 @@ +:root { + --popup-color-with-input-border-0: #f2f2f2; + --popup-color-with-input-border-1: #d0d5dd; + --popup-modal-with-input-title-color: #344054; +} + +.popup-modal-holder { + width: 480px; + font-family: var(--popup-font-family-0); + padding: 50px 40px; + border-radius: 4px; + margin: 10px 20px; + border: 1px solid var(--popup-color-with-input-border-0); + box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03), + 0px 20px 24px -4px rgba(16, 24, 40, 0.08); +} + +.popup-modal-header { + display: flex; + justify-content: space-between; + font-weight: bold; +} + +.popup-modal-close { + cursor: pointer; +} + +.spacing-height { + height: 30px; +} + +.popup-modal-input-title { + margin-bottom: 15px; + color: var(--popup-modal-with-input-title-color); +} + +.popup-modal-text-field { + width: 100%; + height: 35px; + border: 1px solid var(--popup-color-with-input-border-1); + border-radius: 4px; +} + +.popup-modal-controllers { + display: flex; + justify-content: end; +} + +.white-cancel-button { + border: none; + background-color: transparent; + font-family: var(--popup-font-family-0); + margin: 5px 10px; + width: 145px; + height: 35px; + padding: 5px 20px; + border: 1px solid var(--popup-color-with-input-border-1); + border-radius: 4px; + cursor: pointer; + font-size: 13px; +} diff --git a/Client/src/Components/TextFields/Description/DescriptionTextField.jsx b/Client/src/Components/TextFields/Description/DescriptionTextField.jsx new file mode 100644 index 000000000..7f3ba908a --- /dev/null +++ b/Client/src/Components/TextFields/Description/DescriptionTextField.jsx @@ -0,0 +1,47 @@ +import React from "react"; +import "./descriptionTextField.css"; +import { TextField } from "@mui/material"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.hintText - The hint text displayed within the text field (required) + * @param {boolean} props.hasError - A flag indicating if the text field has an error (required) + * @returns {JSX.Element} - Renders the description text field component + */ +const DescriptionTextField = ({ hintText, hasError }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
Description
+ +
+ ); +}; + +DescriptionTextField.propTypes = { + hintText: PropTypes.string.isRequired, + hasError: PropTypes.bool.isRequired, +}; + +export default DescriptionTextField; diff --git a/Client/src/Components/TextFields/Description/descriptionTextField.css b/Client/src/Components/TextFields/Description/descriptionTextField.css new file mode 100644 index 000000000..28616863e --- /dev/null +++ b/Client/src/Components/TextFields/Description/descriptionTextField.css @@ -0,0 +1,45 @@ +:root { + --color-title-1: #344054; + --text-field-margin-0: 10px 20px; + --description-color-0: #344054; +} + +.description-field-holder { + margin: var(--text-field-margin-0); + margin-top: 20px; +} + +.text-field-title { + color: var(--color-title-1); + font-weight: bold; + margin-bottom: 10px; + font-size: 13px; + color: var(--description-color-0); + font-weight: bold; +} + +.description-field-area { + min-width: 320px; + font-size: 13px; + border-radius: 8px; +} + +.description-field-label { + margin-top: 10px; + font-size: 11px; +} + +.with-error { + color: red; +} + +#description-field-area-helper-text { + margin-left: 0; + margin-top: 10px; + font-size: 11px; +} + +#description-field-area { + min-width: 320px; + font-size: 13px; +} diff --git a/Client/src/Components/TextFields/Email/EmailTextField.jsx b/Client/src/Components/TextFields/Email/EmailTextField.jsx new file mode 100644 index 000000000..b1428e1c5 --- /dev/null +++ b/Client/src/Components/TextFields/Email/EmailTextField.jsx @@ -0,0 +1,88 @@ +import React, { useState } from "react"; +import "./emailTextField.css"; +import { InputAdornment, TextField } from "@mui/material"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.id - Unique ID for the text field (optional) + * @param {string} props.label - The label text displayed above the text field (optional) + * @param {"standard" | "outlined" | "filled"} props.variant - The variant of the text field (e.g., "outlined") (optional) + * @param {string} props.placeholder - The placeholder text displayed within the text field (optional) + * @param {"error" | "help"} [props.icon] - The type of icon to display (error or help) (optional) + * @param {string} props.helperText - The helper text displayed below the text field (optional) + * @param {boolean} props.error - A flag indicating if the text field has an error (required) + * @returns {JSX.Element} - Renders the email text field component with dynamic icon display + */ +const EmailTextField = ({ + id, + label, + variant, + placeholder, + icon, + helperText, + error, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + const [showIcon, setShowIcon] = useState(false); + + const handleMouseEnter = () => setShowIcon(true); + const handleMouseLeave = () => setShowIcon(false); + + return ( +
+
Email
+
+ +
+ {error && showIcon && ( + + )} + {error && !showIcon && ( + + )} + {!error && showIcon && ( + + )} +
+ + ), + }} + helperText={helperText} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + /> +
+
+ ); +}; + +export default EmailTextField; diff --git a/Client/src/Components/TextFields/Email/emailTextField.css b/Client/src/Components/TextFields/Email/emailTextField.css new file mode 100644 index 000000000..ff38a29df --- /dev/null +++ b/Client/src/Components/TextFields/Email/emailTextField.css @@ -0,0 +1,41 @@ +:root { + --textfield-color-0: #344054; +} + +.email-text-field { + position: relative; + margin: 10px 20px; +} + +#outlined-basic { + width: 320px; + height: 14px; + font-size: 13px; + padding: 8px 12px; +} + +.email-text-field-title { + margin: 0 20px; + margin-top: 30px; + font-size: 13px; + color: var(--textfield-color-0); + font-weight: bold; +} + +#outlined-basic-helper-text { + margin-left: 0; + margin-top: 10px; + font-size: 11px; +} + +.text-field-icon { + width: 16px; + height: 16px; +} + +.icon-holder { + width: 16px; + height: 16px; + padding: 0; + margin: 0; +} diff --git a/Client/src/Components/TextFields/Website/WebsiteTextField.jsx b/Client/src/Components/TextFields/Website/WebsiteTextField.jsx new file mode 100644 index 000000000..d18e33dd9 --- /dev/null +++ b/Client/src/Components/TextFields/Website/WebsiteTextField.jsx @@ -0,0 +1,72 @@ +import React, { useState } from "react"; +import "./websiteTextField.css"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import ContentCopyIcon from "@mui/icons-material/ContentCopy"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {boolean} [props.showHelp=true] - Controls the visibility of the help icon (defaults to true) + * @param {boolean} [props.hasCopyButton=false] - Controls the visibility of the copy button (defaults to false) + * @param {string} props.hintText - The hint text displayed below the text field (required) + * @returns {JSX.Element} - Renders the website text field component with optional help and copy features + */ +const WebsiteTextField = ({ + showHelp = true, + hasCopyButton = false, + hintText, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + const [copied, setCopied] = useState(false); + + const handleCopy = () => { + setCopied(true); + setTimeout(() => setCopied(false), 1000); + }; + + return ( +
+
Website
+
+ + + {showHelp && ( +
+ +
+ )} + {hasCopyButton && ( +
+ + {copied ? " Copied " : " Copy "} +
+ )} +
+ +
+ ); +}; + +export default WebsiteTextField; diff --git a/Client/src/Components/TextFields/Website/websiteTextField.css b/Client/src/Components/TextFields/Website/websiteTextField.css new file mode 100644 index 000000000..66cdf4fa4 --- /dev/null +++ b/Client/src/Components/TextFields/Website/websiteTextField.css @@ -0,0 +1,82 @@ +:root { + --website-color-0: #344054; + --border-color: #d0d5dd; + --label-font-color: #475467; + --icon-color: #98a2b3; + --text-field-margin-0: 10px 20px; + --text-field-margin-1: 10px 20px 5px; +} + +.website-textfield-title { + margin: 0 20px; + margin-top: 30px; + font-size: 13px; + color: var(--website-color-0); + font-weight: bold; +} + +.website-textfield { + display: flex; + align-items: center; + position: relative; + margin: var(--text-field-margin-1); +} + +.website-textfield-hint { + margin: var(--text-field-margin-0); + font-size: 11px; +} + +.website-label { + padding: 6px 20px 6px 10px; + border: solid 1px var(--border-color); + border-right: none; + border-radius: 4px 0 0 4px; + font-size: 13px; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + color: var(--label-font-color); +} + +.website-url { + width: 248px; + height: 31.5px; + padding: 0px 15px; + border: solid 1px var(--border-color); +} + +.website-icon-holder { + width: 40px; + height: 33px; + padding: 5px; + border: solid 1px var(--border-color); + border-left: none; + text-align: center; + display: flex; + justify-content: center; + align-items: center; +} + +.copy-to-clipboard-button { + padding: 5.5px 20px 6px 10px; + border: solid 1px var(--border-color); + border-left: none; + border-radius: 0 8px 8px 0; + font-size: 13px; + text-align: center; + display: flex; + justify-content: space-evenly; + align-items: center; + color: var(--label-font-color); + cursor: pointer; +} + +.copy-icon { + margin-right: 5px; +} + +.with-no-copy-button { + display: none; +} diff --git a/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx b/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx new file mode 100644 index 000000000..1b1fb8b4d --- /dev/null +++ b/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx @@ -0,0 +1,45 @@ +import "./tooltipWithTail.css"; +import React from "react"; +import { styled } from "@mui/material/styles"; +import Tooltip, { tooltipClasses } from "@mui/material/Tooltip"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; + +const CustomizedTooltip = styled( + ({ className, placement, arrow, ...props }) => ( + + ) +)(({ theme }) => ({ + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: "black", + }, + [`& .${tooltipClasses.arrow}`]: { + color: "black", + }, +})); + +function TooltipWithTail({ placement, arrow = false, title, text }) { + return ( +
+ + {title &&
{title}
} +
{text}
+ + } + className="tooltip-holder" + > + +
+
+ ); +} + +export default TooltipWithTail; diff --git a/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css b/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css new file mode 100644 index 000000000..1b1adf507 --- /dev/null +++ b/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css @@ -0,0 +1,17 @@ +:root { + --tooltip-color-0: #d0d5dd; + --tooltip-margin: 5px; + --tooltip-font-size: 12px; +} + +.tooltip-title { + font-size: var(--tooltip-font-size); + font-weight: bold; + margin: var(--tooltip-margin); +} + +.tooltip-description { + font-size: var(--tooltip-font-size); + color: var(--tooltip-color-0); + margin: var(--tooltip-margin); +} diff --git a/Client/src/Pages/PlayGround/PlayGround-Charts.jsx b/Client/src/Pages/PlayGround/PlayGround-Charts.jsx new file mode 100644 index 000000000..906f2a84a --- /dev/null +++ b/Client/src/Pages/PlayGround/PlayGround-Charts.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import "./playGround.css"; +import Statistic from "../../Components/Charts/Statistics/Statistic"; +import ServerStatus from "../../Components/Charts/Servers/ServerStatus"; + +function PlayGroundCharts() { + return ( + <> +
+ + + + +
+
+
+ + + +
+ + ); +} + +export default PlayGroundCharts; diff --git a/Client/src/Pages/PlayGround/PlayGround-Popup-Modals.jsx b/Client/src/Pages/PlayGround/PlayGround-Popup-Modals.jsx new file mode 100644 index 000000000..a3b89349c --- /dev/null +++ b/Client/src/Pages/PlayGround/PlayGround-Popup-Modals.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import DualButtonPopupModal from "../../Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal"; +import DualButtonPopupModalWithTextfields from "../../Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields"; + +function PlayGroundPopupModals() { + return ( +
+ +
+
+ +
+ ); +} + +export default PlayGroundPopupModals; diff --git a/Client/src/Pages/PlayGround/PlayGround-Tooltips.jsx b/Client/src/Pages/PlayGround/PlayGround-Tooltips.jsx new file mode 100644 index 000000000..3713f889c --- /dev/null +++ b/Client/src/Pages/PlayGround/PlayGround-Tooltips.jsx @@ -0,0 +1,34 @@ +import React from "react"; +import TooltipWithTail from "../../Components/Tooltips/TooltipWithTail/TooltipWithTail"; +import "./playGround.css"; + +function PlayGroundTooltips() { + return ( +
+
+ +
+ +
+ +
+ +
+ ); +} + +export default PlayGroundTooltips; diff --git a/Client/src/Pages/PlayGround/PlayGround-announcements.jsx b/Client/src/Pages/PlayGround/PlayGround-announcements.jsx new file mode 100644 index 000000000..aa4bd1913 --- /dev/null +++ b/Client/src/Pages/PlayGround/PlayGround-announcements.jsx @@ -0,0 +1,73 @@ +import "./playGround.css"; +import React from "react"; +import AnnouncementsDualButtonWithIcon from "../../Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +import ComplexAlert from "../../Components/Icons/ComplexAlert/ComplexAlert"; +import AnnouncementsMessageBar from "../../Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar"; +import AnnouncementsDualButton from "../../Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton"; +import AnnouncementUpdateSubscription from "../../Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription"; + +function PlayGroundAnnouncements() { + return ( +
+ + +
+ } + subject="We’ve just released a new feature" + body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid + pariatur, ipsum dolor." + esc="Dismiss" + primary="View changes" + /> +
+
+ } + subject="There was a problem with that action" + body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid + pariatur, ipsum dolor." + esc="Dismiss" + primary="Learn more" + /> +
+
+ } + subject="Successfully updated profile" + body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid + pariatur, ipsum dolor." + esc="Dismiss" + primary="Learn more" + /> +
+
+ +
+
+ +
+
+ +
+
+
+ ); +} + +export default PlayGroundAnnouncements; diff --git a/Client/src/Pages/PlayGround/PlayGround.jsx b/Client/src/Pages/PlayGround/PlayGround.jsx new file mode 100644 index 000000000..29f4ebe5d --- /dev/null +++ b/Client/src/Pages/PlayGround/PlayGround.jsx @@ -0,0 +1,63 @@ +import React from "react"; +import EmailTextField from "../../Components/TextFields/Email/EmailTextField"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import WebsiteTextField from "../../Components/TextFields/Website/WebsiteTextField"; +import DescriptionTextField from "../../Components/TextFields/Description/DescriptionTextField"; + +// This Component is just for the development and test +// purposes and just to see what my components look like while development +// and will be removed in the end +function PlayGround() { + return ( +
+ {/* Default state of Email Text Fields */} + + {/* Email Text Field when validation error occures */} + } + helperText="This is an error message" + /> + {/* Email Text Field while mouse hover */} + } + helperText="This is a hint text to help user." + /> +
+
+ {/* Now, illustration of the Website text fields */} +
+ + +
+
+
+ {/* Now, illustration of the Description text fields */} +
+ + +
+ ); +} + +export default PlayGround; diff --git a/Client/src/Pages/PlayGround/playGround.css b/Client/src/Pages/PlayGround/playGround.css new file mode 100644 index 000000000..cd6d5e87b --- /dev/null +++ b/Client/src/Pages/PlayGround/playGround.css @@ -0,0 +1,19 @@ +.play-ground-charts { + display: flex; +} + +.play-ground-charts-spacing { + height: 110px; +} + +.tooltip-playground { + margin: auto; + padding: 5%; + width: 5%; + justify-content: center; + text-align: center; +} + +.playground { + padding: 40px; +} diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js index 99a442dfb..068e24572 100644 --- a/Client/src/Utils/Theme.js +++ b/Client/src/Utils/Theme.js @@ -16,6 +16,10 @@ const labelRed = "#F04438"; //Section colros const sectionBorder = "#D0D5DD"; const sectionBg = "#F8F9F8"; + +// Global Font Family +const fontFamilyDefault = '"Roboto", "Helvetica", "Arial", sans-serif'; + const theme = createTheme({ palette: { primary: { @@ -48,6 +52,11 @@ const theme = createTheme({ bgColor: sectionBg, }, }, + font :{ + default: { + font: fontFamilyDefault, + }, + }, shape: { borderRadius: 4, }, diff --git a/Client/src/assets/icons/icon-red-error-0.svg b/Client/src/assets/icons/icon-red-error-0.svg new file mode 100644 index 000000000..f052582ba --- /dev/null +++ b/Client/src/assets/icons/icon-red-error-0.svg @@ -0,0 +1,3 @@ + + +