fix build

This commit is contained in:
hamid zarghami
2025-06-11 01:17:22 +03:30
parent f66f1a768e
commit 7db9ec7f2f
14 changed files with 1685 additions and 38 deletions
+4
View File
@@ -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",
+511 -2
View File
@@ -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)
+1 -1
View File
@@ -1,7 +1,7 @@
import { FC, ReactNode } from 'react'
interface Props {
text: string | number,
text: string | number | ReactNode,
children?: ReactNode,
dir?: string,
}
+3
View File
@@ -48,5 +48,8 @@
"recipients_placeholder": "نام گیرنده",
"subject_placeholder": "موضوع پیام",
"message_placeholder": "متن پیام"
},
"draft": {
"title": "پیش نویس ها"
}
}
+98
View File
@@ -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<string, unknown> {
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: <div className='text-blue-500'>پیش نویس</div>, sender: 'علی محمدی', date: '1402/05/12', read: true },
{ id: '2', title: <div className='text-blue-500'>ارسالی</div>, sender: 'زهرا احمدی', date: '1402/05/13', read: true },
{ id: '3', title: <div className='text-blue-500'>دریافت شده</div>, sender: 'مدیریت', date: '1402/05/14', read: true },
];
const columns: ColumnType<Message>[] = [
{
key: 'title',
title: 'عنوان پیام',
render: (item) => (
<div className="flex items-center">
{!item.read && <div className="w-2 h-2 rounded-full bg-blue-500 mr-2" />}
<span>{item.title}</span>
</div>
)
},
{ key: 'status', title: 'وضعیت' },
{ key: 'sender', title: 'فرستنده' },
{ key: 'date', title: 'تاریخ', align: 'center' },
];
const tableActions = (
<div className='flex items-center gap-4'>
<Refresh2 size={20} color='black' />
<More size={20} color='black' className='rotate-90' />
</div>
);
const handleFilterChange = (newFilters: FilterValues) => {
console.log('Applied filters:', newFilters);
};
return (
<div className='mt-4'>
<h1>{t('draft.title')}</h1>
<Filters
fields={[
{ type: 'date', name: 'from_date', placeholder: t('received.from_date') },
{ type: 'date', name: 'to_date', placeholder: t('received.to_date') },
{
type: 'select',
name: 'status',
placeholder: t('received.all'),
options: [
{ value: 'all', label: t('received.all') },
{ value: 'read', label: t('received.read') },
{ value: 'unread', label: t('received.unread') }
]
},
{ type: 'input', name: 'search', placeholder: t('received.search') }
]}
onChange={handleFilterChange}
className="mt-8 flex justify-between items-center"
searchField="search"
/>
<Table<Message>
columns={columns}
data={messageData}
isLoading={isLoading}
showHeader={false}
actions={tableActions}
onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)}
noDataMessage={
<div className="flex flex-col items-center py-6">
<InfoCircle size={40} className="text-gray-300 mb-2" />
<div>هیچ پیامی یافت نشد</div>
</div>
}
selectable={true}
/>
</div>
)
}
export default TrashList
+99
View File
@@ -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<string, unknown> {
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: <div className='text-blue-500'>پیش نویس</div>, status: <div className='text-yellow-500'>آرشیو شده</div>, sender: 'علی محمدی', date: '1402/05/12', read: true },
{ id: '2', title: <div className='text-blue-500'>ارسالی</div>, status: <div className='text-yellow-500'>آرشیو شده</div>, sender: 'زهرا احمدی', date: '1402/05/13', read: true },
{ id: '3', title: <div className='text-blue-500'>دریافت شده</div>, status: <div className='text-yellow-500'>آرشیو شده</div>, sender: 'مدیریت', date: '1402/05/14', read: true },
];
const columns: ColumnType<Message>[] = [
{
key: 'title',
title: 'عنوان پیام',
render: (item) => (
<div className="flex items-center">
{!item.read && <div className="w-2 h-2 rounded-full bg-blue-500 mr-2" />}
<span>{item.title}</span>
</div>
)
},
{ key: 'status', title: 'وضعیت' },
{ key: 'sender', title: 'فرستنده' },
{ key: 'date', title: 'تاریخ', align: 'center' },
];
const tableActions = (
<div className='flex items-center gap-4'>
<Refresh2 size={20} color='black' />
<More size={20} color='black' className='rotate-90' />
</div>
);
const handleFilterChange = (newFilters: FilterValues) => {
console.log('Applied filters:', newFilters);
};
return (
<div className='mt-4'>
<h1>{t('draft.title')}</h1>
<Filters
fields={[
{ type: 'date', name: 'from_date', placeholder: t('received.from_date') },
{ type: 'date', name: 'to_date', placeholder: t('received.to_date') },
{
type: 'select',
name: 'status',
placeholder: t('received.all'),
options: [
{ value: 'all', label: t('received.all') },
{ value: 'read', label: t('received.read') },
{ value: 'unread', label: t('received.unread') }
]
},
{ type: 'input', name: 'search', placeholder: t('received.search') }
]}
onChange={handleFilterChange}
className="mt-8 flex justify-between items-center"
searchField="search"
/>
<Table<Message>
columns={columns}
data={messageData}
isLoading={isLoading}
showHeader={false}
actions={tableActions}
onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)}
noDataMessage={
<div className="flex flex-col items-center py-6">
<InfoCircle size={40} className="text-gray-300 mb-2" />
<div>هیچ پیامی یافت نشد</div>
</div>
}
selectable={true}
/>
</div>
)
}
export default ArchiveList
+97
View File
@@ -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<string, unknown> {
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: <div className='text-blue-500'>پیش نویس</div>, sender: 'علی محمدی', date: '1402/05/12', read: true },
{ id: '2', title: <div className='text-blue-500'>پیش نویس</div>, sender: 'زهرا احمدی', date: '1402/05/13', read: true },
{ id: '3', title: <div className='text-blue-500'>پیش نویس</div>, sender: 'مدیریت', date: '1402/05/14', read: true },
];
const columns: ColumnType<Message>[] = [
{
key: 'title',
title: 'عنوان پیام',
render: (item) => (
<div className="flex items-center">
{!item.read && <div className="w-2 h-2 rounded-full bg-blue-500 mr-2" />}
<span>{item.title}</span>
</div>
)
},
{ key: 'sender', title: 'فرستنده' },
{ key: 'date', title: 'تاریخ', align: 'center' },
];
const tableActions = (
<div className='flex items-center gap-4'>
<Refresh2 size={20} color='black' />
<More size={20} color='black' className='rotate-90' />
</div>
);
const handleFilterChange = (newFilters: FilterValues) => {
console.log('Applied filters:', newFilters);
};
return (
<div className='mt-4'>
<h1>{t('draft.title')}</h1>
<Filters
fields={[
{ type: 'date', name: 'from_date', placeholder: t('received.from_date') },
{ type: 'date', name: 'to_date', placeholder: t('received.to_date') },
{
type: 'select',
name: 'status',
placeholder: t('received.all'),
options: [
{ value: 'all', label: t('received.all') },
{ value: 'read', label: t('received.read') },
{ value: 'unread', label: t('received.unread') }
]
},
{ type: 'input', name: 'search', placeholder: t('received.search') }
]}
onChange={handleFilterChange}
className="mt-8 flex justify-between items-center"
searchField="search"
/>
<Table<Message>
columns={columns}
data={messageData}
isLoading={isLoading}
showHeader={false}
actions={tableActions}
onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)}
noDataMessage={
<div className="flex flex-col items-center py-6">
<InfoCircle size={40} className="text-gray-300 mb-2" />
<div>هیچ پیامی یافت نشد</div>
</div>
}
selectable={true}
/>
</div>
)
}
export default List
+31 -10
View File
@@ -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>(SettingTabEnum.SETTING_PERSONALITY)
const renderActiveTab = () => {
switch (activeTab) {
case SettingTabEnum.SETTING_MAIL_SERVER:
return <MailServer />;
case SettingTabEnum.SETTING_DOMAIN:
return <Domain />;
case SettingTabEnum.SETTING_ADDRESS:
return <Address />;
case SettingTabEnum.SETTING_PERSONALITY:
return (
<div className='flex flex-row-reverse gap-6 mt-8'>
<PersonalitySidebar />
<Personality />
</div>
);
default:
return null;
}
};
return (
<div className='mt-4'>
<h1>{t('setting.title')}</h1>
<h1 className='text-2xl font-bold text-right'>{t('setting.title')}</h1>
<div className='mt-7'>
<Tabs
items={[
{
icon: <Setting3 size={22} color={activeTab === SettingTabEnum.SETTING_MAIL_SERVER ? 'black' : '#8C90A3'} />,
label: t('setting.address'),
label: t('setting.mail_server'),
value: SettingTabEnum.SETTING_MAIL_SERVER
},
{
icon: <Global size={22} color={activeTab === SettingTabEnum.SETTING_DOMAIN ? 'black' : '#8C90A3'} />,
label: t('setting.mail_server'),
label: t('setting.domain'),
value: SettingTabEnum.SETTING_DOMAIN
},
{
icon: <People size={22} color={activeTab === SettingTabEnum.SETTING_ADDRESS ? 'black' : '#8C90A3'} />,
label: t('setting.domain'),
label: t('setting.address'),
value: SettingTabEnum.SETTING_ADDRESS
},
{
@@ -41,12 +66,8 @@ const Setting: FC = () => {
/>
</div>
<div className='mt-10'>
{
activeTab === SettingTabEnum.SETTING_PERSONALITY ?
<Personality />
: null
}
<div>
{renderActiveTab()}
</div>
</div>
)
+244
View File
@@ -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<EmailAddress[]>([
{ 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<number | null>(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 (
<div className='bg-white rounded-4xl p-8'>
<div className='flex justify-between mb-8'>
<h2 className='text-xl font-semibold'>{t('setting.address')}</h2>
<button className='bg-primary text-white px-6 py-2 rounded-lg'>{t('common.save')}</button>
</div>
<div className='mb-6'>
<div className='flex justify-between items-center mb-4'>
<h3 className='text-md font-medium'>{t('setting.email_addresses')}</h3>
{!showAddForm && (
<button
onClick={() => setShowAddForm(true)}
className='flex items-center gap-1 text-primary'
>
<Add size={18} />
<span>{t('setting.add_address')}</span>
</button>
)}
</div>
{showAddForm && (
<div className='p-4 bg-gray-50 rounded-lg mb-4'>
<h4 className='font-medium mb-3'>{t('setting.new_address')}</h4>
<div className='grid grid-cols-1 gap-4 mb-4'>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.email')}</label>
<input
type="email"
value={newEmail}
onChange={(e) => 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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.display_name')}</label>
<input
type="text"
value={newName}
onChange={(e) => 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')}
/>
</div>
</div>
<div className='flex justify-end gap-2'>
<button
onClick={() => {
setShowAddForm(false)
setNewEmail('')
setNewName('')
}}
className='px-4 py-2 border border-gray-300 rounded-lg'
>
{t('common.cancel')}
</button>
<button
onClick={handleAddAddress}
disabled={!newEmail || !newName}
className={`px-4 py-2 rounded-lg ${!newEmail || !newName ? 'bg-gray-300 text-gray-500' : 'bg-primary text-white'}`}
>
{t('common.save')}
</button>
</div>
</div>
)}
<div className='space-y-3'>
{addresses.map((address) => (
<div key={address.id} className='p-4 bg-gray-50 rounded-lg'>
{editingId === address.id ? (
<div className='grid grid-cols-1 gap-4 mb-4'>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.email')}</label>
<input
type="email"
value={newEmail}
onChange={(e) => 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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.display_name')}</label>
<input
type="text"
value={newName}
onChange={(e) => 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'
/>
</div>
<div className='flex justify-end gap-2'>
<button
onClick={() => {
setEditingId(null)
setNewEmail('')
setNewName('')
}}
className='px-4 py-2 border border-gray-300 rounded-lg'
>
{t('common.cancel')}
</button>
<button
onClick={handleEditSave}
disabled={!newEmail || !newName}
className={`px-4 py-2 rounded-lg ${!newEmail || !newName ? 'bg-gray-300 text-gray-500' : 'bg-primary text-white'}`}
>
{t('common.save')}
</button>
</div>
</div>
) : (
<div className='flex items-center justify-between'>
<div>
<div className='flex items-center gap-2'>
<p className='font-medium'>{address.name}</p>
{address.isPrimary && (
<span className='px-2 py-0.5 bg-green-100 text-green-600 text-xs rounded-full'>
{t('setting.primary')}
</span>
)}
</div>
<p className='text-gray-500'>{address.email}</p>
</div>
<div className='flex items-center gap-2'>
{!address.isPrimary && (
<>
<button
onClick={() => handleSetPrimary(address.id)}
className='text-blue-600 px-3 py-1 text-sm'
>
{t('setting.set_primary')}
</button>
<button
onClick={() => handleEditStart(address)}
className='text-gray-500'
>
<Edit2 size={18} />
</button>
<button
onClick={() => handleDelete(address.id)}
className='text-gray-500'
>
<Trash size={18} />
</button>
</>
)}
</div>
</div>
)}
</div>
))}
</div>
</div>
<div className='p-4 bg-yellow-50 rounded-lg border border-yellow-100'>
<div className='flex items-start gap-3'>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="#F59E0B" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M12 8V13" stroke="#F59E0B" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M11.9941 16H12.0031" stroke="#F59E0B" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
<div>
<h4 className='font-medium text-yellow-800'>{t('setting.verification_required')}</h4>
<p className='text-sm text-yellow-700 mt-1'>{t('setting.verification_note')}</p>
</div>
</div>
</div>
</div>
)
}
export default Address
+128
View File
@@ -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<string[]>(['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 (
<div className='bg-white rounded-4xl p-8'>
<div className='flex justify-between mb-8'>
<h2 className='text-xl font-semibold'>{t('setting.domain')}</h2>
<button className='bg-primary text-white px-6 py-2 rounded-lg'>{t('common.save')}</button>
</div>
<div className='mb-6'>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.add_domain')}</label>
<div className='flex gap-2'>
<input
type="text"
value={newDomain}
onChange={(e) => {
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'
/>
<button
onClick={handleAddDomain}
className='bg-primary text-white px-4 py-2 rounded-lg'
>
<Add size={20} />
</button>
</div>
{error && <p className='text-red-500 text-sm mt-1'>{error}</p>}
</div>
<div>
<h3 className='text-md font-medium mb-4'>{t('setting.your_domains')}</h3>
<div className='space-y-3'>
{domains.map((domain, index) => (
<div key={index} className='flex items-center justify-between p-4 bg-gray-50 rounded-lg'>
<div>
<p className='font-medium'>{domain}</p>
<p className='text-sm text-gray-500'>
{index === 0 ? t('setting.primary_domain') : t('setting.additional_domain')}
</p>
</div>
<div className='flex items-center gap-3'>
<div className={`px-2 py-1 rounded-full text-xs ${index === 0 ? 'bg-green-100 text-green-600' : 'bg-blue-100 text-blue-600'}`}>
{index === 0 ? t('setting.verified') : t('setting.pending')}
</div>
{index !== 0 && (
<button
onClick={() => handleRemoveDomain(domain)}
className='text-gray-400 hover:text-red-500'
>
<CloseCircle size={20} />
</button>
)}
</div>
</div>
))}
</div>
</div>
<div className='mt-8 p-4 bg-blue-50 rounded-lg'>
<h3 className='text-md font-medium text-blue-700 mb-2'>{t('setting.dns_records')}</h3>
<p className='text-sm text-blue-600 mb-4'>{t('setting.dns_instructions')}</p>
<div className='bg-white p-4 rounded-lg border border-blue-100'>
<div className='grid grid-cols-3 gap-4 text-sm font-medium text-gray-500 pb-2 border-b'>
<div>{t('setting.type')}</div>
<div>{t('setting.hostname')}</div>
<div>{t('setting.value')}</div>
</div>
<div className='grid grid-cols-3 gap-4 text-sm py-4 border-b'>
<div>MX</div>
<div>@</div>
<div>mail.example.com</div>
</div>
<div className='grid grid-cols-3 gap-4 text-sm py-4 border-b'>
<div>TXT</div>
<div>@</div>
<div className='break-all'>v=spf1 include:spf.example.com ~all</div>
</div>
<div className='grid grid-cols-3 gap-4 text-sm py-4'>
<div>CNAME</div>
<div>mail</div>
<div>mailserver.example.com</div>
</div>
</div>
</div>
</div>
)
}
export default Domain
@@ -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 (
<div className='bg-white rounded-4xl p-8'>
<div className='flex justify-between mb-8'>
<h2 className='text-xl font-semibold'>{t('setting.mail_server')}</h2>
<button className='bg-primary text-white px-6 py-2 rounded-lg'>{t('common.save')}</button>
</div>
<div className='grid grid-cols-1 gap-6'>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.server_type')}</label>
<div className='flex gap-4 mb-4'>
<label className='flex items-center gap-2 cursor-pointer'>
<input
type="radio"
checked={serverType === 'smtp'}
onChange={() => setServerType('smtp')}
className='h-4 w-4 accent-primary'
/>
<span>SMTP</span>
</label>
<label className='flex items-center gap-2 cursor-pointer'>
<input
type="radio"
checked={serverType === 'api'}
onChange={() => setServerType('api')}
className='h-4 w-4 accent-primary'
/>
<span>API</span>
</label>
</div>
</div>
{serverType === 'smtp' && (
<>
<div className='grid grid-cols-2 gap-4'>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.host')}</label>
<input
type="text"
value={host}
onChange={(e) => 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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.port')}</label>
<input
type="text"
value={port}
onChange={(e) => 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'
/>
</div>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.username')}</label>
<input
type="text"
value={username}
onChange={(e) => 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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.password')}</label>
<input
type="password"
value={password}
onChange={(e) => 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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.encryption')}</label>
<select
value={encryption}
onChange={(e) => setEncryption(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'
>
<option value="none">{t('setting.none')}</option>
<option value="ssl">SSL</option>
<option value="tls">TLS</option>
</select>
</div>
<div>
<button className='bg-blue-50 text-blue-600 px-4 py-2 rounded-lg mt-4'>{t('setting.test_connection')}</button>
</div>
</>
)}
{serverType === 'api' && (
<>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.api_key')}</label>
<input
type="password"
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'
/>
</div>
<div>
<label className='block text-sm font-medium text-gray-700 mb-1'>{t('setting.api_url')}</label>
<input
type="text"
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='https://api.example.com/send'
/>
</div>
</>
)}
</div>
</div>
)
}
export default MailServer
+180 -7
View File
@@ -1,13 +1,186 @@
import { FC } from 'react'
import Setting from './Setting'
const Personality: FC = () => {
return (
<div className='flex gap-8'>
<div className='flex-1 bg-white rounded-4xl p-8'>
import { FC, useState } from 'react'
import { Add, Edit } from 'iconsax-react'
const Personality: FC = () => {
const [backgroundImage, setBackgroundImage] = useState<string | null>(null)
const [emailContent, setEmailContent] = useState<string>('')
const [emailFooter, setEmailFooter] = useState<string>('')
const [showContentEditor, setShowContentEditor] = useState<boolean>(false)
const [showFooterEditor, setShowFooterEditor] = useState<boolean>(false)
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
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 (
<div className='bg-white rounded-4xl p-6 flex-1'>
{/* Header buttons */}
<div className='flex justify-between mb-8'>
<button className='bg-black text-white px-5 py-2 rounded-xl text-sm'>ذخیره</button>
{/* <div className='flex gap-3'>
<button className='w-10 h-10 flex items-center justify-center bg-white border border-gray-200 rounded-full'>
<Edit size={20} variant="Bold" color="#FF008A" />
</button>
<button className='w-10 h-10 flex items-center justify-center bg-white border border-gray-200 rounded-full'>
<ArrowRight size={20} />
</button>
<button className='w-10 h-10 flex items-center justify-center bg-white border border-gray-200 rounded-full'>
<ArrowLeft size={20} />
</button>
<button className='w-10 h-10 flex items-center justify-center bg-white border border-gray-200 rounded-full'>
<Eye size={20} />
</button>
</div> */}
</div>
<Setting />
{/* Background image section */}
<div className='border border-dashed border-gray-300 rounded-2xl p-8 mb-6'>
{backgroundImage ? (
<div className='relative w-full'>
<img src={backgroundImage} alt="Background" className='w-full h-48 object-cover rounded-lg' />
<button
className='absolute top-2 right-2 bg-white p-1 rounded-full shadow-sm'
onClick={() => setBackgroundImage(null)}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9.17 14.83L14.83 9.17" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M14.83 14.83L9.17 9.17" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</button>
</div>
) : (
<div className='flex flex-col items-center justify-center py-10'>
<div className='text-gray-500 mb-4'>تصویر پس زمینه مورد نظر را آپلود کنید</div>
<label className='flex items-center gap-2 bg-white border border-gray-200 rounded-lg px-4 py-2 text-sm cursor-pointer'>
<input
type="file"
accept="image/*"
className='hidden'
onChange={handleImageUpload}
/>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 17V11L7 13" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9 11L11 13" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M22 10V15C22 20 20 22 15 22H9C4 22 2 20 2 15V9C2 4 4 2 9 2H14" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M22 10H18C15 10 14 9 14 6V2L22 10Z" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
آپلود
</label>
</div>
)}
</div>
{/* Email content section */}
<div className='border border-dashed border-gray-300 rounded-2xl p-8 mb-6'>
{emailContent && showContentEditor ? (
<div className='w-full'>
<textarea
className='w-full p-4 border border-gray-200 rounded-lg min-h-[150px] text-right'
value={emailContent}
onChange={(e) => setEmailContent(e.target.value)}
/>
<div className='flex justify-end mt-3'>
<button
className='px-4 py-2 bg-gray-200 rounded-lg text-sm'
onClick={() => setShowContentEditor(false)}
>
تایید
</button>
</div>
</div>
) : emailContent ? (
<div className='w-full'>
<div className='p-4 border border-gray-200 rounded-lg min-h-[150px] text-right'>
{emailContent}
</div>
<div className='flex justify-end mt-3'>
<button
className='p-2 bg-gray-100 rounded-lg'
onClick={() => setShowContentEditor(true)}
>
<Edit size={16} />
</button>
</div>
</div>
) : (
<div className='flex flex-col items-center justify-center py-14'>
<div className='text-gray-500 mb-3'>محتوای ایمیل شما</div>
<button
className='w-10 h-10 flex items-center justify-center rounded-full bg-gray-100'
onClick={handleAddEmailContent}
>
<Add size={24} />
</button>
</div>
)}
</div>
{/* Email footer section */}
<div className='border border-dashed border-gray-300 rounded-2xl p-8 mb-6'>
{emailFooter && showFooterEditor ? (
<div className='w-full'>
<textarea
className='w-full p-4 border border-gray-200 rounded-lg min-h-[100px] text-right'
value={emailFooter}
onChange={(e) => setEmailFooter(e.target.value)}
/>
<div className='flex justify-end mt-3'>
<button
className='px-4 py-2 bg-gray-200 rounded-lg text-sm'
onClick={() => setShowFooterEditor(false)}
>
تایید
</button>
</div>
</div>
) : emailFooter ? (
<div className='w-full'>
<div className='p-4 border border-gray-200 rounded-lg min-h-[100px] text-right'>
{emailFooter}
</div>
<div className='flex justify-end mt-3'>
<button
className='p-2 bg-gray-100 rounded-lg'
onClick={() => setShowFooterEditor(true)}
>
<Edit size={16} />
</button>
</div>
</div>
) : (
<div className='flex flex-col items-center justify-center py-10'>
<div className='text-gray-500 mb-3'>پاورقی ایمیل شما</div>
<button
className='w-10 h-10 flex items-center justify-center rounded-full bg-gray-100'
onClick={handleAddEmailFooter}
>
<Add size={24} />
</button>
</div>
)}
</div>
</div>
)
}
+149 -18
View File
@@ -1,31 +1,162 @@
import { FC } from 'react'
import { ArrowDown2, Gallery, LinkSquare, Setting4, Shapes, Text } from 'iconsax-react'
import Logo from '@/assets/images/logo-small.svg'
import { Gallery, LinkSquare, Setting4, Shapes, Text } from 'iconsax-react'
import { useTranslation } from 'react-i18next'
const Setting: FC = () => {
const { t } = useTranslation()
const PersonalitySidebar: FC = () => {
return (
<div className='flex-1 bg-white rounded-4xl p-8 max-w-[400px] flex'>
<div className='flex-1'>
<div className='bg-white rounded-3xl w-[360px] flex'>
<div className='flex-1 p-6'>
<div className='text-xl font-semibold text-right mb-6'>تنظیمات</div>
{/* Layout options */}
<div className='mb-6'>
<div className='grid grid-cols-2 gap-3'>
<div className='border border-gray-200 rounded-xl p-2'>
<div className='flex h-full'>
<div className='w-full h-12 bg-gray-100 rounded-lg'></div>
</div>
</div>
<div className='border border-gray-200 rounded-xl p-2'>
<div className='flex h-full'>
<div className='w-full h-12 bg-gray-100 rounded-lg'></div>
</div>
</div>
<div className='border border-gray-200 rounded-xl p-2'>
<div className='grid grid-cols-2 gap-1 w-full h-full'>
<div className='bg-gray-100 rounded-lg'></div>
<div className='bg-gray-100 rounded-lg'></div>
</div>
</div>
<div className='border border-gray-200 rounded-xl p-2'>
<div className='grid grid-cols-3 gap-1 w-full h-full'>
<div className='bg-gray-100 rounded-lg'></div>
<div className='bg-gray-100 rounded-lg'></div>
<div className='bg-gray-100 rounded-lg'></div>
</div>
</div>
</div>
</div>
{/* Color picker section */}
<div className='mb-6'>
<div className='flex justify-end mb-2'>
<span className='text-sm text-gray-600'>رنگ زمینه</span>
</div>
<div className='flex flex-col items-center'>
<div className='w-full h-36 bg-[#FF008A] rounded-lg mb-3'></div>
<div className='flex items-center w-full'>
<div className='flex'>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" fill="url(#paint0_angular_121_3242)" stroke="#E5E7EB" strokeWidth="1.5" />
<circle cx="12" cy="12" r="3" fill="#FF008A" stroke="white" strokeWidth="1.5" />
<defs>
<radialGradient id="paint0_angular_121_3242" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(12 12) rotate(90) scale(10)">
<stop offset="0" stopColor="#FF0000" />
<stop offset="0.17" stopColor="#FFFF00" />
<stop offset="0.33" stopColor="#00FF00" />
<stop offset="0.5" stopColor="#00FFFF" />
<stop offset="0.67" stopColor="#0000FF" />
<stop offset="0.83" stopColor="#FF00FF" />
<stop offset="1" stopColor="#FF0000" />
</radialGradient>
</defs>
</svg>
</div>
<div className='text-sm text-gray-500 ml-auto text-right'>#FF008A</div>
</div>
</div>
</div>
{/* Upload image section */}
<div className='border border-dashed border-gray-300 rounded-lg p-5 mb-6'>
<div className='flex flex-col items-center'>
<div className='mb-3'>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="4" fill="#F3F4F6" />
<path d="M17 9.5C17 11.7091 15.2091 13.5 13 13.5C10.7909 13.5 9 11.7091 9 9.5C9 7.29086 10.7909 5.5 13 5.5C15.2091 5.5 17 7.29086 17 9.5Z" stroke="#9CA3AF" strokeWidth="1" />
<path d="M3 20.5L8 15.5L10.5 17L14.5 13L21 19.5" stroke="#9CA3AF" strokeWidth="1" />
</svg>
</div>
<div className='text-center text-xs text-gray-500 mb-3'>تصویر پس زمینه مورد نظر را آپلود کنید</div>
<button className='flex items-center gap-1 bg-white border border-gray-200 rounded-lg px-3 py-1 text-xs'>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 17V11L7 13" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9 11L11 13" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M22 10V15C22 20 20 22 15 22H9C4 22 2 20 2 15V9C2 4 4 2 9 2H14" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M22 10H18C15 10 14 9 14 6V2L22 10Z" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
آپلود
</button>
</div>
</div>
{/* Other settings */}
<div className='mb-4'>
<div className='flex justify-end mb-2'>
<span className='text-sm text-gray-600'>سایر</span>
</div>
<div className='flex items-center justify-between border border-gray-200 rounded-lg p-2'>
<ArrowDown2 size={16} />
<span className='text-sm'>پوشش</span>
</div>
</div>
{/* Positioning options */}
<div>
{t('setting.title')}
<div className='flex justify-between mb-2'>
<div className='text-sm text-gray-600'>موقعیت افقی</div>
<div className='text-sm text-gray-600'>موقعیت عمودی</div>
</div>
<div className='flex justify-between'>
<div className='flex gap-1'>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.5 7H19.5M7.5 12H16.5M10.5 17H13.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 7H16.5M4.5 12H19.5M10.5 17H13.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 7H13.5M7.5 12H16.5M4.5 17H19.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
</div>
<div className='flex gap-1'>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 4.5V19.5M12 7.5V16.5M17 10.5V13.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 7.5V16.5M12 4.5V19.5M17 10.5V13.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
<button className='w-7 h-7 border border-gray-200 rounded flex items-center justify-center'>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 10.5V13.5M12 7.5V16.5M17 4.5V19.5" stroke="#292D32" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</button>
</div>
</div>
<div className='w-fit pr-6 flex flex-col items-end border-r border-border'>
<img src={Logo} className='w-8' />
<div className='flex flex-col gap-6 mt-14'>
<Setting4 size={20} color='black' variant='Bold' />
<Text size={20} color='black' />
<LinkSquare size={20} color='black' />
<Gallery size={20} color='black' />
<Shapes size={20} color='black' />
</div>
</div>
<div className='w-20 border-r border-gray-200 flex flex-col items-center pt-6 pb-6'>
<img src={Logo} className='w-8' alt="Logo" />
<div className='flex flex-col gap-10 mt-16'>
<Setting4 size={22} color='black' variant='Bold' />
<Text size={22} color='black' />
<LinkSquare size={22} color='black' />
<Gallery size={22} color='black' />
<Shapes size={22} color='black' />
</div>
</div>
</div>
)
}
export default Setting
export default PersonalitySidebar
+6
View File
@@ -5,6 +5,9 @@ import Home from '@/pages/home/Home'
import ReceivedList from '@/pages/received/List'
import Setting from '@/pages/setting/Setting'
import SentList from '@/pages/sent/List'
import DraftList from '@/pages/draft/List'
import ArchiveList from '@/pages/archive/List'
import TrashList from '@/pages/Trash/List'
const AppRouter: FC = () => {
return (
<Routes>
@@ -12,6 +15,9 @@ const AppRouter: FC = () => {
<Route path={Paths.received} element={<ReceivedList />} />
<Route path={Paths.setting} element={<Setting />} />
<Route path={Paths.sent} element={<SentList />} />
<Route path={Paths.draft} element={<DraftList />} />
<Route path={Paths.archive} element={<ArchiveList />} />
<Route path={Paths.trash} element={<TrashList />} />
</Routes>
)
}