This commit is contained in:
Shahrad Elahi 2023-11-08 04:00:10 +03:30
parent 771a0f301c
commit f649ce4294
22 changed files with 402 additions and 63 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 183 KiB

View File

@ -19,6 +19,7 @@
"@types/crypto-js": "^4.1.3",
"@types/jsonwebtoken": "^9.0.4",
"@types/node": "^20.8.10",
"@types/qrcode": "^1.5.5",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.31",
"postcss-load-config": "^4.0.1",
@ -45,6 +46,7 @@
"ioredis": "^5.3.2",
"jsonwebtoken": "^9.0.2",
"lucide-svelte": "^0.292.0",
"qrcode": "^1.5.3",
"tailwind-merge": "^2.0.0",
"tailwind-variants": "^0.1.18"
}

View File

@ -32,6 +32,9 @@ dependencies:
lucide-svelte:
specifier: ^0.292.0
version: 0.292.0(svelte@4.2.2)
qrcode:
specifier: ^1.5.3
version: 1.5.3
tailwind-merge:
specifier: ^2.0.0
version: 2.0.0
@ -55,6 +58,9 @@ devDependencies:
'@types/node':
specifier: ^20.8.10
version: 20.8.10
'@types/qrcode':
specifier: ^1.5.5
version: 1.5.5
autoprefixer:
specifier: ^10.4.16
version: 10.4.16(postcss@8.4.31)
@ -561,6 +567,12 @@ packages:
resolution: {integrity: sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==}
dev: true
/@types/qrcode@1.5.5:
resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
dependencies:
'@types/node': 20.8.10
dev: true
/@types/resolve@1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true
@ -613,6 +625,18 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: false
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/ansi-styles@5.2.0:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'}
@ -734,6 +758,11 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
/camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
dev: false
/caniuse-lite@1.0.30001561:
resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==}
dev: true
@ -771,6 +800,14 @@ packages:
optionalDependencies:
fsevents: 2.3.3
/cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
dev: false
/clsx@2.0.0:
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
engines: {node: '>=6'}
@ -790,6 +827,17 @@ packages:
estree-walker: 3.0.3
periscopic: 3.1.0
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
@ -832,6 +880,11 @@ packages:
dependencies:
ms: 2.1.2
/decamelize@1.2.0:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
dev: false
/deep-eql@4.1.3:
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
engines: {node: '>=6'}
@ -868,6 +921,10 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: true
/dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
dev: false
/dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@ -886,6 +943,14 @@ packages:
resolution: {integrity: sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==}
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: false
/encode-utf8@1.0.3:
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
dev: false
/es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
dev: true
@ -957,6 +1022,14 @@ packages:
dependencies:
to-regex-range: 5.0.1
/find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
dependencies:
locate-path: 5.0.0
path-exists: 4.0.0
dev: false
/focus-trap@7.5.4:
resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
dependencies:
@ -992,6 +1065,11 @@ packages:
/function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
dev: false
/get-func-name@2.0.2:
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
dev: true
@ -1112,6 +1190,11 @@ packages:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: false
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
@ -1195,6 +1278,13 @@ packages:
/locate-character@3.0.0:
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
/locate-path@5.0.0:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'}
dependencies:
p-locate: 4.1.0
dev: false
/lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
dev: false
@ -1381,6 +1471,13 @@ packages:
dependencies:
wrappy: 1.0.2
/p-limit@2.3.0:
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
engines: {node: '>=6'}
dependencies:
p-try: 2.2.0
dev: false
/p-limit@4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -1388,6 +1485,18 @@ packages:
yocto-queue: 1.0.0
dev: true
/p-locate@4.1.0:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
engines: {node: '>=8'}
dependencies:
p-limit: 2.3.0
dev: false
/p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
dev: false
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -1395,6 +1504,11 @@ packages:
callsites: 3.1.0
dev: true
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: false
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
@ -1440,6 +1554,11 @@ packages:
pathe: 1.1.1
dev: true
/pngjs@5.0.0:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
dev: false
/postcss-import@15.1.0(postcss@8.4.31):
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
@ -1528,6 +1647,17 @@ packages:
react-is: 18.2.0
dev: true
/qrcode@1.5.3:
resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
engines: {node: '>=10.13.0'}
hasBin: true
dependencies:
dijkstrajs: 1.0.3
encode-utf8: 1.0.3
pngjs: 5.0.0
yargs: 15.4.1
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -1562,6 +1692,15 @@ packages:
resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
dev: false
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
dev: false
/require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@ -1625,6 +1764,10 @@ packages:
lru-cache: 6.0.0
dev: false
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
dev: false
/set-cookie-parser@2.6.0:
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
@ -1666,6 +1809,22 @@ packages:
resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==}
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: false
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: false
/strip-indent@3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
@ -2081,6 +2240,10 @@ packages:
- terser
dev: true
/which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
dev: false
/why-is-node-running@2.2.2:
resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
engines: {node: '>=8'}
@ -2090,9 +2253,22 @@ packages:
stackback: 0.0.2
dev: true
/wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: false
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
dev: false
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: false
@ -2101,6 +2277,31 @@ packages:
resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
engines: {node: '>= 14'}
/yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}
dependencies:
camelcase: 5.3.1
decamelize: 1.2.0
dev: false
/yargs@15.4.1:
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
engines: {node: '>=8'}
dependencies:
cliui: 6.0.0
decamelize: 1.2.0
find-up: 4.1.0
get-caller-file: 2.0.5
require-directory: 2.1.1
require-main-filename: 2.0.0
set-blocking: 2.0.0
string-width: 4.2.3
which-module: 2.0.1
y18n: 4.0.3
yargs-parser: 18.1.3
dev: false
/yocto-queue@1.0.0:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'}

