diff --git a/package.json b/package.json index de0a55d..a6387f3 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ }, "dependencies": { "@radix-ui/react-checkbox": "^1.3.2", + "@react-three/drei": "^10.1.2", + "@react-three/fiber": "^9.1.2", "@tailwindcss/vite": "^4.1.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -31,6 +33,7 @@ "swiper": "^11.2.6", "tailwind-merge": "^3.2.0", "tailwindcss": "^4.1.4", + "three": "^0.177.0", "vite-tsconfig-paths": "^5.1.4", "zustand": "^5.0.3" }, @@ -38,6 +41,7 @@ "@eslint/js": "^9.22.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/three": "^0.177.0", "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.22.0", "eslint-plugin-react-hooks": "^5.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d3aafd..214fbe4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@radix-ui/react-checkbox': specifier: ^1.3.2 version: 1.3.2(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-three/drei': + specifier: ^10.1.2 + version: 10.1.2(@react-three/fiber@9.1.2(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0))(@types/react@19.1.6)(@types/three@0.177.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0) + '@react-three/fiber': + specifier: ^9.1.2 + version: 9.1.2(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0) '@tailwindcss/vite': specifier: ^4.1.4 version: 4.1.7(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) @@ -71,12 +77,15 @@ importers: tailwindcss: specifier: ^4.1.4 version: 4.1.7 + three: + specifier: ^0.177.0 + version: 0.177.0 vite-tsconfig-paths: specifier: ^5.1.4 version: 5.1.4(typescript@5.7.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) zustand: specifier: ^5.0.3 - version: 5.0.5(@types/react@19.1.6)(react@19.1.0) + version: 5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) devDependencies: '@eslint/js': specifier: ^9.22.0 @@ -87,6 +96,9 @@ importers: '@types/react-dom': specifier: ^19.0.4 version: 19.1.5(@types/react@19.1.6) + '@types/three': + specifier: ^0.177.0 + version: 0.177.0 '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.5.0(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) @@ -204,6 +216,9 @@ packages: resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} engines: {node: '>=6.9.0'} + '@dimforge/rapier3d-compat@0.12.0': + resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==} + '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} @@ -434,6 +449,14 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@mediapipe/tasks-vision@0.10.17': + resolution: {integrity: sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==} + + '@monogrid/gainmap-js@3.1.0': + resolution: {integrity: sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==} + peerDependencies: + three: '>= 0.159.0' + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -560,6 +583,42 @@ packages: '@types/react': optional: true + '@react-three/drei@10.1.2': + resolution: {integrity: sha512-CCcLAqZEvYiUErOcJgGzovY3RH6KgdrqD4ubeAx1nyGbSPLnKR9a8ynYbPdtZhIyiWqGc07z+RYQzpaOfN4ZIA==} + peerDependencies: + '@react-three/fiber': ^9.0.0 + react: ^19 + react-dom: ^19 + three: '>=0.159' + peerDependenciesMeta: + react-dom: + optional: true + + '@react-three/fiber@9.1.2': + resolution: {integrity: sha512-k8FR9yVHV9kIF3iuOD0ds5hVymXYXfgdKklqziBVod9ZEJ8uk05Zjw29J/omU3IKeUfLNAIHfxneN3TUYM4I2w==} + peerDependencies: + expo: '>=43.0' + expo-asset: '>=8.4' + expo-file-system: '>=11.0' + expo-gl: '>=11.0' + react: ^19.0.0 + react-dom: ^19.0.0 + react-native: '>=0.78' + three: '>=0.156' + peerDependenciesMeta: + expo: + optional: true + expo-asset: + optional: true + expo-file-system: + optional: true + expo-gl: + optional: true + react-dom: + optional: true + react-native: + optional: true + '@rolldown/pluginutils@1.0.0-beta.9': resolution: {integrity: sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==} @@ -753,6 +812,9 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tweenjs/tween.js@23.1.3': + resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -765,12 +827,18 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/draco3d@1.4.10': + resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==} + '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/offscreencanvas@2019.7.3': + resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} + '@types/quill@1.3.10': resolution: {integrity: sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==} @@ -779,9 +847,23 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-reconciler@0.28.9': + resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} + peerDependencies: + '@types/react': '*' + '@types/react@19.1.6': resolution: {integrity: sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==} + '@types/stats.js@0.17.4': + resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} + + '@types/three@0.177.0': + resolution: {integrity: sha512-/ZAkn4OLUijKQySNci47lFO+4JLE1TihEjsGWPUT+4jWqxtwOPPEwJV1C3k5MEx0mcBPCdkFjzRzDOnHEI1R+A==} + + '@types/webxr@0.5.22': + resolution: {integrity: sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==} + '@typescript-eslint/eslint-plugin@8.32.1': resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -829,12 +911,23 @@ packages: resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@use-gesture/core@10.3.1': + resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==} + + '@use-gesture/react@10.3.1': + resolution: {integrity: sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==} + peerDependencies: + react: '>= 16.8.0' + '@vitejs/plugin-react@4.5.0': resolution: {integrity: sha512-JuLWaEqypaJmOJPLWwO335Ig6jSgC1FTONCWAxnqcQthLTK/Yc9aH6hr9z/87xciejbQcnP3GnA1FWUSWeXaeg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@webgpu/types@0.1.61': + resolution: {integrity: sha512-w2HbBvH+qO19SB5pJOJFKs533CdZqxl3fcGonqL321VHkW7W/iBo6H8bjDy6pr/+pbMwIu5dnuaAxH7NxBqUrQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -858,6 +951,12 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -873,6 +972,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -889,6 +991,11 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camera-controls@2.10.1: + resolution: {integrity: sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==} + peerDependencies: + three: '>=0.126.1' + caniuse-lite@1.0.30001718: resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} @@ -928,6 +1035,11 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -959,10 +1071,16 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + detect-gpu@5.0.70: + resolution: {integrity: sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + draco3d@1.5.7: + resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1091,6 +1209,12 @@ packages: picomatch: optional: true + fflate@0.6.10: + resolution: {integrity: sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==} + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1156,6 +1280,9 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + glsl-noise@0.0.0: + resolution: {integrity: sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1185,6 +1312,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hls.js@1.6.5: + resolution: {integrity: sha512-KMn5n7JBK+olC342740hDPHnGWfE8FiHtGMOdJPfUjRdARTWj9OB+8c13fnsf9sk1VtpuU2fKSgUjHvg4rNbzQ==} + html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} @@ -1201,6 +1331,9 @@ packages: peerDependencies: react: '*' + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1209,6 +1342,9 @@ packages: resolution: {integrity: sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -1237,6 +1373,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -1244,6 +1383,11 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + its-fine@2.0.0: + resolution: {integrity: sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==} + peerDependencies: + react: ^19.0.0 + jiti@2.4.2: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true @@ -1281,6 +1425,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -1377,6 +1524,12 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + maath@0.10.8: + resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==} + peerDependencies: + '@types/three': '>=0.134.0' + three: '>=0.134.0' + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -1388,6 +1541,14 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + meshline@3.3.1: + resolution: {integrity: sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==} + peerDependencies: + three: '>=0.137' + + meshoptimizer@0.18.1: + resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -1483,10 +1644,16 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + potpack@1.0.2: + resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + promise-worker-transferable@1.0.4: + resolution: {integrity: sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -1569,6 +1736,12 @@ packages: react: ^16 || ^17 || ^18 react-dom: ^16 || ^17 || ^18 + react-reconciler@0.31.0: + resolution: {integrity: sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^19.0.0 + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -1596,6 +1769,15 @@ packages: react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-use-measure@2.1.7: + resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} + peerDependencies: + react: '>=16.13' + react-dom: '>=16.13' + peerDependenciesMeta: + react-dom: + optional: true + react@19.1.0: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} @@ -1604,6 +1786,10 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1620,6 +1806,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} @@ -1655,6 +1844,15 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + stats-gl@2.4.2: + resolution: {integrity: sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==} + peerDependencies: + '@types/three': '*' + three: '*' + + stats.js@0.17.0: + resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1663,6 +1861,11 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + suspend-react@0.1.3: + resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==} + peerDependencies: + react: '>=17.0' + swiper@11.2.8: resolution: {integrity: sha512-S5FVf6zWynPWooi7pJ7lZhSUe2snTzqLuUzbd5h5PHUOhzgvW0bLKBd2wv0ixn6/5o9vwc/IkQT74CRcLJQzeg==} engines: {node: '>= 4.7.0'} @@ -1681,6 +1884,19 @@ packages: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} + three-mesh-bvh@0.8.3: + resolution: {integrity: sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==} + peerDependencies: + three: '>= 0.159.0' + + three-stdlib@2.36.0: + resolution: {integrity: sha512-kv0Byb++AXztEGsULgMAs8U2jgUdz6HPpAB/wDJnLiLlaWQX2APHhiTJIN7rqW+Of0eRgcp7jn05U1BsCP3xBA==} + peerDependencies: + three: '>=0.128.0' + + three@0.177.0: + resolution: {integrity: sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -1689,6 +1905,19 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + troika-three-text@0.52.4: + resolution: {integrity: sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==} + peerDependencies: + three: '>=0.125.0' + + troika-three-utils@0.52.4: + resolution: {integrity: sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==} + peerDependencies: + three: '>=0.125.0' + + troika-worker-utils@0.52.0: + resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==} + ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} @@ -1705,6 +1934,9 @@ packages: typescript: optional: true + tunnel-rat@0.1.2: + resolution: {integrity: sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==} + tw-animate-css@1.3.0: resolution: {integrity: sha512-jrJ0XenzS9KVuDThJDvnhalbl4IYiMQ/XvpA0a2FL8KmlK+6CSMviO7ROY/I7z1NnUs5NnDhlM6fXmF40xPxzw==} @@ -1733,6 +1965,15 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + utility-types@3.11.0: + resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} + engines: {node: '>= 4'} + vite-tsconfig-paths@5.1.4: resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} peerDependencies: @@ -1785,6 +2026,12 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + webgl-constants@1.1.1: + resolution: {integrity: sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==} + + webgl-sdf-generator@1.1.1: + resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1805,6 +2052,21 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + zustand@5.0.5: resolution: {integrity: sha512-mILtRfKW9xM47hqxGIxCv12gXusoY/xTSHBYApXozR0HmQv299whhBeeAcRy+KrPPybzosvJBCOmVjq6x12fCg==} engines: {node: '>=12.20.0'} @@ -1942,6 +2204,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@dimforge/rapier3d-compat@0.12.0': {} + '@esbuild/aix-ppc64@0.25.5': optional: true @@ -2095,6 +2359,13 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@mediapipe/tasks-vision@0.10.17': {} + + '@monogrid/gainmap-js@3.1.0(three@0.177.0)': + dependencies: + promise-worker-transferable: 1.0.4 + three: 0.177.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2197,6 +2468,61 @@ snapshots: optionalDependencies: '@types/react': 19.1.6 + '@react-three/drei@10.1.2(@react-three/fiber@9.1.2(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0))(@types/react@19.1.6)(@types/three@0.177.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0)': + dependencies: + '@babel/runtime': 7.27.3 + '@mediapipe/tasks-vision': 0.10.17 + '@monogrid/gainmap-js': 3.1.0(three@0.177.0) + '@react-three/fiber': 9.1.2(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0) + '@use-gesture/react': 10.3.1(react@19.1.0) + camera-controls: 2.10.1(three@0.177.0) + cross-env: 7.0.3 + detect-gpu: 5.0.70 + glsl-noise: 0.0.0 + hls.js: 1.6.5 + maath: 0.10.8(@types/three@0.177.0)(three@0.177.0) + meshline: 3.3.1(three@0.177.0) + react: 19.1.0 + stats-gl: 2.4.2(@types/three@0.177.0)(three@0.177.0) + stats.js: 0.17.0 + suspend-react: 0.1.3(react@19.1.0) + three: 0.177.0 + three-mesh-bvh: 0.8.3(three@0.177.0) + three-stdlib: 2.36.0(three@0.177.0) + troika-three-text: 0.52.4(three@0.177.0) + tunnel-rat: 0.1.2(@types/react@19.1.6)(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + utility-types: 3.11.0 + zustand: 5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) + optionalDependencies: + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - '@types/three' + - immer + + '@react-three/fiber@9.1.2(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.177.0)': + dependencies: + '@babel/runtime': 7.27.3 + '@types/react-reconciler': 0.28.9(@types/react@19.1.6) + '@types/webxr': 0.5.22 + base64-js: 1.5.1 + buffer: 6.0.3 + its-fine: 2.0.0(@types/react@19.1.6)(react@19.1.0) + react: 19.1.0 + react-reconciler: 0.31.0(react@19.1.0) + react-use-measure: 2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + scheduler: 0.25.0 + suspend-react: 0.1.3(react@19.1.0) + three: 0.177.0 + use-sync-external-store: 1.5.0(react@19.1.0) + zustand: 5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) + optionalDependencies: + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - immer + '@rolldown/pluginutils@1.0.0-beta.9': {} '@rollup/rollup-android-arm-eabi@4.41.1': @@ -2330,6 +2656,8 @@ snapshots: tailwindcss: 4.1.7 vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1) + '@tweenjs/tween.js@23.1.3': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.3 @@ -2351,10 +2679,14 @@ snapshots: dependencies: '@babel/types': 7.27.3 + '@types/draco3d@1.4.10': {} + '@types/estree@1.0.7': {} '@types/json-schema@7.0.15': {} + '@types/offscreencanvas@2019.7.3': {} + '@types/quill@1.3.10': dependencies: parchment: 1.1.4 @@ -2363,10 +2695,28 @@ snapshots: dependencies: '@types/react': 19.1.6 + '@types/react-reconciler@0.28.9(@types/react@19.1.6)': + dependencies: + '@types/react': 19.1.6 + '@types/react@19.1.6': dependencies: csstype: 3.1.3 + '@types/stats.js@0.17.4': {} + + '@types/three@0.177.0': + dependencies: + '@dimforge/rapier3d-compat': 0.12.0 + '@tweenjs/tween.js': 23.1.3 + '@types/stats.js': 0.17.4 + '@types/webxr': 0.5.22 + '@webgpu/types': 0.1.61 + fflate: 0.8.2 + meshoptimizer: 0.18.1 + + '@types/webxr@0.5.22': {} + '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.27.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -2444,6 +2794,13 @@ snapshots: '@typescript-eslint/types': 8.32.1 eslint-visitor-keys: 4.2.0 + '@use-gesture/core@10.3.1': {} + + '@use-gesture/react@10.3.1(react@19.1.0)': + dependencies: + '@use-gesture/core': 10.3.1 + react: 19.1.0 + '@vitejs/plugin-react@4.5.0(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))': dependencies: '@babel/core': 7.27.3 @@ -2456,6 +2813,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@webgpu/types@0.1.61': {} + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -2477,6 +2836,12 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2497,6 +2862,11 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.5) + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2516,6 +2886,10 @@ snapshots: callsites@3.1.0: {} + camera-controls@2.10.1(three@0.177.0): + dependencies: + three: 0.177.0 + caniuse-lite@1.0.30001718: {} chalk@4.1.2: @@ -2545,6 +2919,10 @@ snapshots: cookie@1.0.2: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2580,8 +2958,14 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + detect-gpu@5.0.70: + dependencies: + webgl-constants: 1.1.1 + detect-libc@2.0.4: {} + draco3d@1.5.7: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2744,6 +3128,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fflate@0.6.10: {} + + fflate@0.8.2: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -2807,6 +3195,8 @@ snapshots: globrex@0.1.2: {} + glsl-noise@0.0.0: {} + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -2829,6 +3219,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hls.js@1.6.5: {} + html-parse-stringify@3.0.1: dependencies: void-elements: 3.1.0 @@ -2844,10 +3236,14 @@ snapshots: prop-types: 15.8.1 react: 19.1.0 + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.4: {} + immediate@3.0.6: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -2873,6 +3269,8 @@ snapshots: is-number@7.0.0: {} + is-promise@2.2.2: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -2882,6 +3280,13 @@ snapshots: isexe@2.0.0: {} + its-fine@2.0.0(@types/react@19.1.6)(react@19.1.0): + dependencies: + '@types/react-reconciler': 0.28.9(@types/react@19.1.6) + react: 19.1.0 + transitivePeerDependencies: + - '@types/react' + jiti@2.4.2: {} js-tokens@4.0.0: {} @@ -2909,6 +3314,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lightningcss-darwin-arm64@1.30.1: optional: true @@ -2980,6 +3389,11 @@ snapshots: dependencies: react: 19.1.0 + maath@0.10.8(@types/three@0.177.0)(three@0.177.0): + dependencies: + '@types/three': 0.177.0 + three: 0.177.0 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -2988,6 +3402,12 @@ snapshots: merge2@1.4.1: {} + meshline@3.3.1(three@0.177.0): + dependencies: + three: 0.177.0 + + meshoptimizer@0.18.1: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -3067,8 +3487,15 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + potpack@1.0.2: {} + prelude-ls@1.2.1: {} + promise-worker-transferable@1.0.4: + dependencies: + is-promise: 2.2.2 + lie: 3.3.0 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -3158,6 +3585,11 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) + react-reconciler@0.31.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.25.0 + react-refresh@0.17.0: {} react-router-dom@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): @@ -3179,6 +3611,12 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) + react-use-measure@2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + optionalDependencies: + react-dom: 19.1.0(react@19.1.0) + react@19.1.0: {} regexp.prototype.flags@1.5.4: @@ -3190,6 +3628,8 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} reusify@1.1.0: {} @@ -3224,6 +3664,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + scheduler@0.25.0: {} + scheduler@0.26.0: {} semver@6.3.1: {} @@ -3256,12 +3698,23 @@ snapshots: source-map-js@1.2.1: {} + stats-gl@2.4.2(@types/three@0.177.0)(three@0.177.0): + dependencies: + '@types/three': 0.177.0 + three: 0.177.0 + + stats.js@0.17.0: {} + strip-json-comments@3.1.1: {} supports-color@7.2.0: dependencies: has-flag: 4.0.0 + suspend-react@0.1.3(react@19.1.0): + dependencies: + react: 19.1.0 + swiper@11.2.8: {} tailwind-merge@3.3.0: {} @@ -3279,6 +3732,22 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 + three-mesh-bvh@0.8.3(three@0.177.0): + dependencies: + three: 0.177.0 + + three-stdlib@2.36.0(three@0.177.0): + dependencies: + '@types/draco3d': 1.4.10 + '@types/offscreencanvas': 2019.7.3 + '@types/webxr': 0.5.22 + draco3d: 1.5.7 + fflate: 0.6.10 + potpack: 1.0.2 + three: 0.177.0 + + three@0.177.0: {} + tinyglobby@0.2.14: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -3288,6 +3757,20 @@ snapshots: dependencies: is-number: 7.0.0 + troika-three-text@0.52.4(three@0.177.0): + dependencies: + bidi-js: 1.0.3 + three: 0.177.0 + troika-three-utils: 0.52.4(three@0.177.0) + troika-worker-utils: 0.52.0 + webgl-sdf-generator: 1.1.1 + + troika-three-utils@0.52.4(three@0.177.0): + dependencies: + three: 0.177.0 + + troika-worker-utils@0.52.0: {} + ts-api-utils@2.1.0(typescript@5.7.3): dependencies: typescript: 5.7.3 @@ -3296,6 +3779,14 @@ snapshots: optionalDependencies: typescript: 5.7.3 + tunnel-rat@0.1.2(@types/react@19.1.6)(react@19.1.0): + dependencies: + zustand: 4.5.7(@types/react@19.1.6)(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - immer + - react + tw-animate-css@1.3.0: {} type-check@0.4.0: @@ -3324,6 +3815,12 @@ snapshots: dependencies: punycode: 2.3.1 + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + + utility-types@3.11.0: {} + vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)): dependencies: debug: 4.4.1 @@ -3350,6 +3847,10 @@ snapshots: void-elements@3.1.0: {} + webgl-constants@1.1.1: {} + + webgl-sdf-generator@1.1.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -3362,7 +3863,15 @@ snapshots: yocto-queue@0.1.0: {} - zustand@5.0.5(@types/react@19.1.6)(react@19.1.0): + zustand@4.5.7(@types/react@19.1.6)(react@19.1.0): + dependencies: + use-sync-external-store: 1.5.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 react: 19.1.0 + + zustand@5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)): + optionalDependencies: + '@types/react': 19.1.6 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) diff --git a/src/components/Td.tsx b/src/components/Td.tsx index 92c1f05..d581f8a 100644 --- a/src/components/Td.tsx +++ b/src/components/Td.tsx @@ -1,7 +1,7 @@ import { FC, ReactNode } from 'react' interface Props { - text: string | number, + text: string | number | ReactNode, children?: ReactNode, dir?: string, } diff --git a/src/langs/fa.json b/src/langs/fa.json index e7d6d22..cce41ae 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -48,5 +48,8 @@ "recipients_placeholder": "نام گیرنده", "subject_placeholder": "موضوع پیام", "message_placeholder": "متن پیام" + }, + "draft": { + "title": "پیش نویس ها" } } diff --git a/src/pages/Trash/List.tsx b/src/pages/Trash/List.tsx new file mode 100644 index 0000000..f7da255 --- /dev/null +++ b/src/pages/Trash/List.tsx @@ -0,0 +1,98 @@ +import Filters, { FilterValues } from '../../components/Filters'; +import { FC, ReactNode, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Table from '../../components/Table'; +import { ColumnType } from '../../components/types/TableTypes'; +import { InfoCircle, More, Refresh2 } from 'iconsax-react'; + +interface Message extends Record { + id: string; + title: string | ReactNode; + sender: string; + date: string; + read: boolean; +} + +const TrashList: FC = () => { + const { t } = useTranslation(); + const [isLoading] = useState(false); + + const messageData: Message[] = [ + { id: '1', title:
پیش نویس
, sender: 'علی محمدی', date: '1402/05/12', read: true }, + { id: '2', title:
ارسالی
, sender: 'زهرا احمدی', date: '1402/05/13', read: true }, + { id: '3', title:
دریافت شده
, sender: 'مدیریت', date: '1402/05/14', read: true }, + ]; + + const columns: ColumnType[] = [ + { + key: 'title', + title: 'عنوان پیام', + render: (item) => ( +
+ {!item.read &&
} + {item.title} +
+ ) + }, + { key: 'status', title: 'وضعیت' }, + { key: 'sender', title: 'فرستنده' }, + { key: 'date', title: 'تاریخ', align: 'center' }, + ]; + + const tableActions = ( +
+ + +
+ ); + + const handleFilterChange = (newFilters: FilterValues) => { + console.log('Applied filters:', newFilters); + }; + + return ( +
+

{t('draft.title')}

+ + + + + columns={columns} + data={messageData} + isLoading={isLoading} + showHeader={false} + actions={tableActions} + onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)} + noDataMessage={ +
+ +
هیچ پیامی یافت نشد
+
+ } + selectable={true} + /> + +
+ ) +} + +export default TrashList diff --git a/src/pages/archive/List.tsx b/src/pages/archive/List.tsx new file mode 100644 index 0000000..595a6ed --- /dev/null +++ b/src/pages/archive/List.tsx @@ -0,0 +1,99 @@ +import Filters, { FilterValues } from '../../components/Filters'; +import { FC, ReactNode, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Table from '../../components/Table'; +import { ColumnType } from '../../components/types/TableTypes'; +import { InfoCircle, More, Refresh2 } from 'iconsax-react'; + +interface Message extends Record { + id: string; + title: string | ReactNode; + status: ReactNode; + sender: string; + date: string; + read: boolean; +} + +const ArchiveList: FC = () => { + const { t } = useTranslation(); + const [isLoading] = useState(false); + + const messageData: Message[] = [ + { id: '1', title:
پیش نویس
, status:
آرشیو شده
, sender: 'علی محمدی', date: '1402/05/12', read: true }, + { id: '2', title:
ارسالی
, status:
آرشیو شده
, sender: 'زهرا احمدی', date: '1402/05/13', read: true }, + { id: '3', title:
دریافت شده
, status:
آرشیو شده
, sender: 'مدیریت', date: '1402/05/14', read: true }, + ]; + + const columns: ColumnType[] = [ + { + key: 'title', + title: 'عنوان پیام', + render: (item) => ( +
+ {!item.read &&
} + {item.title} +
+ ) + }, + { key: 'status', title: 'وضعیت' }, + { key: 'sender', title: 'فرستنده' }, + { key: 'date', title: 'تاریخ', align: 'center' }, + ]; + + const tableActions = ( +
+ + +
+ ); + + const handleFilterChange = (newFilters: FilterValues) => { + console.log('Applied filters:', newFilters); + }; + + return ( +
+

{t('draft.title')}

+ + + + + columns={columns} + data={messageData} + isLoading={isLoading} + showHeader={false} + actions={tableActions} + onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)} + noDataMessage={ +
+ +
هیچ پیامی یافت نشد
+
+ } + selectable={true} + /> + +
+ ) +} + +export default ArchiveList diff --git a/src/pages/draft/List.tsx b/src/pages/draft/List.tsx new file mode 100644 index 0000000..64368d2 --- /dev/null +++ b/src/pages/draft/List.tsx @@ -0,0 +1,97 @@ +import Filters, { FilterValues } from '../../components/Filters'; +import { FC, ReactNode, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Table from '../../components/Table'; +import { ColumnType } from '../../components/types/TableTypes'; +import { InfoCircle, More, Refresh2 } from 'iconsax-react'; + +interface Message extends Record { + id: string; + title: string | ReactNode; + sender: string; + date: string; + read: boolean; +} + +const List: FC = () => { + const { t } = useTranslation(); + const [isLoading] = useState(false); + + const messageData: Message[] = [ + { id: '1', title:
پیش نویس
, sender: 'علی محمدی', date: '1402/05/12', read: true }, + { id: '2', title:
پیش نویس
, sender: 'زهرا احمدی', date: '1402/05/13', read: true }, + { id: '3', title:
پیش نویس
, sender: 'مدیریت', date: '1402/05/14', read: true }, + ]; + + const columns: ColumnType[] = [ + { + key: 'title', + title: 'عنوان پیام', + render: (item) => ( +
+ {!item.read &&
} + {item.title} +
+ ) + }, + { key: 'sender', title: 'فرستنده' }, + { key: 'date', title: 'تاریخ', align: 'center' }, + ]; + + const tableActions = ( +
+ + +
+ ); + + const handleFilterChange = (newFilters: FilterValues) => { + console.log('Applied filters:', newFilters); + }; + + return ( +
+

{t('draft.title')}

+ + + + + columns={columns} + data={messageData} + isLoading={isLoading} + showHeader={false} + actions={tableActions} + onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)} + noDataMessage={ +
+ +
هیچ پیامی یافت نشد
+
+ } + selectable={true} + /> + +
+ ) +} + +export default List diff --git a/src/pages/setting/Setting.tsx b/src/pages/setting/Setting.tsx index 2aaf41c..d15fea2 100644 --- a/src/pages/setting/Setting.tsx +++ b/src/pages/setting/Setting.tsx @@ -4,30 +4,55 @@ import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import { SettingTabEnum } from './enum/SettingEnum' import Personality from './personality/Personality' +import Domain from './domain/Domain' +import MailServer from './mail-server/MailServer' +import Address from './address/Address' +import PersonalitySidebar from './personality/Setting' const Setting: FC = () => { const { t } = useTranslation() const [activeTab, setActiveTab] = useState(SettingTabEnum.SETTING_PERSONALITY) + + const renderActiveTab = () => { + switch (activeTab) { + case SettingTabEnum.SETTING_MAIL_SERVER: + return ; + case SettingTabEnum.SETTING_DOMAIN: + return ; + case SettingTabEnum.SETTING_ADDRESS: + return
; + case SettingTabEnum.SETTING_PERSONALITY: + return ( +
+ + +
+ ); + default: + return null; + } + }; + return (
-

{t('setting.title')}

+

{t('setting.title')}

, - label: t('setting.address'), + label: t('setting.mail_server'), value: SettingTabEnum.SETTING_MAIL_SERVER }, { icon: , - label: t('setting.mail_server'), + label: t('setting.domain'), value: SettingTabEnum.SETTING_DOMAIN }, { icon: , - label: t('setting.domain'), + label: t('setting.address'), value: SettingTabEnum.SETTING_ADDRESS }, { @@ -41,12 +66,8 @@ const Setting: FC = () => { />
-
- { - activeTab === SettingTabEnum.SETTING_PERSONALITY ? - - : null - } +
+ {renderActiveTab()}
) diff --git a/src/pages/setting/address/Address.tsx b/src/pages/setting/address/Address.tsx new file mode 100644 index 0000000..85b82cd --- /dev/null +++ b/src/pages/setting/address/Address.tsx @@ -0,0 +1,244 @@ +import { FC, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Add, Edit2, Trash } from 'iconsax-react' + +interface EmailAddress { + id: number + email: string + name: string + isPrimary: boolean +} + +const Address: FC = () => { + const { t } = useTranslation() + const [addresses, setAddresses] = useState([ + { id: 1, email: 'user@example.com', name: 'Main Account', isPrimary: true } + ]) + const [showAddForm, setShowAddForm] = useState(false) + const [newEmail, setNewEmail] = useState('') + const [newName, setNewName] = useState('') + const [editingId, setEditingId] = useState(null) + + const handleAddAddress = () => { + if (newEmail && newName) { + const newId = addresses.length > 0 ? Math.max(...addresses.map(a => a.id)) + 1 : 1 + setAddresses([...addresses, { + id: newId, + email: newEmail, + name: newName, + isPrimary: addresses.length === 0 + }]) + setNewEmail('') + setNewName('') + setShowAddForm(false) + } + } + + const handleEditStart = (address: EmailAddress) => { + setEditingId(address.id) + setNewEmail(address.email) + setNewName(address.name) + } + + const handleEditSave = () => { + if (editingId && newEmail && newName) { + setAddresses(addresses.map(addr => + addr.id === editingId + ? { ...addr, email: newEmail, name: newName } + : addr + )) + setEditingId(null) + setNewEmail('') + setNewName('') + } + } + + const handleSetPrimary = (id: number) => { + setAddresses(addresses.map(addr => ({ + ...addr, + isPrimary: addr.id === id + }))) + } + + const handleDelete = (id: number) => { + const filteredAddresses = addresses.filter(addr => addr.id !== id) + // If we're deleting the primary address, make the first one primary + if (addresses.find(addr => addr.id === id)?.isPrimary && filteredAddresses.length > 0) { + filteredAddresses[0].isPrimary = true + } + setAddresses(filteredAddresses) + } + + return ( +
+
+

{t('setting.address')}

+ +
+ +
+
+

{t('setting.email_addresses')}

+ {!showAddForm && ( + + )} +
+ + {showAddForm && ( +
+

{t('setting.new_address')}

+
+
+ + setNewEmail(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + placeholder='email@domain.com' + /> +
+
+ + setNewName(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + placeholder={t('setting.display_name_placeholder')} + /> +
+
+
+ + +
+
+ )} + +
+ {addresses.map((address) => ( +
+ {editingId === address.id ? ( +
+
+ + setNewEmail(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + /> +
+
+ + setNewName(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + /> +
+
+ + +
+
+ ) : ( +
+
+
+

{address.name}

+ {address.isPrimary && ( + + {t('setting.primary')} + + )} +
+

{address.email}

+
+
+ {!address.isPrimary && ( + <> + + + + + )} +
+
+ )} +
+ ))} +
+
+ +
+
+ + + + + +
+

{t('setting.verification_required')}

+

{t('setting.verification_note')}

+
+
+
+
+ ) +} + +export default Address \ No newline at end of file diff --git a/src/pages/setting/domain/Domain.tsx b/src/pages/setting/domain/Domain.tsx new file mode 100644 index 0000000..189067c --- /dev/null +++ b/src/pages/setting/domain/Domain.tsx @@ -0,0 +1,128 @@ +import { FC, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Add, CloseCircle } from 'iconsax-react' + +const Domain: FC = () => { + const { t } = useTranslation() + const [domains, setDomains] = useState(['example.com']) + const [newDomain, setNewDomain] = useState('') + const [error, setError] = useState('') + + const handleAddDomain = () => { + if (!newDomain) { + setError(t('setting.domain_required')) + return + } + + // Simple domain validation + const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/ + if (!domainRegex.test(newDomain)) { + setError(t('setting.invalid_domain')) + return + } + + if (domains.includes(newDomain)) { + setError(t('setting.domain_exists')) + return + } + + setDomains([...domains, newDomain]) + setNewDomain('') + setError('') + } + + const handleRemoveDomain = (domain: string) => { + setDomains(domains.filter(d => d !== domain)) + } + + return ( +
+
+

{t('setting.domain')}

+ +
+ +
+ +
+ { + setNewDomain(e.target.value) + setError('') + }} + className={`flex-1 px-4 py-2 border ${error ? 'border-red-500' : 'border-gray-300'} rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent`} + placeholder='domain.com' + /> + +
+ {error &&

{error}

} +
+ +
+

{t('setting.your_domains')}

+
+ {domains.map((domain, index) => ( +
+
+

{domain}

+

+ {index === 0 ? t('setting.primary_domain') : t('setting.additional_domain')} +

+
+
+
+ {index === 0 ? t('setting.verified') : t('setting.pending')} +
+ {index !== 0 && ( + + )} +
+
+ ))} +
+
+ +
+

{t('setting.dns_records')}

+

{t('setting.dns_instructions')}

+ +
+
+
{t('setting.type')}
+
{t('setting.hostname')}
+
{t('setting.value')}
+
+
+
MX
+
@
+
mail.example.com
+
+
+
TXT
+
@
+
v=spf1 include:spf.example.com ~all
+
+
+
CNAME
+
mail
+
mailserver.example.com
+
+
+
+
+ ) +} + +export default Domain \ No newline at end of file diff --git a/src/pages/setting/mail-server/MailServer.tsx b/src/pages/setting/mail-server/MailServer.tsx new file mode 100644 index 0000000..1c87ae3 --- /dev/null +++ b/src/pages/setting/mail-server/MailServer.tsx @@ -0,0 +1,134 @@ +import { FC, useState } from 'react' +import { useTranslation } from 'react-i18next' + +const MailServer: FC = () => { + const { t } = useTranslation() + const [serverType, setServerType] = useState('smtp') + const [host, setHost] = useState('') + const [port, setPort] = useState('') + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [encryption, setEncryption] = useState('tls') + + return ( +
+
+

{t('setting.mail_server')}

+ +
+ +
+
+ +
+ + +
+
+ + {serverType === 'smtp' && ( + <> +
+
+ + setHost(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + placeholder='mail.example.com' + /> +
+
+ + setPort(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + placeholder='587' + /> +
+
+ +
+ + setUsername(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + placeholder='username@example.com' + /> +
+ +
+ + setPassword(e.target.value)} + className='w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent' + /> +
+ +
+ + +
+ +
+ +
+ + )} + + {serverType === 'api' && ( + <> +
+ + +
+
+ + +
+ + )} +
+
+ ) +} + +export default MailServer \ No newline at end of file diff --git a/src/pages/setting/personality/Personality.tsx b/src/pages/setting/personality/Personality.tsx index a52655d..2afa51c 100644 --- a/src/pages/setting/personality/Personality.tsx +++ b/src/pages/setting/personality/Personality.tsx @@ -1,13 +1,186 @@ -import { FC } from 'react' -import Setting from './Setting' -const Personality: FC = () => { - return ( -
-
+import { FC, useState } from 'react' +import { Add, Edit } from 'iconsax-react' +const Personality: FC = () => { + const [backgroundImage, setBackgroundImage] = useState(null) + const [emailContent, setEmailContent] = useState('') + const [emailFooter, setEmailFooter] = useState('') + const [showContentEditor, setShowContentEditor] = useState(false) + const [showFooterEditor, setShowFooterEditor] = useState(false) + + const handleImageUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0] + if (file) { + const reader = new FileReader() + reader.onload = (e) => { + setBackgroundImage(e.target?.result as string) + } + reader.readAsDataURL(file) + } + } + + const handleAddEmailContent = () => { + if (!emailContent) { + setEmailContent('متن ایمیل خود را اینجا وارد کنید') + } + setShowContentEditor(true) + } + + const handleAddEmailFooter = () => { + if (!emailFooter) { + setEmailFooter('پاورقی ایمیل خود را اینجا وارد کنید') + } + setShowFooterEditor(true) + } + + return ( +
+ {/* Header buttons */} +
+ + {/*
+ + + + +
*/}
- + {/* Background image section */} +
+ {backgroundImage ? ( +
+ Background + +
+ ) : ( +
+
تصویر پس زمینه مورد نظر را آپلود کنید
+ +
+ )} +
+ + {/* Email content section */} +
+ {emailContent && showContentEditor ? ( +
+