structure + sidebar
This commit is contained in:
+9
-1
@@ -11,9 +11,17 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"i18next": "^25.0.1",
|
||||
"iconsax-react": "^0.0.8",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"tailwindcss": "^4.1.4"
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-router-dom": "^7.5.2",
|
||||
"react-spinners": "^0.17.0",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"zustand": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
|
||||
Generated
+253
@@ -11,15 +11,39 @@ importers:
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
i18next:
|
||||
specifier: ^25.0.1
|
||||
version: 25.0.1(typescript@5.7.3)
|
||||
iconsax-react:
|
||||
specifier: ^0.0.8
|
||||
version: 0.0.8(react@19.1.0)
|
||||
react:
|
||||
specifier: ^19.0.0
|
||||
version: 19.1.0
|
||||
react-dom:
|
||||
specifier: ^19.0.0
|
||||
version: 19.1.0(react@19.1.0)
|
||||
react-i18next:
|
||||
specifier: ^15.5.1
|
||||
version: 15.5.1(i18next@25.0.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3)
|
||||
react-router-dom:
|
||||
specifier: ^7.5.2
|
||||
version: 7.5.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react-spinners:
|
||||
specifier: ^0.17.0
|
||||
version: 0.17.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
tailwind-merge:
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0
|
||||
tailwindcss:
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4
|
||||
vite-tsconfig-paths:
|
||||
specifier: ^5.1.4
|
||||
version: 5.1.4(typescript@5.7.3)(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
zustand:
|
||||
specifier: ^5.0.3
|
||||
version: 5.0.3(@types/react@19.1.2)(react@19.1.0)
|
||||
devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^9.22.0
|
||||
@@ -128,6 +152,10 @@ packages:
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0-0
|
||||
|
||||
'@babel/runtime@7.27.0':
|
||||
resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.27.0':
|
||||
resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -709,6 +737,10 @@ packages:
|
||||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
cookie@1.0.2:
|
||||
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -877,6 +909,9 @@ packages:
|
||||
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globrex@0.1.2:
|
||||
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
||||
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
@@ -887,6 +922,22 @@ packages:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
html-parse-stringify@3.0.1:
|
||||
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
|
||||
|
||||
i18next@25.0.1:
|
||||
resolution: {integrity: sha512-8S8PyZbrymJZn3DaN70/34JYWNhsqrU6yA4MuzcygJBv+41dgNMocEA8h+kV1P7MCc1ll03lOTOIXE7mpNCicw==}
|
||||
peerDependencies:
|
||||
typescript: ^5
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
iconsax-react@0.0.8:
|
||||
resolution: {integrity: sha512-l3dVk4zGtkkJHgvNYqAf0wDKqnKxXykee5/DoESGo2JvSYwaxajJUHSX2YrPRXSov8Hd8ClGFwJxCEaEjrFD1Q==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
ignore@5.3.2:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
@@ -1022,6 +1073,10 @@ packages:
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
loose-envify@1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
|
||||
lru-cache@5.1.1:
|
||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
|
||||
@@ -1054,6 +1109,10 @@ packages:
|
||||
node-releases@2.0.19:
|
||||
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
optionator@0.9.4:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@@ -1097,6 +1156,9 @@ packages:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
punycode@2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -1109,14 +1171,59 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^19.1.0
|
||||
|
||||
react-i18next@15.5.1:
|
||||
resolution: {integrity: sha512-C8RZ7N7H0L+flitiX6ASjq9p5puVJU1Z8VyL3OgM/QOMRf40BMZX+5TkpxzZVcTmOLPX5zlti4InEX5pFyiVeA==}
|
||||
peerDependencies:
|
||||
i18next: '>= 23.2.3'
|
||||
react: '>= 16.8.0'
|
||||
react-dom: '*'
|
||||
react-native: '*'
|
||||
typescript: ^5
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
|
||||
react-refresh@0.17.0:
|
||||
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
react-router-dom@7.5.2:
|
||||
resolution: {integrity: sha512-yk1XW8Fj7gK7flpYBXF3yzd2NbX6P7Kxjvs2b5nu1M04rb5pg/Zc4fGdBNTeT4eDYL2bvzWNyKaIMJX/RKHTTg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
|
||||
react-router@7.5.2:
|
||||
resolution: {integrity: sha512-9Rw8r199klMnlGZ8VAsV/I8WrIF6IyJ90JQUdboupx1cdkgYqwnrYjH+I/nY/7cA1X5zia4mDJqH36npP7sxGQ==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
react-spinners@0.17.0:
|
||||
resolution: {integrity: sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ==}
|
||||
peerDependencies:
|
||||
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@19.1.0:
|
||||
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
regenerator-runtime@0.14.1:
|
||||
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -1145,6 +1252,9 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
set-cookie-parser@2.7.1:
|
||||
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1165,6 +1275,9 @@ packages:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
tailwind-merge@3.2.0:
|
||||
resolution: {integrity: sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==}
|
||||
|
||||
tailwindcss@4.1.4:
|
||||
resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==}
|
||||
|
||||
@@ -1186,6 +1299,19 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4'
|
||||
|
||||
tsconfck@3.1.5:
|
||||
resolution: {integrity: sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==}
|
||||
engines: {node: ^18 || >=20}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
turbo-stream@2.4.0:
|
||||
resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==}
|
||||
|
||||
type-check@0.4.0:
|
||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@@ -1211,6 +1337,14 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
vite-tsconfig-paths@5.1.4:
|
||||
resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==}
|
||||
peerDependencies:
|
||||
vite: '*'
|
||||
peerDependenciesMeta:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
vite@6.3.3:
|
||||
resolution: {integrity: sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==}
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
@@ -1251,6 +1385,10 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
void-elements@3.1.0:
|
||||
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -1267,6 +1405,24 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
zustand@5.0.3:
|
||||
resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=18.0.0'
|
||||
immer: '>=9.0.6'
|
||||
react: '>=18.0.0'
|
||||
use-sync-external-store: '>=1.2.0'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
immer:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
use-sync-external-store:
|
||||
optional: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
@@ -1361,6 +1517,10 @@ snapshots:
|
||||
'@babel/core': 7.26.10
|
||||
'@babel/helper-plugin-utils': 7.26.5
|
||||
|
||||
'@babel/runtime@7.27.0':
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.1
|
||||
|
||||
'@babel/template@7.27.0':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.26.2
|
||||
@@ -1851,6 +2011,8 @@ snapshots:
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
cookie@1.0.2: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@@ -2044,12 +2206,29 @@ snapshots:
|
||||
|
||||
globals@16.0.0: {}
|
||||
|
||||
globrex@0.1.2: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
graphemer@1.4.0: {}
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
html-parse-stringify@3.0.1:
|
||||
dependencies:
|
||||
void-elements: 3.1.0
|
||||
|
||||
i18next@25.0.1(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
optionalDependencies:
|
||||
typescript: 5.7.3
|
||||
|
||||
iconsax-react@0.0.8(react@19.1.0):
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.0
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
@@ -2147,6 +2326,10 @@ snapshots:
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
loose-envify@1.4.0:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
|
||||
lru-cache@5.1.1:
|
||||
dependencies:
|
||||
yallist: 3.1.1
|
||||
@@ -2174,6 +2357,8 @@ snapshots:
|
||||
|
||||
node-releases@2.0.19: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
optionator@0.9.4:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
@@ -2213,6 +2398,12 @@ snapshots:
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prop-types@15.8.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
react-is: 16.13.1
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
@@ -2222,10 +2413,44 @@ snapshots:
|
||||
react: 19.1.0
|
||||
scheduler: 0.26.0
|
||||
|
||||
react-i18next@15.5.1(i18next@25.0.1(typescript@5.7.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
html-parse-stringify: 3.0.1
|
||||
i18next: 25.0.1(typescript@5.7.3)
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
typescript: 5.7.3
|
||||
|
||||
react-is@16.13.1: {}
|
||||
|
||||
react-refresh@0.17.0: {}
|
||||
|
||||
react-router-dom@7.5.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
react-router: 7.5.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
|
||||
react-router@7.5.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
cookie: 1.0.2
|
||||
react: 19.1.0
|
||||
set-cookie-parser: 2.7.1
|
||||
turbo-stream: 2.4.0
|
||||
optionalDependencies:
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react-spinners@0.17.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react@19.1.0: {}
|
||||
|
||||
regenerator-runtime@0.14.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
reusify@1.1.0: {}
|
||||
@@ -2266,6 +2491,8 @@ snapshots:
|
||||
|
||||
semver@7.7.1: {}
|
||||
|
||||
set-cookie-parser@2.7.1: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
@@ -2280,6 +2507,8 @@ snapshots:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
tailwind-merge@3.2.0: {}
|
||||
|
||||
tailwindcss@4.1.4: {}
|
||||
|
||||
tapable@2.2.1: {}
|
||||
@@ -2297,6 +2526,12 @@ snapshots:
|
||||
dependencies:
|
||||
typescript: 5.7.3
|
||||
|
||||
tsconfck@3.1.5(typescript@5.7.3):
|
||||
optionalDependencies:
|
||||
typescript: 5.7.3
|
||||
|
||||
turbo-stream@2.4.0: {}
|
||||
|
||||
type-check@0.4.0:
|
||||
dependencies:
|
||||
prelude-ls: 1.2.1
|
||||
@@ -2323,6 +2558,17 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)):
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.1.5(typescript@5.7.3)
|
||||
optionalDependencies:
|
||||
vite: 6.3.3(jiti@2.4.2)(lightningcss@1.29.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2):
|
||||
dependencies:
|
||||
esbuild: 0.25.3
|
||||
@@ -2336,6 +2582,8 @@ snapshots:
|
||||
jiti: 2.4.2
|
||||
lightningcss: 1.29.2
|
||||
|
||||
void-elements@3.1.0: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
@@ -2345,3 +2593,8 @@ snapshots:
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
zustand@5.0.3(@types/react@19.1.2)(react@19.1.0):
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.2
|
||||
react: 19.1.0
|
||||
|
||||
+20
-1
@@ -1,9 +1,28 @@
|
||||
import { FC } from 'react'
|
||||
import './assets/fonts/irancell/style.css'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import Main from './shared/Main'
|
||||
import i18next from 'i18next'
|
||||
import FaJson from './langs/fa.json'
|
||||
import { I18nextProvider } from 'react-i18next'
|
||||
i18next.init({
|
||||
interpolation: { escapeValue: false },
|
||||
lng: 'fa',
|
||||
defaultNS: 'global',
|
||||
resources: {
|
||||
fa: {
|
||||
global: FaJson
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const App: FC = () => {
|
||||
return (
|
||||
<div>App</div>
|
||||
<BrowserRouter>
|
||||
<I18nextProvider i18n={i18next}>
|
||||
<Main />
|
||||
</I18nextProvider>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 961.6 222.5" style="enable-background:new 0 0 961.6 222.5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1D1D1B;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M246,180.4h-8.7v24.3h-3.6v-24.3H225v-2.9h21V180.4z"/>
|
||||
<path class="st0" d="M279.1,205c-2.7,0-5-0.9-6.7-2.7s-2.6-4.2-2.6-7.2v-0.6c0-2,0.4-3.8,1.1-5.4s1.8-2.8,3.2-3.7
|
||||
s2.9-1.3,4.5-1.3c2.6,0,4.7,0.9,6.1,2.6c1.5,1.7,2.2,4.2,2.2,7.4v1.4h-13.7c0,2,0.6,3.6,1.7,4.8s2.5,1.8,4.2,1.8
|
||||
c1.2,0,2.3-0.2,3.1-0.7s1.6-1.2,2.2-2l2.1,1.6C285,203.7,282.5,205,279.1,205z M278.7,186.9c-1.4,0-2.6,0.5-3.5,1.5
|
||||
s-1.5,2.4-1.8,4.3h10.1v-0.3c-0.1-1.8-0.6-3.1-1.4-4.1C281.3,187.4,280.1,186.9,278.7,186.9z"/>
|
||||
<path class="st0" d="M320.4,202.2c1.2,0,2.3-0.4,3.2-1.1c0.9-0.7,1.4-1.7,1.5-2.8h3.3c-0.1,1.2-0.5,2.3-1.2,3.3
|
||||
s-1.7,1.9-2.9,2.5c-1.2,0.6-2.5,0.9-3.9,0.9c-2.8,0-4.9-0.9-6.6-2.8c-1.6-1.8-2.4-4.3-2.4-7.5v-0.6c0-2,0.4-3.7,1.1-5.2
|
||||
s1.8-2.7,3.1-3.6c1.4-0.8,2.9-1.3,4.8-1.3c2.3,0,4.1,0.7,5.6,2c1.5,1.4,2.3,3.1,2.4,5.3h-3.3c-0.1-1.3-0.6-2.4-1.5-3.2
|
||||
s-2-1.3-3.3-1.3c-1.8,0-3.1,0.6-4.1,1.9s-1.4,3.1-1.4,5.5v0.7c0,2.3,0.5,4.1,1.4,5.4C317.2,201.6,318.6,202.2,320.4,202.2z"/>
|
||||
<path class="st0" d="M357,186.9c1.5-1.9,3.5-2.8,6-2.8c4.3,0,6.4,2.4,6.5,7.2v13.4H366v-13.4c0-1.5-0.3-2.5-1-3.2s-1.7-1-3.1-1
|
||||
c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.4v-28.7h3.5V186.9z"/>
|
||||
<path class="st0" d="M399.1,184.5l0.1,2.5c1.5-1.9,3.6-2.9,6.1-2.9c4.3,0,6.4,2.4,6.5,7.2v13.4h-3.5v-13.4c0-1.5-0.3-2.5-1-3.2
|
||||
s-1.7-1-3.1-1c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.5v-20.2h3.4V184.5z"/>
|
||||
<path class="st0" d="M437.3,194.4c0-2,0.4-3.8,1.2-5.3c0.8-1.6,1.9-2.8,3.2-3.7s3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9
|
||||
s2.5,4.4,2.5,7.6v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7c-1.4,0.9-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9s-2.5-4.4-2.5-7.6v-0.2
|
||||
H437.3z M440.8,194.8c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2c1.8,0,3.1-0.7,4.2-2.1s1.6-3.3,1.6-5.8c0-2.2-0.5-4-1.6-5.4
|
||||
s-2.5-2.1-4.2-2.1s-3.1,0.7-4.1,2C441.3,190.3,440.8,192.3,440.8,194.8z"/>
|
||||
<path class="st0" d="M485.1,204.7h-3.5V176h3.5V204.7z"/>
|
||||
<path class="st0" d="M511,194.4c0-2,0.4-3.8,1.2-5.3c0.8-1.5,1.9-2.8,3.2-3.7c1.4-0.9,3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9
|
||||
s2.5,4.4,2.5,7.6v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7s-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9c-1.7-1.9-2.5-4.4-2.5-7.6v-0.2
|
||||
H511z M514.4,194.8c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2s3.2-0.7,4.2-2.1c1-1.4,1.5-3.3,1.5-5.8c0-2.2-0.5-4-1.6-5.4
|
||||
s-2.5-2.1-4.2-2.1s-3.1,0.7-4.1,2C515,190.3,514.4,192.3,514.4,194.8z"/>
|
||||
<path class="st0" d="M554.1,194.4c0-3.2,0.7-5.7,2.2-7.5s3.4-2.8,5.8-2.8c2.5,0,4.4,0.9,5.8,2.6l0.2-2.2h3.2v19.7
|
||||
c0,2.6-0.8,4.7-2.3,6.2c-1.6,1.5-3.6,2.3-6.2,2.3c-1.5,0-2.9-0.3-4.3-0.9c-1.4-0.6-2.5-1.5-3.2-2.6l1.8-2.1
|
||||
c1.5,1.8,3.3,2.7,5.4,2.7c1.7,0,3-0.5,3.9-1.4s1.4-2.3,1.4-4v-1.7c-1.4,1.6-3.3,2.4-5.7,2.4s-4.3-1-5.7-2.9
|
||||
S554.1,197.7,554.1,194.4z M557.6,194.8c0,2.3,0.5,4.1,1.4,5.4c0.9,1.3,2.2,2,3.9,2c2.2,0,3.8-1,4.8-3V190
|
||||
c-1.1-1.9-2.6-2.9-4.8-2.9c-1.7,0-3,0.7-3.9,2C558.1,190.3,557.6,192.2,557.6,194.8z"/>
|
||||
<path class="st0" d="M604.3,199.6l4.7-15.1h3.7l-8.1,23.3c-1.3,3.4-3.3,5-6,5l-0.7-0.1l-1.3-0.2v-2.8l0.9,0.1
|
||||
c1.2,0,2.1-0.2,2.7-0.7c0.7-0.5,1.2-1.3,1.6-2.6l0.8-2.1l-7.2-20h3.8L604.3,199.6z"/>
|
||||
<path class="st0" d="M688.3,196c-0.3,2.9-1.4,5.1-3.2,6.7c-1.8,1.6-4.2,2.3-7.1,2.3c-3.2,0-5.8-1.2-7.7-3.5s-2.9-5.4-2.9-9.2
|
||||
v-2.6c0-2.5,0.5-4.8,1.4-6.7s2.2-3.4,3.8-4.4s3.6-1.5,5.8-1.5c2.9,0,5.2,0.8,6.9,2.4c1.7,1.6,2.8,3.8,3,6.7h-3.6
|
||||
c-0.3-2.2-1-3.7-2-4.7s-2.5-1.5-4.4-1.5c-2.3,0-4.1,0.8-5.4,2.5c-1.3,1.7-2,4.1-2,7.2v2.6c0,3,0.6,5.3,1.8,7s3,2.6,5.2,2.6
|
||||
c2,0,3.5-0.5,4.6-1.4s1.8-2.5,2.1-4.7h3.7V196z"/>
|
||||
<path class="st0" d="M713,194.4c0-2,0.4-3.8,1.2-5.3s1.9-2.8,3.2-3.7c1.4-0.9,3-1.3,4.8-1.3c2.8,0,5,1,6.7,2.9s2.5,4.4,2.5,7.6
|
||||
v0.2c0,2-0.4,3.7-1.1,5.3s-1.8,2.8-3.2,3.7s-3,1.3-4.8,1.3c-2.7,0-5-1-6.7-2.9s-2.5-4.4-2.5-7.6v-0.2H713z M716.5,194.8
|
||||
c0,2.2,0.5,4,1.6,5.4c1,1.4,2.4,2,4.2,2s3.2-0.7,4.2-2.1c1-1.4,1.5-3.3,1.5-5.8c0-2.2-0.5-4-1.6-5.4s-2.5-2.1-4.2-2.1
|
||||
s-3.1,0.7-4.1,2C717,190.3,716.5,192.3,716.5,194.8z"/>
|
||||
<path class="st0" d="M760.3,184.5l0.1,2.2c1.5-1.7,3.5-2.6,6-2.6c2.8,0,4.8,1.1,5.8,3.2c0.7-1,1.5-1.8,2.6-2.4
|
||||
c1.1-0.6,2.4-0.9,3.8-0.9c4.4,0,6.7,2.3,6.8,7v13.5h-3.5v-13.3c0-1.4-0.3-2.5-1-3.2s-1.8-1.1-3.3-1.1c-1.3,0-2.3,0.4-3.2,1.1
|
||||
c-0.8,0.8-1.3,1.8-1.5,3.1v13.4h-3.5v-13.2c0-2.9-1.4-4.4-4.3-4.4c-2.3,0-3.8,1-4.7,2.9v14.8h-3.5v-20.2h3.4V184.5z"/>
|
||||
<path class="st0" d="M828.9,194.8c0,3.1-0.7,5.6-2.1,7.4c-1.4,1.9-3.3,2.8-5.7,2.8c-2.5,0-4.4-0.8-5.8-2.3v9.7h-3.5v-28h3.2
|
||||
l0.2,2.2c1.4-1.7,3.4-2.6,5.9-2.6c2.4,0,4.3,0.9,5.8,2.7c1.4,1.8,2.1,4.4,2.1,7.6v0.5H828.9z M825.5,194.4
|
||||
c0-2.3-0.5-4.1-1.5-5.4c-1-1.3-2.3-2-4-2c-2.1,0-3.7,0.9-4.7,2.8v9.7c1,1.8,2.6,2.8,4.7,2.8c1.7,0,3-0.7,4-2
|
||||
S825.5,197,825.5,194.4z"/>
|
||||
<path class="st0" d="M867,204.7c-0.2-0.4-0.4-1.1-0.5-2.1c-1.6,1.7-3.5,2.5-5.8,2.5c-2,0-3.6-0.6-4.9-1.7s-1.9-2.6-1.9-4.3
|
||||
c0-2.1,0.8-3.7,2.4-4.9c1.6-1.2,3.9-1.7,6.8-1.7h3.4v-1.7c0-1.2-0.4-2.2-1.1-2.9c-0.7-0.7-1.8-1.1-3.2-1.1
|
||||
c-1.2,0-2.3,0.3-3.1,0.9c-0.8,0.6-1.3,1.4-1.3,2.3h-3.5c0-1,0.4-2,1.1-2.9c0.7-0.9,1.7-1.7,2.9-2.2s2.6-0.8,4-0.8
|
||||
c2.3,0,4.2,0.6,5.5,1.7c1.3,1.2,2,2.8,2.1,4.8v9.3c0,1.9,0.2,3.3,0.7,4.4v0.3H867V204.7z M861.3,202c1.1,0,2.1-0.3,3.1-0.8
|
||||
c1-0.6,1.7-1.3,2.1-2.2v-4.1h-2.7c-4.2,0-6.4,1.2-6.4,3.7c0,1.1,0.4,1.9,1.1,2.5C859.2,201.7,860.2,202,861.3,202z"/>
|
||||
<path class="st0" d="M899.9,184.5l0.1,2.5c1.5-1.9,3.6-2.9,6.1-2.9c4.3,0,6.4,2.4,6.5,7.2v13.4h-3.5v-13.4c0-1.5-0.3-2.5-1-3.2
|
||||
s-1.7-1-3.1-1c-1.1,0-2.1,0.3-3,0.9s-1.5,1.4-2,2.4v14.4h-3.5v-20.2h3.4V184.5z"/>
|
||||
<path class="st0" d="M945.6,199.6l4.7-15.1h3.7l-8.1,23.3c-1.3,3.4-3.3,5-6,5l-0.7-0.1l-1.3-0.2v-2.8l0.9,0.1
|
||||
c1.2,0,2.1-0.2,2.7-0.7c0.7-0.5,1.2-1.3,1.6-2.6l0.8-2.1l-7.2-20h3.8L945.6,199.6z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st0" d="M221.6,148.7V44.1h29.5c9.1,0,17.1,2,24.1,6s12.4,9.7,16.2,17.2c3.8,7.4,5.7,15.9,5.8,25.6v6.7
|
||||
c0,9.9-1.9,18.5-5.7,25.9c-3.8,7.4-9.2,13.1-16.3,17.1c-7.1,4-15.3,6-24.7,6.1L221.6,148.7L221.6,148.7z M235.4,55.4v82h14.5
|
||||
c10.6,0,18.9-3.3,24.8-9.9c5.9-6.6,8.9-16,8.9-28.3v-6.1c0-11.9-2.8-21.1-8.4-27.7s-13.5-9.9-23.7-10L235.4,55.4L235.4,55.4z"/>
|
||||
<path class="st0" d="M627.1,148.7h-13.9l-52.7-80.6v80.6h-13.9V44.1h13.9l52.8,81v-81H627v104.6H627.1z"/>
|
||||
<path class="st0" d="M900.9,100.1l-12.8,13.3v35.3h-13.8V44.1h13.8v51.7l46.5-51.7h16.7l-41.2,46.2l44.4,58.4H938L900.9,100.1z"/>
|
||||
<polygon class="st0" points="423.2,61.1 455.1,148.7 469.2,148.7 429.2,44.1 417.1,44.1 377.2,148.7 391.4,148.7 "/>
|
||||
<polygon class="st0" points="750.6,61.1 782.6,148.7 796.7,148.7 756.7,44.1 744.6,44.1 704.7,148.7 718.9,148.7 "/>
|
||||
</g>
|
||||
<path class="st0" d="M132.1,140.4c0,0-26.1,25.2-48,46.5v28.9c-2.2,1.7,77.6-75.4,77.6-75.4L84.1,59v31L132.1,140.4z"/>
|
||||
<g>
|
||||
<polygon class="st0" points="83.7,157.5 6.5,75.1 7.5,74.2 84.7,156.6 "/>
|
||||
<polygon class="st0" points="83.7,149.8 13.6,75.2 14.6,74.3 84.6,148.9 "/>
|
||||
<polygon class="st0" points="83.7,142.1 20.7,75.4 21.7,74.4 84.6,141.1 "/>
|
||||
<polygon class="st0" points="83.6,134.3 27.8,75.5 28.7,74.6 84.6,133.4 "/>
|
||||
<polygon class="st0" points="83.6,126.6 34.9,75.6 35.8,74.7 84.6,125.7 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st0" points="8,75.5 7.1,74.5 83.7,0 84.6,0.9 "/>
|
||||
<polygon class="st0" points="15.2,75.5 14.3,74.6 83.6,7 84.5,7.9 "/>
|
||||
<polygon class="st0" points="22.4,75.6 21.4,74.7 83.6,14 84.5,14.9 "/>
|
||||
<polygon class="st0" points="29.5,75.6 28.6,74.7 83.5,21 84.4,22 "/>
|
||||
<polygon class="st0" points="36.7,75.7 35.7,74.8 83.5,28 84.4,29 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
@@ -0,0 +1,40 @@
|
||||
import { ButtonHTMLAttributes, FC, memo, ReactNode } from 'react'
|
||||
import MoonLoader from "react-spinners/MoonLoader"
|
||||
import { XOR } from '../helpers/types'
|
||||
import { clx } from '../helpers/utils'
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
isLoading?: boolean,
|
||||
percentage?: number,
|
||||
} & ButtonHTMLAttributes<HTMLButtonElement> &
|
||||
XOR<{ children: ReactNode }, { label: string }>;
|
||||
|
||||
const Button: FC<Props> = memo((props: Props) => {
|
||||
|
||||
const buttonClass = clx(
|
||||
'flex rounded-xl items-center justify-center text-center h-10 text-sm bg-primary text-white w-full',
|
||||
props.disabled && 'cursor-not-allowed opacity-60',
|
||||
props.className
|
||||
);
|
||||
|
||||
return (
|
||||
<button {...props} className={`${buttonClass} ${props.className}`} >
|
||||
{
|
||||
props.isLoading ?
|
||||
<div className='flex gap-2 items-center'>
|
||||
{
|
||||
!props.percentage ?
|
||||
<MoonLoader size={20} color='#fff' />
|
||||
:
|
||||
<span>{props.percentage}%</span>
|
||||
}
|
||||
</div>
|
||||
:
|
||||
props.label || props.children
|
||||
}
|
||||
</button>
|
||||
)
|
||||
})
|
||||
|
||||
export default Button
|
||||
@@ -0,0 +1,15 @@
|
||||
import { FC } from 'react'
|
||||
|
||||
type Props = {
|
||||
errorText: string
|
||||
}
|
||||
|
||||
const Error: FC<Props> = (props: Props) => {
|
||||
return (
|
||||
<div className='mt-1.5 font-normal text-red-500 text-[11px]'>
|
||||
{props.errorText}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Error
|
||||
@@ -0,0 +1,115 @@
|
||||
import { FC, InputHTMLAttributes, useEffect, useState } from 'react'
|
||||
import { clx } from '../helpers/utils';
|
||||
import { Eye, SearchNormal } from 'iconsax-react';
|
||||
import Error from './Error';
|
||||
|
||||
type Variant = "floating_outlined" | "primary" | "search";
|
||||
|
||||
type Props = {
|
||||
label?: string;
|
||||
className?: string;
|
||||
variant?: Variant;
|
||||
error_text?: string;
|
||||
onEnter?: () => void;
|
||||
unit?: string;
|
||||
seprator?: boolean;
|
||||
isNotRequired?: boolean;
|
||||
onChangeSearchFinal?: (value: string) => void;
|
||||
} & InputHTMLAttributes<HTMLInputElement>
|
||||
|
||||
const formatNumber = (value: string | number): string => {
|
||||
if (!value) return '';
|
||||
const inputValue = String(value).replace(/,/g, '');
|
||||
return inputValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
};
|
||||
|
||||
const Input: FC<Props> = (props: Props) => {
|
||||
|
||||
const [formattedValue, setFormattedValue] = useState<string>(
|
||||
props.value ? formatNumber(props.value as string) : ''
|
||||
);
|
||||
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false)
|
||||
const [search, setSearch] = useState<string>('')
|
||||
|
||||
const inputClass = clx(
|
||||
'w-full h-10 text-black block px-4 text-xs rounded-xl border border-border',
|
||||
props.readOnly && 'bg-gray-100 border-0 text-description',
|
||||
props.variant === 'search' && 'bg-[#EEF0F7] border-0 ps-10',
|
||||
props.className
|
||||
);
|
||||
|
||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (props.seprator) {
|
||||
const inputValue = event.target.value.replace(/,/g, ''); // حذف کاماها
|
||||
const formatted = formatNumber(inputValue);
|
||||
|
||||
// بهروزرسانی مقدار قالببندیشده
|
||||
setFormattedValue(formatted);
|
||||
|
||||
// ارسال مقدار خام به `onChange` والد
|
||||
props.onChange?.({
|
||||
...event,
|
||||
target: {
|
||||
...event.target,
|
||||
value: inputValue,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
props.onChange?.(event);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (props.value) {
|
||||
setFormattedValue(formatNumber(props.value as string));
|
||||
} else {
|
||||
setFormattedValue('');
|
||||
}
|
||||
}, [props.value])
|
||||
|
||||
useEffect(() => {
|
||||
if (props.variant === 'search' && props.onChangeSearchFinal) {
|
||||
const timeout = setTimeout(() => {
|
||||
props.onChangeSearchFinal?.(search)
|
||||
}, 1000)
|
||||
return () => clearTimeout(timeout)
|
||||
}
|
||||
}, [search, props])
|
||||
|
||||
|
||||
return (
|
||||
<div className='w-full'>
|
||||
<label className='text-sm'>
|
||||
{props.label}
|
||||
</label>
|
||||
|
||||
<div className='w-full relative mt-1'>
|
||||
<input {...props} onChange={(e) => {
|
||||
setSearch(e.target.value)
|
||||
handleInputChange(e)
|
||||
}} value={props.seprator ? formattedValue : props.value} type={props.type === 'password' && showPassword ? 'text' : props.type === 'password' ? 'password' : undefined} className={inputClass} />
|
||||
|
||||
{
|
||||
props.type === 'password' &&
|
||||
<Eye onClick={() => setShowPassword((oldValue) => !oldValue)} size={20} color='#8C90A3' className='absolute top-0 bottom-0 cursor-pointer my-auto left-3' />
|
||||
// <img onClick={() => setShowPassword((oldValue) => !oldValue)} src={EyeIcon} className='w-5 absolute top-0 bottom-0 cursor-pointer my-auto left-3' />
|
||||
}
|
||||
|
||||
{
|
||||
props.variant === 'search' &&
|
||||
<SearchNormal size={20} color='#8C90A3' className='absolute top-0 w-5 bottom-0 my-auto right-3' />
|
||||
}
|
||||
|
||||
{
|
||||
props.error_text &&
|
||||
<Error
|
||||
errorText={props.error_text}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Input
|
||||
@@ -0,0 +1,20 @@
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
|
||||
export type XOR<T, U> = T | U extends object
|
||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||
: T | U;
|
||||
|
||||
export type ItemsSelectType = {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type ErrorType = Error & {
|
||||
response?: {
|
||||
data?: {
|
||||
error: {
|
||||
message: string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
/**
|
||||
* Concatenates truthy classes into a space-separated string.
|
||||
*
|
||||
* @param classes - The classes to concatenate.
|
||||
* @returns The concatenated classes.
|
||||
*/
|
||||
export const clx = (...classes: (string | boolean | undefined)[]): string => {
|
||||
return twMerge(classes.filter(Boolean).join(" "));
|
||||
};
|
||||
@@ -40,3 +40,9 @@ input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--color-primary: #000000;
|
||||
--color-secondary: #eaecf4;
|
||||
--color-description: #888888;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"sidebar": {
|
||||
"menu": "منو",
|
||||
"received": "دریافتی ها",
|
||||
"sent": "ارسال شده ها",
|
||||
"draft": "پیش نویس ها",
|
||||
"archive": "آرشیو شده ها",
|
||||
"profile": "پروفایل",
|
||||
"trash": "سطل زباله",
|
||||
"other": "سایر",
|
||||
"favorite": "نشان شده ها",
|
||||
"spam": "هرزنامه ها",
|
||||
"setting": "تنظیمات",
|
||||
"logout": "خروج",
|
||||
"new_message": "پیام جدید"
|
||||
},
|
||||
"header": {
|
||||
"search": "جستجو"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { FC } from 'react'
|
||||
|
||||
const Home: FC = () => {
|
||||
return (
|
||||
<div>home page</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
@@ -0,0 +1,13 @@
|
||||
import { FC } from 'react'
|
||||
import { Routes, Route } from 'react-router-dom'
|
||||
import Home from '@/pages/home/Home'
|
||||
|
||||
const AppRouter: FC = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path='/' element={<Home />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
||||
export default AppRouter
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Element3, Element4, Home2, Messages3, NotificationStatus } from 'iconsax-react'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pages } from '../config/Pages'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
|
||||
const Footer: FC = () => {
|
||||
const { t } = useTranslation('global')
|
||||
const location = useLocation()
|
||||
|
||||
const isActive = (path: string) => location.pathname === path
|
||||
|
||||
return (
|
||||
<div className='xl:hidden'>
|
||||
<div className='h-[60px] '></div>
|
||||
<div className='fixed z-10 bottom-2 right-3 left-3 bg-white h-[60px] rounded-2xl flex justify-between items-center px-3'>
|
||||
<Link to={Pages.services.mine}>
|
||||
<div className={`text-description w-[70px] flex flex-col items-center gap-1.5 ${isActive(Pages.dashboard) ? 'text-black' : ''}`}>
|
||||
<Element4
|
||||
className='size-5'
|
||||
color={isActive(Pages.services.mine) ? 'black' : '#8C90A3'}
|
||||
variant={isActive(Pages.services.mine) ? 'Bold' : 'Linear'}
|
||||
/>
|
||||
<div className={`text-[10px] ${isActive(Pages.services.mine) ? 'text-black' : ''}`}>
|
||||
{t('footer.my_services')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.services.other}>
|
||||
<div className={`text-description w-[70px] flex flex-col items-center gap-1.5 ${isActive(Pages.services.other) ? 'text-black' : ''}`}>
|
||||
<Element3
|
||||
className='size-5'
|
||||
color={isActive(Pages.services.other) ? 'black' : '#8C90A3'}
|
||||
variant={isActive(Pages.services.other) ? 'Bold' : 'Linear'}
|
||||
/>
|
||||
<div className={`text-[10px] ${isActive(Pages.services.other) ? 'text-black' : ''}`}>
|
||||
{t('footer.other_services')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.dashboard}>
|
||||
<div className={`text-description w-[70px] flex flex-col items-center gap-1.5 ${isActive(Pages.services.mine) ? 'text-black' : ''}`}>
|
||||
<div className='bg-white p-1 rounded-full -mt-7'>
|
||||
<div className={`bg-black flex justify-center items-center size-10 rounded-full ${isActive(Pages.services.mine) ? 'bg-black' : ''}`}>
|
||||
<Home2
|
||||
className='size-5'
|
||||
color={isActive(Pages.dashboard) ? 'white' : 'white'}
|
||||
variant={isActive(Pages.dashboard) ? 'Bold' : 'Linear'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`text-[10px] ${isActive(Pages.services.mine) ? 'text-black' : ''}`}>
|
||||
{t('footer.home')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.announcement.list}>
|
||||
<div className={`text-description w-[70px] flex flex-col items-center gap-1.5 ${isActive(Pages.announcement.list) ? 'text-black' : ''}`}>
|
||||
<NotificationStatus
|
||||
className='size-5'
|
||||
color={isActive(Pages.announcement.list) ? 'black' : '#8C90A3'}
|
||||
variant={isActive(Pages.announcement.list) ? 'Bold' : 'Linear'}
|
||||
/>
|
||||
<div className={`text-[10px] ${isActive(Pages.announcement.list) ? 'text-black' : ''}`}>
|
||||
{t('footer.announcements')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.ticket.list}>
|
||||
<div className={`text-description w-[70px] flex flex-col items-center gap-1.5 ${isActive(Pages.ticket.list) ? 'text-black' : ''}`}>
|
||||
<Messages3
|
||||
className='size-5'
|
||||
color={isActive(Pages.ticket.list) ? 'black' : '#8C90A3'}
|
||||
variant={isActive(Pages.ticket.list) ? 'Bold' : 'Linear'}
|
||||
/>
|
||||
<div className={`text-[10px] ${isActive(Pages.ticket.list) ? 'text-black' : ''}`}>
|
||||
{t('footer.tickets')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Footer
|
||||
@@ -0,0 +1,173 @@
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import Input from '../components/Input'
|
||||
import { Element3, HambergerMenu, Wallet } from 'iconsax-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { Paths } from '@/utils/Paths'
|
||||
// import Notifications from '../pages/notification/Notification'
|
||||
import { useSharedStore } from './store/sharedStore'
|
||||
// import { useGetProfile } from '../pages/profile/hooks/useProfileData'
|
||||
// import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'
|
||||
// import { useGetWalletBalance } from '../pages/wallet/hooks/useWalletData'
|
||||
// import { NumberFormat } from '../config/func'
|
||||
|
||||
const Header: FC = () => {
|
||||
|
||||
const location = useLocation();
|
||||
const [popoverKey, setPopoverKey] = useState(0);
|
||||
const { t } = useTranslation('global')
|
||||
const { setOpenSidebar, openSidebar } = useSharedStore()
|
||||
// const { data } = useGetProfile()
|
||||
// const getWalletBalance = useGetWalletBalance()
|
||||
|
||||
console.log(popoverKey);
|
||||
useEffect(() => {
|
||||
|
||||
setPopoverKey((prevKey) => prevKey + 1);
|
||||
}, [location.pathname]);
|
||||
|
||||
return (
|
||||
<div className='fixed z-10 right-4 left-4 xl:right-[285px] top-4 xl:h-16 h-12 flex items-center px-6 bg-white justify-between rounded-[32px] xl:w-[calc(100%-305px)]'>
|
||||
|
||||
<div className='min-w-[270px] hidden xl:block'>
|
||||
<Input
|
||||
variant='search'
|
||||
placeholder={t('header.search')}
|
||||
/>
|
||||
</div>
|
||||
<div onClick={() => setOpenSidebar(!openSidebar)} className='xl:hidden block'>
|
||||
<HambergerMenu size={24} color='black' />
|
||||
</div>
|
||||
{/* <img src={LogoImage} className='h-6 xl:hidden block absolute right-0 left-0 mx-auto' /> */}
|
||||
<div className='flex xl:gap-6 gap-4 items-center'>
|
||||
<Link to={Paths.home}>
|
||||
<Element3 color='black' className='xl:size-[18px] size-[17px]' />
|
||||
</Link>
|
||||
<Link className='xl:hidden' to={Paths.home}>
|
||||
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
||||
</Link>
|
||||
<Link className='hidden xl:block' to={Paths.home}>
|
||||
<div className='flex items-center h-8 pl-2 rounded-full bg-[#EEF0F7]'>
|
||||
<div className='px-3 text-xs'>
|
||||
{/* {NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')} */}
|
||||
</div>
|
||||
<div className='size-[26px] flex justify-center items-center bg-white rounded-xl'>
|
||||
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
{/* <Notifications /> */}
|
||||
{/* {
|
||||
data && (
|
||||
<Popover className="relative" key={popoverKey}>
|
||||
<PopoverButton >
|
||||
<div className='flex gap-2 items-center mt-2.5'>
|
||||
<div className='size-6 rounded-full bg-description overflow-hidden'>
|
||||
<img src={data?.data?.user?.profilePic ? data?.data?.user?.profilePic : AvatarImage} className='size-full object-cover' />
|
||||
</div>
|
||||
<div className='xl:flex hidden gap-1 items-center'>
|
||||
<div className='text-xs'>
|
||||
{data?.data?.user?.firstName + ' ' + data?.data?.user?.lastName}
|
||||
</div>
|
||||
<ArrowDown2 size={14} color='#8C90A3' />
|
||||
</div>
|
||||
</div>
|
||||
</PopoverButton>
|
||||
|
||||
<PopoverPanel style={{ minHeight: window.innerWidth < 1140 ? window.innerHeight : undefined }} anchor="bottom" className="flex xl:ml-6 overflow-auto flex-col gap-3 bg-white boxShadow xl:mt-7 z-30 py-4 text-xs rounded-2.5 xl:w-[300px] -mt-[50px] w-full fixed xl:h-fit h-full shadow-md">
|
||||
<div className='absolute xl:hidden top-6 left-6'>
|
||||
<CloseCircle onClick={() => setPopoverKey((prevKey) => prevKey + 1)} size={20} color='black' />
|
||||
</div>
|
||||
<Link to={Pages.profile} className='flex flex-col gap-2 items-center justify-center border-b border-[#EAEDF5] pb-4'>
|
||||
<div className='size-14 rounded-full overflow-hidden'>
|
||||
<img src={data?.data?.user?.profilePic ? data?.data?.user?.profilePic : AvatarImage} className='size-full object-cover' />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{data?.data?.user?.firstName + ' ' + data?.data?.user?.lastName}
|
||||
</div>
|
||||
|
||||
<div className='text-description'>
|
||||
{data?.data?.user?.email}
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<div className='pb-6 px-6 border-b border-[#EAEDF5]'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<SideBarItem
|
||||
icon={<Wallet size={20} color='black' />}
|
||||
title={t('header.wallet')}
|
||||
link={Pages.wallet}
|
||||
isActive
|
||||
isWithoutLine
|
||||
/>
|
||||
<div className='flex xl:hidden items-center mt-4 h-8 pl-2 rounded-full bg-[#EEF0F7]'>
|
||||
<div className='ps-3'>{t('home.balance')}</div>
|
||||
<div className='px-3 text-xs'>
|
||||
{NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SideBarItem
|
||||
icon={<Card color={'black'} size={20} />}
|
||||
title={t('sidebar.transactions')}
|
||||
isActive
|
||||
link={Pages.transactions}
|
||||
isWithoutLine
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<TicketDiscount color={'black'} size={20} />}
|
||||
title={t('header.discounts')}
|
||||
isActive
|
||||
link={Pages.discounts}
|
||||
isWithoutLine
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<Receipt1 color={'black'} size={20} />}
|
||||
title={t('header.financial_info')}
|
||||
isActive
|
||||
link={Pages.financial}
|
||||
isWithoutLine
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<ProfileCircle color={'black'} size={20} />}
|
||||
title={t('header.profile')}
|
||||
isActive
|
||||
link={Pages.profile}
|
||||
isWithoutLine
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<Setting2 color={'black'} size={20} />}
|
||||
title={t('header.setting')}
|
||||
isActive
|
||||
link={Pages.setting}
|
||||
isWithoutLine
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='px-6 -mt-[2px]'>
|
||||
<SideBarItem
|
||||
icon={<Logout color={'black'} size={20} />}
|
||||
title={t('sidebar.logout')}
|
||||
isActive
|
||||
link={Pages.setting}
|
||||
isWithoutLine
|
||||
isLogout
|
||||
/>
|
||||
</div>
|
||||
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
)
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
||||
@@ -0,0 +1,15 @@
|
||||
import { FC } from 'react'
|
||||
import SideBar from './SideBar'
|
||||
import Header from './Header'
|
||||
|
||||
const Main: FC = () => {
|
||||
return (
|
||||
<div className='p-4 overflow-hidden'>
|
||||
<SideBar />
|
||||
<Header />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Main
|
||||
@@ -0,0 +1,135 @@
|
||||
import { FC } from 'react'
|
||||
import LogoImage from '../assets/images/logo.svg'
|
||||
import { Add, ArchiveTick, DirectInbox, DirectSend, Edit, InfoCircle, Logout, Setting2, Star, Trash } from 'iconsax-react'
|
||||
import SideBarItem from './SideBarItem'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { useSharedStore } from './store/sharedStore'
|
||||
import { clx } from '../helpers/utils'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Paths } from '@/utils/Paths'
|
||||
import Button from '@/components/Button'
|
||||
|
||||
const SideBar: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { openSidebar, setOpenSidebar } = useSharedStore()
|
||||
const location = useLocation()
|
||||
|
||||
const isActive = (path: string) => location.pathname === path
|
||||
|
||||
const iconSizeSideBar = 20
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
openSidebar && <div className='fixed top-0 left-0 right-0 bottom-0 bg-black bg-opacity-50 z-10' onClick={() => setOpenSidebar(false)} />
|
||||
}
|
||||
<div
|
||||
className={clx(
|
||||
'fixed xl:flex flex-1 translate-x-[400px] xl:translate-x-0 transition-all ease-in-out opacity-0 invisible xl:visible xl:opacity-100 xl:right-4 right-0 xl:top-4 top-0 xl:bottom-4 bottom-0 xl:rounded-[32px] w-[250px] bg-white flex-col py-12',
|
||||
openSidebar && 'opacity-100 visible -translate-x-[0px] block z-40'
|
||||
)}
|
||||
>
|
||||
<div className='flex justify-center'>
|
||||
<img src={LogoImage} className='w-[140px]' />
|
||||
</div>
|
||||
|
||||
<div className='flex justify-center mt-14'>
|
||||
<Button
|
||||
className='bg-secondary font-normal text-primary w-fit px-6'
|
||||
>
|
||||
<div className='flex gap-2'>
|
||||
<Add size={20} color='black' />
|
||||
<div>{t('sidebar.new_message')}</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className='flex-1 flex flex-col h-full overflow-y-auto no-scrollbar'>
|
||||
<div className='mt-10 px-12 text-[#C3C7DD] text-sm font-bold'>
|
||||
{t('sidebar.menu')}
|
||||
</div>
|
||||
|
||||
<div className='text-xs text-[#8C90A3]'>
|
||||
<SideBarItem
|
||||
icon={<DirectInbox variant={isActive(Paths.received) ? 'Bold' : 'Outline'} color={isActive(Paths.received) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.received')}
|
||||
isActive={isActive(Paths.received)}
|
||||
link={Paths.received}
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<DirectSend variant={isActive(Paths.sent) ? 'Bold' : 'Outline'} color={isActive(Paths.sent) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.sent')}
|
||||
isActive={isActive(Paths.sent)}
|
||||
link={Paths.sent}
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<Edit variant={isActive(Paths.draft) ? 'Bold' : 'Outline'} color={isActive(Paths.draft) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.draft')}
|
||||
isActive={isActive(Paths.draft)}
|
||||
link={Paths.draft}
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<ArchiveTick variant={isActive(Paths.archive) ? 'Bold' : 'Outline'} color={isActive(Paths.archive) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.archive')}
|
||||
isActive={isActive(Paths.archive)}
|
||||
link={Paths.archive}
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<Trash variant={isActive(Paths.trash) ? 'Bold' : 'Outline'} color={isActive(Paths.trash) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.trash')}
|
||||
isActive={isActive(Paths.trash)}
|
||||
link={Paths.trash}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-10 px-12 text-[#C3C7DD] text-sm font-bold'>
|
||||
{t('sidebar.other')}
|
||||
</div>
|
||||
|
||||
<div className='text-xs text-[#8C90A3]'>
|
||||
<SideBarItem
|
||||
icon={<Star variant={isActive(Paths.favorite) ? 'Bold' : 'Outline'} color={isActive(Paths.favorite) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.favorite')}
|
||||
isActive={isActive(Paths.favorite)}
|
||||
link={Paths.favorite}
|
||||
/>
|
||||
|
||||
<SideBarItem
|
||||
icon={<InfoCircle variant={isActive(Paths.spam) ? 'Bold' : 'Outline'} color={isActive(Paths.spam) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.spam')}
|
||||
isActive={isActive(Paths.spam)}
|
||||
link={Paths.spam}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex-1 flex flex-col justify-end mt-14 pb-8'>
|
||||
<div className='text-xs text-[#8C90A3]'>
|
||||
<SideBarItem
|
||||
icon={<Setting2 variant={isActive(Paths.setting) ? 'Bold' : 'Outline'} color={isActive(Paths.setting) ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.setting')}
|
||||
isActive={isActive(Paths.setting)}
|
||||
link={Paths.setting}
|
||||
/>
|
||||
</div>
|
||||
<div className='text-xs text-[#8C90A3]'>
|
||||
<SideBarItem
|
||||
icon={<Logout variant={isActive('logout') ? 'Bold' : 'Outline'} color={isActive('logout') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.logout')}
|
||||
isActive={isActive('logout')}
|
||||
link={`#`}
|
||||
isLogout
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideBar
|
||||
@@ -0,0 +1,43 @@
|
||||
import { FC, ReactNode } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { clx } from '../helpers/utils'
|
||||
|
||||
type Props = {
|
||||
icon: ReactNode,
|
||||
title: string,
|
||||
isActive: boolean,
|
||||
link: string,
|
||||
isLogout?: boolean,
|
||||
isWithoutLine?: boolean
|
||||
}
|
||||
|
||||
const SideBarItem: FC<Props> = (props: Props) => {
|
||||
|
||||
const handleLogout = async () => {
|
||||
// await logout.mutateAsync()
|
||||
// removeToken()
|
||||
// removeRefreshToken()
|
||||
// window.location.href = Pages.auth.login
|
||||
}
|
||||
|
||||
return (
|
||||
<Link onClick={props.isLogout ? handleLogout : undefined} to={props.link} className='flex text-xs gap-9 mt-4'>
|
||||
{
|
||||
!props.isWithoutLine &&
|
||||
<div className={clx(
|
||||
'w-1 bg-black h-6',
|
||||
!props.isActive && 'invisible'
|
||||
)}></div>
|
||||
}
|
||||
<div className='flex gap-2.5 items-center'>
|
||||
{props.icon}
|
||||
<div className={props.isActive ? 'text-black' : ''}>
|
||||
{props.title}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideBarItem
|
||||
@@ -0,0 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { SharedStoreType } from "../types/SharedTypes";
|
||||
|
||||
export const useSharedStore = create<SharedStoreType>((set) => ({
|
||||
openSidebar: false,
|
||||
setOpenSidebar: (value) => set({ openSidebar: value }),
|
||||
}));
|
||||
@@ -0,0 +1,4 @@
|
||||
export type SharedStoreType = {
|
||||
openSidebar: boolean;
|
||||
setOpenSidebar: (value: boolean) => void;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export const Paths = {
|
||||
home: "/",
|
||||
received: "/received",
|
||||
sent: "/sent",
|
||||
draft: "/draft",
|
||||
archive: "/archive",
|
||||
trash: "/trash",
|
||||
favorite: "/favorite",
|
||||
spam: "/spam",
|
||||
setting: "/setting",
|
||||
};
|
||||
+16
-6
@@ -3,10 +3,13 @@
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
@@ -14,13 +17,20 @@
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
+16
-4
@@ -1,7 +1,19 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -2,23 +2,31 @@
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"lib": [
|
||||
"ES2023"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
plugins: [react(), tailwindcss(), tsconfigPaths()],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user