View File

@ -1,18 +0,0 @@
<svg width="32" height="32" version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="50%" y1="100%" x2="50%" y2="0%" id="linearGradient-1">
<stop stop-color="#420C5D" offset="0%"></stop>
<stop stop-color="#951AD1" offset="100%"></stop>
</linearGradient>
</defs>
<g transform="translate(-58.12 -303.3)" fill="url(#linearGradient-1)" fill-rule="evenodd">
<path d="m77.15 303.3c-1.608 1.868-0.09027 2.972-0.9891 4.84 1.514-2.129 5.034-2.862 7.328-3.643-3.051 2.72-5.457 6.326-8.489 9.009l-1.975-0.8374c-0.4647-4.514-1.736-4.705 4.125-9.369z"
fill-rule="evenodd"/>
<path d="m74.04 313.1 2.932 0.9454c-0.615 2.034 0.3559 2.791 0.9472 3.123 1.324 0.7332 2.602 1.49 3.619 2.412 1.916 1.75 3.004 4.21 3.004 6.812 0 2.578-1.183 5.061-3.169 6.717-1.868 1.561-4.446 2.223-6.953 2.223-1.561 0-2.956-0.0708-4.47-0.5677-3.453-1.159-6.031-4.115-6.244-7.663-0.1893-2.767 0.4257-4.872 2.578-7.072 1.111-1.159 2.563-2.749 4.1-3.813 0.757-0.5204 1.119-1.191-0.4183-3.958l1.28-1.076 2.795 1.918-2.352-0.3007c0.1656 0.2366 1.189 0.7706 1.284 1.078 0.2128 0.8751-0.1911 1.771-0.3804 2.149-0.9696 1.75-1.86 2.275-3.066 3.268-2.129 1.75-4.27 2.836-4.01 7.637 0.1183 2.365 1.433 5.295 4.2 6.643 1.561 0.757 2.859 1.189 4.68 1.284 1.632 0.071 4.754-0.8988 6.457-2.318 1.821-1.514 2.838-3.808 2.838-6.149 0-2.365-0.9461-4.612-2.72-6.197-1.017-0.9223-2.696-2.034-3.737-2.625-1.041-0.5912-2.782-2.06-2.356-3.645z"/>
<path d="m73.41 316.6c-0.186 1.088-0.4177 3.117-0.8909 3.917-0.3293 0.5488-0.4126 0.8101-0.7846 1.094-1.09 1.535-1.45 1.761-2.132 4.552-0.1447 0.5914-0.3832 1.516-0.2591 2.107 0.372 1.703 0.6612 2.874 1.316 4.103 0 0 0.1271 0.1217 0.1271 0.169 0.6821 0.9225 0.6264 1.05 2.665 2.246l-0.06204 0.3313c-1.55-0.4729-2.604-0.9591-3.41-2.024 0-0.0236-0.1513-0.1558-0.1513-0.1558-0.868-1.135-1.753-2.788-2.021-4.546-0.1447-0.7097-0.0769-1.341 0.08833-2.075 0.7026-2.885 1.415-4.093 2.744-5.543 0.3514-0.2601 0.6704-0.6741 1.001-1.092 0.4859-0.6764 1.462-2.841 1.814-4.189z"/>
<path d="m74.09 318.6c0.0237 1.04 0.0078 3.036 0.3389 3.796 0.0945 0.2599 0.3274 1.414 0.9422 2.794 0.4258 0.96 0.5418 1.933 0.6128 2.193 0.2838 1.14-0.4002 3.086-0.8734 4.906-0.2364 0.98-0.6051 1.773-1.371 2.412l0.2796 0.3593c0.5204-0.02 1.954-1.096 2.403-2.416 0.757-2.24 1.328-3.317 0.9729-5.797-0.0473-0.2402-0.2094-1.134-0.6588-2.014-0.6622-1.34-1.474-2.614-1.592-2.874-0.213-0.4198-1.007-2.119-1.054-3.359z"/>
<path d="m74.88 313.9 0.9727 0.4962c-0.09145 0.6403 0.04572 2.059 0.686 2.424 2.836 1.761 5.512 3.683 6.565 5.604 3.751 6.771-2.63 13.04-8.143 12.44 2.996-2.219 4.428-6.583 3.307-11.55-0.4574-1.944-1.729-3.893-2.987-5.883-0.545-0.9768-0.3547-2.188-0.4006-3.538z"
fill-rule="evenodd"/>
<rect x="73.07" y="312.8" width="1" height="22"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,74 @@
<script lang="ts">
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '$lib/components/ui/dialog';
import { Skeleton } from '$lib/components/ui/skeleton';
import { Dialog as DialogPrimitive } from 'bits-ui';
import { Button } from '$lib/components/ui/button';
import type { SafeReturn } from '$lib/typings';
const DialogClose = DialogPrimitive.Close;
let loading: boolean = true;
let error: boolean = false;
let imageData: string | undefined = undefined;
export let content: string | undefined;
const getImageData = async (content: string): Promise<SafeReturn<string>> => {
const resp = await fetch('/api/qrcode', {
method: 'POST',
body: content,
headers: {
'Content-Type': 'text/plain',
},
});
if (resp.statusText !== 'OK') {
return { error: new Error('request failed') };
}
const data = await resp.text();
return { data };
};
$: if (typeof content === 'string') {
(async () => {
const { data, error: e } = await getImageData(content);
loading = false;
if (!data || e) {
error = true;
return;
}
imageData = data;
})();
}
</script>
<Dialog>
<DialogTrigger asChild let:builder>
<slot {builder} />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>QRCode</DialogTitle>
</DialogHeader>
<div class="flex items-center justify-center">
{#if loading}
<Skeleton class="w-[280px] h-[280px] rounded-lg" />
{:else if error || !imageData}
<div>!!ERROR!!</div>
{:else}
<img src={imageData} alt="QRCode" width="300" height="300" />
{/if}
</div>
<DialogFooter>
<DialogClose>
<Button size="sm">Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>

View File

@ -0,0 +1,7 @@
import Root from './QRCodeDialog.svelte';
export {
Root,
//
Root as QRCodeDialog,
};

View File

@ -2,6 +2,7 @@ import { Dialog as DialogPrimitive } from 'bits-ui';
const Root = DialogPrimitive.Root;
const Trigger = DialogPrimitive.Trigger;
const Close = DialogPrimitive.Close;
import Title from './dialog-title.svelte';
import Portal from './dialog-portal.svelte';
@ -18,6 +19,7 @@ export {
Footer,
Header,
Trigger,
Close,
Overlay,
Content,
Description,
@ -28,6 +30,7 @@ export {
Footer as DialogFooter,
Header as DialogHeader,
Trigger as DialogTrigger,
Close as DialogClose,
Overlay as DialogOverlay,
Content as DialogContent,
Description as DialogDescription,

View File

@ -0,0 +1,7 @@
import Root from "./skeleton.svelte";
export {
Root,
//
Root as Skeleton
};

View File

@ -0,0 +1,14 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div
class={cn("animate-pulse rounded-md bg-muted", className)}
{...$$restProps}
/>

View File

@ -76,4 +76,10 @@ export type APISuccessResponse<D> = {
result: D;
};
export type SafeReturn<T, K = any> = LeastOne<{
data: T,
error: K
}>
export type LeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];

View File

@ -525,13 +525,13 @@ export async function isConfigIdReserved(id: number): Promise<boolean> {
}
export async function getNextFreeConfId(): Promise<number> {
let id = maxConfId();
for (let i = 0; i < 1_000; i++) {
if (!(await isConfigIdReserved(id))) {
return id;
let id = maxConfId() + 1;
for (let i = id; i < 1_000; i++) {
if (!(await isConfigIdReserved(i))) {
return i;
}
}
throw new Error('Could not find a free config id');
throw new Error('WireGuard: Error: Could not find a free config id');
}
export function getConfigHash(confId: number): string | undefined {

View File

@ -8,7 +8,6 @@
import fetchAction from '$lib/fetch-action';
export let data: PageData;
export let isOpen = false;
const handleRename = async (id: string, name: string) => {
const resp = await fetchAction({
@ -32,10 +31,13 @@
<BasePage showLogout={true}>
<div class={'flex items-center justify-between py-3 px-2'}>
<h2 class={'font-bold text-xl'}>Hello there 👋</h2>
<Button on:click={() => (isOpen = true)}>
<i class="fas fa-plus mr-2"></i>
Create Server
</Button>
<CreateServerDialog let:builder>
<Button builders={[builder]}>
<i class="fas fa-plus mr-2"></i>
Create Server
</Button>
</CreateServerDialog>
</div>
<div class="space-y-3.5">
@ -58,5 +60,3 @@
{/if}
</div>
</BasePage>
<CreateServerDialog {isOpen} />

View File

@ -1,7 +1,14 @@
<script lang="ts">
import { CreateServerSchema, type CreateServerSchemaType } from './schema';
import type { SuperValidated } from 'sveltekit-superforms';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '$lib/components/ui/dialog';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '$lib/components/ui/dialog';
import {
Form,
FormButton,
@ -18,13 +25,15 @@
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '$lib/components/ui/collapsible';
import { Button } from '$lib/components/ui/button';
export let isOpen = false;
let loading: boolean = false;
let form: SuperValidated<CreateServerSchemaType>;
</script>
<Dialog open={isOpen}>
<Dialog>
<DialogTrigger asChild let:builder>
<slot {builder} />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create Server</DialogTitle>

View File

@ -18,7 +18,9 @@
<div class="w-full md:w-2/3 flex items-center gap-x-2">
<div class="flex grow">
<div class={'w-12 aspect-square flex items-center justify-center mr-4 rounded-full bg-gray-200 max-md:hidden'}>
<i class={'fa-solid fa-server text-gray-400 text-xl'} />
<i
class={cn(server.tor ? 'fa-solid fa-onion text-purple-700' : 'fa-solid fa-server text-gray-400', 'text-xl')}
/>
</div>
<div class="h-full flex flex-col justify-between col-span-4 gap-y-1.5">

View File

@ -13,7 +13,6 @@
import { goto, invalidateAll } from '$app/navigation';
export let data: PageData;
export let dialogOpen: boolean = false;
const handleRename = async (peerId: string, name: string) => {
const resp = await fetchAction({
@ -76,8 +75,6 @@
};
</script>
<CreatePeerDialog open={dialogOpen} on:close={() => (dialogOpen = false)} />
<Card>
<CardHeader>
<CardTitle>Server</CardTitle>
@ -166,12 +163,16 @@
{/each}
</CardContent>
<CardFooter>
<Button on:click={() => (dialogOpen = true)}>Add Client</Button>
<CreatePeerDialog let:builder>
<Button size="sm" builders={[builder]}>Add Client</Button>
</CreatePeerDialog>
</CardFooter>
{:else}
<CardContent>
<div>No Clients!</div>
<Button on:click={() => (dialogOpen = true)}>Add Client</Button>
<CreatePeerDialog let:builder>
<Button size="sm" builders={[builder]}>Add Client</Button>
</CreatePeerDialog>
</CardContent>
{/if}
</Card>

View File

@ -1,7 +1,14 @@
<script lang="ts">
import { CreatePeerSchema, type CreatePeerSchemaType } from './schema';
import type { SuperValidated } from 'sveltekit-superforms';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '$lib/components/ui/dialog';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '$lib/components/ui/dialog';
import { Form, FormButton, FormField, FormInput, FormLabel, FormValidation } from '$lib/components/ui/form';
import { FormItem } from '$lib/components/ui/form/index.js';
import { cn } from '$lib/utils';
@ -10,7 +17,6 @@
const dispatch = createEventDispatcher();
export let open = false;
let loading: boolean = false;
let form: SuperValidated<CreatePeerSchemaType>;
@ -21,7 +27,10 @@
};
</script>
<Dialog {open}>
<Dialog>
<DialogTrigger asChild let:builder>
<slot {builder} />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create Peer</DialogTitle>

View File

@ -6,6 +6,7 @@
import PeerActionButton from './PeerActionButton.svelte';
import { createEventDispatcher, onMount } from 'svelte';
import { getPeerConf } from '$lib/wireguard/utils';
import { QRCodeDialog } from '$lib/components/qrcode-dialog';
export let peer: Peer;
@ -15,7 +16,7 @@
export let conf: string | undefined = undefined;
export let isLoading: boolean = false;
let isLoading: boolean = false;
onMount(async () => {
conf = await getPeerConf({
@ -35,7 +36,7 @@
}
console.log('conf', conf);
// create a blob
const blob = new Blob([conf], { type: 'text/plain' });
const blob = new Blob([ conf ], { type: 'text/plain' });
// create a link
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
@ -46,8 +47,6 @@
link.remove();
};
const handleQRCode = async () => {};
const handleRename = (value: string) => {
dispatch('rename', value);
};
@ -58,7 +57,7 @@
</script>
<div class="flex items-center justify-between p-4 border border-neutral-200/60 rounded-md hover:border-neutral-200">
<div class="flex items-center gap-2.5">
<div class="flex items-center gap-x-2">
<div class={'w-12 aspect-square flex items-center justify-center mr-4 rounded-full bg-gray-200 max-md:hidden'}>
<i class={'fas fa-user text-gray-400 text-lg'} />
</div>
@ -80,16 +79,18 @@
</div>
<div class="flex items-center justify-center gap-x-3">
<!-- QRCode -->
<PeerActionButton disabled={isLoading} on:click={handleQRCode}>
<i class={'fal text-neutral-700 group-hover:text-primary fa-qrcode'} />
</PeerActionButton>
<QRCodeDialog let:builder content={conf}>
<PeerActionButton builders={[builder]} disabled={isLoading}>
<i class={'fal text-neutral-700 group-hover:text-primary fa-qrcode'} />
</PeerActionButton>
</QRCodeDialog>
<!-- Download -->
<PeerActionButton disabled={isLoading} on:click={handleDownload}>
<i class={'fal text-neutral-700 group-hover:text-primary fa-download'} />
</PeerActionButton>
<!-- Download -->
<!-- Remove -->
<PeerActionButton loading={isLoading} on:click={handleRemove}>
<i class={'fal text-neutral-700 group-hover:text-primary text-lg fa-trash-can'} />
</PeerActionButton>

View File

@ -1,9 +1,16 @@
<script lang="ts">
import { cn } from '$lib/utils';
import { createEventDispatcher } from 'svelte';
import { Button } from 'bits-ui';
type $$Props = Button.Props & {
disabled?: boolean;
loading?: boolean;
};
export let disabled: boolean = false;
export let loading: boolean = false;
export let builders: $$Props['builders'] = [];
const dispatch = createEventDispatcher();
@ -13,10 +20,9 @@
}
</script>
<div
aria-roledescription="Action"
role="button"
tabindex="0"
<Button.Root
{builders}
{...$$restProps}
class={cn(
'group flex items-center justify-center w-10 aspect-square rounded-md',
'bg-gray-200/80 hover:bg-gray-100/50',
@ -31,5 +37,9 @@
if (e.key === 'Enter') handleClick();
}}
>
<slot />
</div>
{#if loading}
<i class="far fa-spinner-third fa-spin" />
{:else}
<slot />
{/if}
</Button.Root>

View File

@ -0,0 +1,16 @@
import type { RequestHandler } from '@sveltejs/kit';
import QRCode from 'qrcode';
export const POST: RequestHandler = async ({ request }) => {
if (!request.headers.has('Content-Type') || request.headers.get('Content-Type') !== 'text/plain') {
return new Response(null, { status: 400, headers: { 'Content-Type': 'text/plain' } });
}
const body = await request.text();
const data = await QRCode.toDataURL(body, {
errorCorrectionLevel: 'H',
width: 500,
});
return new Response(data, { status: 200, headers: { 'Content-Type': 'text/plain' } });
};

View File

@ -28,7 +28,6 @@ export const actions: Actions = {
const receivedHashed = Buffer.from(password.toString()).toString('hex').toLowerCase();
if (hashed !== receivedHashed) {
console.log('[+] TEST ONLY', password, hashed, receivedHashed);
return setError(form, 'password', 'Incorrect password.');
}
}
@ -41,20 +40,16 @@ export const actions: Actions = {
const { ORIGIN } = process.env;
if (ORIGIN) {
console.log('[+] TEST ONLY', 'ORIGIN', ORIGIN);
const secure = ORIGIN.startsWith('https://');
event.cookies.set('authorization', token, {
secure,
httpOnly: true,
path: '/'
path: '/',
});
} else {
event.cookies.set('authorization', token);
}
return { ok: true };
},
};