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

View File

@ -32,6 +32,9 @@ dependencies:
lucide-svelte: lucide-svelte:
specifier: ^0.292.0 specifier: ^0.292.0
version: 0.292.0(svelte@4.2.2) version: 0.292.0(svelte@4.2.2)
qrcode:
specifier: ^1.5.3
version: 1.5.3
tailwind-merge: tailwind-merge:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
@ -55,6 +58,9 @@ devDependencies:
'@types/node': '@types/node':
specifier: ^20.8.10 specifier: ^20.8.10
version: 20.8.10 version: 20.8.10
'@types/qrcode':
specifier: ^1.5.5
version: 1.5.5
autoprefixer: autoprefixer:
specifier: ^10.4.16 specifier: ^10.4.16
version: 10.4.16(postcss@8.4.31) version: 10.4.16(postcss@8.4.31)
@ -561,6 +567,12 @@ packages:
resolution: {integrity: sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==} resolution: {integrity: sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==}
dev: true 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: /@types/resolve@1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true dev: true
@ -613,6 +625,18 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true 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: /ansi-styles@5.2.0:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -734,6 +758,11 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
/camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
dev: false
/caniuse-lite@1.0.30001561: /caniuse-lite@1.0.30001561:
resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==} resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==}
dev: true dev: true
@ -771,6 +800,14 @@ packages:
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 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: /clsx@2.0.0:
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -790,6 +827,17 @@ packages:
estree-walker: 3.0.3 estree-walker: 3.0.3
periscopic: 3.1.0 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: /commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -832,6 +880,11 @@ packages:
dependencies: dependencies:
ms: 2.1.2 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: /deep-eql@4.1.3:
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -868,6 +921,10 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: true dev: true
/dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
dev: false
/dlv@1.1.3: /dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@ -886,6 +943,14 @@ packages:
resolution: {integrity: sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==} resolution: {integrity: sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==}
dev: true 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: /es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
dev: true dev: true
@ -957,6 +1022,14 @@ packages:
dependencies: dependencies:
to-regex-range: 5.0.1 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: /focus-trap@7.5.4:
resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
dependencies: dependencies:
@ -992,6 +1065,11 @@ packages:
/function-bind@1.1.2: /function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 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: /get-func-name@2.0.2:
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
dev: true dev: true
@ -1112,6 +1190,11 @@ packages:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'} 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: /is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -1195,6 +1278,13 @@ packages:
/locate-character@3.0.0: /locate-character@3.0.0:
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 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: /lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
dev: false dev: false
@ -1381,6 +1471,13 @@ packages:
dependencies: dependencies:
wrappy: 1.0.2 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: /p-limit@4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -1388,6 +1485,18 @@ packages:
yocto-queue: 1.0.0 yocto-queue: 1.0.0
dev: true 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: /parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1395,6 +1504,11 @@ packages:
callsites: 3.1.0 callsites: 3.1.0
dev: true 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: /path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -1440,6 +1554,11 @@ packages:
pathe: 1.1.1 pathe: 1.1.1
dev: true 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): /postcss-import@15.1.0(postcss@8.4.31):
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -1528,6 +1647,17 @@ packages:
react-is: 18.2.0 react-is: 18.2.0
dev: true 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: /queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -1562,6 +1692,15 @@ packages:
resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
dev: false 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: /resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -1625,6 +1764,10 @@ packages:
lru-cache: 6.0.0 lru-cache: 6.0.0
dev: false dev: false
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
dev: false
/set-cookie-parser@2.6.0: /set-cookie-parser@2.6.0:
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
@ -1666,6 +1809,22 @@ packages:
resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==} resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==}
dev: true 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: /strip-indent@3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2081,6 +2240,10 @@ packages:
- terser - terser
dev: true dev: true
/which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
dev: false
/why-is-node-running@2.2.2: /why-is-node-running@2.2.2:
resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2090,9 +2253,22 @@ packages:
stackback: 0.0.2 stackback: 0.0.2
dev: true 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: /wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 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: /yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: false dev: false
@ -2101,6 +2277,31 @@ packages:
resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
engines: {node: '>= 14'} 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: /yocto-queue@1.0.0:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'} 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 Root = DialogPrimitive.Root;
const Trigger = DialogPrimitive.Trigger; const Trigger = DialogPrimitive.Trigger;
const Close = DialogPrimitive.Close;
import Title from './dialog-title.svelte'; import Title from './dialog-title.svelte';
import Portal from './dialog-portal.svelte'; import Portal from './dialog-portal.svelte';
@ -18,6 +19,7 @@ export {
Footer, Footer,
Header, Header,
Trigger, Trigger,
Close,
Overlay, Overlay,
Content, Content,
Description, Description,
@ -28,6 +30,7 @@ export {
Footer as DialogFooter, Footer as DialogFooter,
Header as DialogHeader, Header as DialogHeader,
Trigger as DialogTrigger, Trigger as DialogTrigger,
Close as DialogClose,
Overlay as DialogOverlay, Overlay as DialogOverlay,
Content as DialogContent, Content as DialogContent,
Description as DialogDescription, 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; 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]; 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> { export async function getNextFreeConfId(): Promise<number> {
let id = maxConfId(); let id = maxConfId() + 1;
for (let i = 0; i < 1_000; i++) { for (let i = id; i < 1_000; i++) {
if (!(await isConfigIdReserved(id))) { if (!(await isConfigIdReserved(i))) {
return id; 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 { export function getConfigHash(confId: number): string | undefined {

View File

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

View File

@ -1,7 +1,14 @@
<script lang="ts"> <script lang="ts">
import { CreateServerSchema, type CreateServerSchemaType } from './schema'; import { CreateServerSchema, type CreateServerSchemaType } from './schema';
import type { SuperValidated } from 'sveltekit-superforms'; 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 { import {
Form, Form,
FormButton, FormButton,
@ -18,13 +25,15 @@
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '$lib/components/ui/collapsible'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '$lib/components/ui/collapsible';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
export let isOpen = false;
let loading: boolean = false; let loading: boolean = false;
let form: SuperValidated<CreateServerSchemaType>; let form: SuperValidated<CreateServerSchemaType>;
</script> </script>
<Dialog open={isOpen}> <Dialog>
<DialogTrigger asChild let:builder>
<slot {builder} />
</DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Create Server</DialogTitle> <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="w-full md:w-2/3 flex items-center gap-x-2">
<div class="flex grow"> <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'}> <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>
<div class="h-full flex flex-col justify-between col-span-4 gap-y-1.5"> <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'; import { goto, invalidateAll } from '$app/navigation';
export let data: PageData; export let data: PageData;
export let dialogOpen: boolean = false;
const handleRename = async (peerId: string, name: string) => { const handleRename = async (peerId: string, name: string) => {
const resp = await fetchAction({ const resp = await fetchAction({
@ -76,8 +75,6 @@
}; };
</script> </script>
<CreatePeerDialog open={dialogOpen} on:close={() => (dialogOpen = false)} />
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Server</CardTitle> <CardTitle>Server</CardTitle>
@ -166,12 +163,16 @@
{/each} {/each}
</CardContent> </CardContent>
<CardFooter> <CardFooter>
<Button on:click={() => (dialogOpen = true)}>Add Client</Button> <CreatePeerDialog let:builder>
<Button size="sm" builders={[builder]}>Add Client</Button>
</CreatePeerDialog>
</CardFooter> </CardFooter>
{:else} {:else}
<CardContent> <CardContent>
<div>No Clients!</div> <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> </CardContent>
{/if} {/if}
</Card> </Card>

View File

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

View File

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

View File

@ -1,9 +1,16 @@
<script lang="ts"> <script lang="ts">
import { cn } from '$lib/utils'; import { cn } from '$lib/utils';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { Button } from 'bits-ui';
type $$Props = Button.Props & {
disabled?: boolean;
loading?: boolean;
};
export let disabled: boolean = false; export let disabled: boolean = false;
export let loading: boolean = false; export let loading: boolean = false;
export let builders: $$Props['builders'] = [];
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -13,10 +20,9 @@
} }
</script> </script>
<div <Button.Root
aria-roledescription="Action" {builders}
role="button" {...$$restProps}
tabindex="0"
class={cn( class={cn(
'group flex items-center justify-center w-10 aspect-square rounded-md', 'group flex items-center justify-center w-10 aspect-square rounded-md',
'bg-gray-200/80 hover:bg-gray-100/50', 'bg-gray-200/80 hover:bg-gray-100/50',
@ -31,5 +37,9 @@
if (e.key === 'Enter') handleClick(); if (e.key === 'Enter') handleClick();
}} }}
> >
<slot /> {#if loading}
</div> <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(); const receivedHashed = Buffer.from(password.toString()).toString('hex').toLowerCase();
if (hashed !== receivedHashed) { if (hashed !== receivedHashed) {
console.log('[+] TEST ONLY', password, hashed, receivedHashed);
return setError(form, 'password', 'Incorrect password.'); return setError(form, 'password', 'Incorrect password.');
} }
} }
@ -41,20 +40,16 @@ export const actions: Actions = {
const { ORIGIN } = process.env; const { ORIGIN } = process.env;
if (ORIGIN) { if (ORIGIN) {
console.log('[+] TEST ONLY', 'ORIGIN', ORIGIN);
const secure = ORIGIN.startsWith('https://'); const secure = ORIGIN.startsWith('https://');
event.cookies.set('authorization', token, { event.cookies.set('authorization', token, {
secure, secure,
httpOnly: true, httpOnly: true,
path: '/' path: '/',
}); });
} else { } else {
event.cookies.set('authorization', token); event.cookies.set('authorization', token);
} }
return { ok: true }; return { ok: true };
}, },
}; };