mirror of
https://github.com/BradNut/AdelieStack
synced 2025-09-08 17:40:20 +00:00
Adding auth page with layout, signup fixes, moving DTOs for reuse in front end and back end.
This commit is contained in:
parent
10a794766d
commit
a8abcbc540
38 changed files with 1467 additions and 195 deletions
|
|
@ -25,6 +25,7 @@ REDIS_URL=redis://localhost:6379
|
|||
|
||||
# Security - openssl rand -hex 32
|
||||
SIGNING_SECRET=
|
||||
SHOW_OAUTH_BUTTONS=false
|
||||
|
||||
# Storage
|
||||
PUBLIC_IMAGE_URI=http://localhost:9000/dev
|
||||
|
|
|
|||
879
src/lib/components/logo.svelte
Normal file
879
src/lib/components/logo.svelte
Normal file
|
|
@ -0,0 +1,879 @@
|
|||
<svg width="265" height="46" viewBox="0 0 265 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M68.3545 2.7142C65.7271 1.43779 62.777 0.721863 59.6597 0.721863C56.5424 0.721863 53.5923 1.43779 50.9649 2.7142H68.3545Z"
|
||||
fill="url(#paint0_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M48.8452 3.9096C49.0563 3.77286 49.2703 3.64 49.4869 3.51113H69.8325C70.9893 4.1994 72.0704 5.00149 73.0605 5.90194H46.2589C46.4074 5.76689 46.5579 5.63405 46.7105 5.50347H26.7871C26.8836 5.42083 26.981 5.33909 27.0791 5.25827H7.45459C7.79948 4.9812 8.15378 4.71537 8.51695 4.46134H28.1138C28.3784 4.27103 28.6478 4.08704 28.9218 3.9096H48.8452Z"
|
||||
fill="url(#paint1_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M75.8915 9.08968C75.2861 8.24083 74.6158 7.44148 73.8878 6.69887H45.4315C45.3031 6.82994 45.1764 6.96278 45.0515 7.09734H25.1281C24.9604 7.27816 24.7959 7.46211 24.6349 7.64908H4.95529C4.72692 7.90882 4.50522 8.17455 4.29043 8.44601H23.9833C23.9203 8.52725 23.8579 8.60898 23.7962 8.69121H43.7195C43.6207 8.82278 43.5235 8.95561 43.4279 9.08968H75.8915Z"
|
||||
fill="url(#paint2_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M42.6384 10.2851C42.7201 10.1512 42.8033 10.0184 42.888 9.88661H76.4314C76.9218 10.6495 77.3615 11.448 77.7459 12.2774H41.5735C41.6354 12.1438 41.6988 12.011 41.7635 11.8789H21.8402C21.8805 11.7969 21.9213 11.7152 21.9626 11.6337H2.22838C2.36814 11.3645 2.51387 11.0987 2.66539 10.8368H22.3906C22.4959 10.651 22.6041 10.4671 22.7151 10.2851H42.6384Z"
|
||||
fill="url(#paint3_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M78.903 15.4652C78.6831 14.6462 78.4123 13.848 78.0942 13.0744H41.2252C41.1709 13.2065 41.1179 13.3393 41.0664 13.4728H21.143C21.0725 13.6554 21.0046 13.8394 20.9394 14.0246H1.18116C1.08604 14.2877 0.996312 14.5534 0.912096 14.8215H20.6776C20.6527 14.903 20.6283 14.9847 20.6045 15.0667H40.5279C40.4894 15.1989 40.4522 15.3318 40.4164 15.4652H78.903Z"
|
||||
fill="url(#paint4_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M40.1349 16.6606C40.1619 16.5272 40.1903 16.3944 40.22 16.2621H79.0993C79.2746 17.0427 79.404 17.8406 79.4847 18.6529H39.8347C39.8479 18.5197 39.8624 18.3869 39.8783 18.2544H19.9549C19.9647 18.1725 19.975 18.0908 19.9858 18.0092H0.193705C0.231164 17.7418 0.273929 17.4762 0.321892 17.2123H20.1076C20.1397 17.0275 20.1743 16.8436 20.2115 16.6606H40.1349Z"
|
||||
fill="url(#paint5_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M79.583 20.6452C79.583 21.0466 79.5712 21.4452 79.5478 21.8406H39.7716C39.7637 21.7082 39.7572 21.5753 39.752 21.4422H19.8286C19.8254 21.3606 19.8227 21.2788 19.8204 21.197H0.00390527C0.00130579 21.0645 0 20.9316 0 20.7985C0 20.6654 0.00130579 20.5325 0.00390527 20.4H19.8144C19.8167 20.2155 19.8214 20.0316 19.8286 19.8483H39.752C39.7572 19.7151 39.7637 19.5823 39.7716 19.4498H79.5478C79.5712 19.8453 79.583 20.2439 79.583 20.6452Z"
|
||||
fill="url(#paint6_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M79.4847 22.6376C79.404 23.4498 79.2746 24.2478 79.0993 25.0284H40.22C40.1903 24.896 40.1619 24.7632 40.1349 24.6299H20.2115C20.1949 24.5483 20.1789 24.4666 20.1633 24.3847H0.321892C0.273929 24.1208 0.231164 23.8552 0.193705 23.5878H20.0287C20.0016 23.4047 19.977 23.2207 19.9549 23.036H39.8783C39.8624 22.9036 39.8479 22.7708 39.8347 22.6376H79.4847Z"
|
||||
fill="url(#paint7_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M41.0664 27.8176C41.1179 27.9512 41.1709 28.084 41.2252 28.2161H78.0942C78.4123 27.4424 78.6831 26.6443 78.903 25.8253H40.4164C40.4522 25.9587 40.4894 26.0915 40.5279 26.2238H20.6045C20.6584 26.4088 20.7148 26.5927 20.7739 26.7755H0.912096C0.996312 27.0436 1.08604 27.3093 1.18116 27.5724H21.0502C21.0806 27.6544 21.1116 27.7362 21.143 27.8176H41.0664Z"
|
||||
fill="url(#paint8_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M77.7459 29.013C77.3615 29.8425 76.9218 30.641 76.4314 31.4038H42.888C42.8033 31.2721 42.7201 31.1392 42.6384 31.0054H22.7151C22.6655 30.924 22.6164 30.8423 22.5679 30.7602H2.66539C2.51387 30.4982 2.36814 30.2325 2.22838 29.9632H22.1217C22.0251 29.781 21.9312 29.5971 21.8402 29.4115H41.7635C41.6988 29.2795 41.6354 29.1467 41.5735 29.013H77.7459Z"
|
||||
fill="url(#paint9_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M45.0515 34.1931C45.1764 34.3277 45.3031 34.4605 45.4315 34.5916H73.8878C74.6158 33.849 75.2861 33.0496 75.8915 32.2008H43.4279C43.5235 32.3348 43.6207 32.4677 43.7195 32.5992H23.7962C23.9362 32.7857 24.0795 32.9697 24.2259 33.151H4.29043C4.50522 33.4224 4.72692 33.6882 4.95529 33.9479H24.9044C24.9783 34.0303 25.0529 34.112 25.1281 34.1931H45.0515Z"
|
||||
fill="url(#paint10_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M73.0605 35.3885C72.0704 36.289 70.9893 37.0911 69.8325 37.7793H49.4869C49.2703 37.6505 49.0563 37.5176 48.8452 37.3809H28.9218C28.7976 37.3005 28.6744 37.2187 28.5522 37.1357H8.51695C8.15378 36.8816 7.79948 36.6158 7.45459 36.3387H27.4607C27.2321 36.1596 27.0075 35.9757 26.7871 35.787H46.7105C46.5579 35.6564 46.4074 35.5236 46.2589 35.3885H73.0605Z"
|
||||
fill="url(#paint11_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M50.9649 38.5763C53.5923 39.8527 56.5424 40.5686 59.6597 40.5686C62.777 40.5686 65.7271 39.8527 68.3545 38.5763H50.9649Z"
|
||||
fill="url(#paint12_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M26.7366 2.07053C24.6109 1.29704 22.3164 0.875131 19.9234 0.875131C17.5303 0.875131 15.2358 1.29704 13.1101 2.07053H26.7366Z"
|
||||
fill="url(#paint13_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M13.1101 39.5265C15.2358 40.3 17.5303 40.7219 19.9234 40.7219C22.3164 40.7219 24.6109 40.3 26.7366 39.5265H13.1101Z"
|
||||
fill="url(#paint14_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M39.7363 0.721863C42.5127 0.721863 45.1564 1.28976 47.5577 2.31573H31.9149C34.3162 1.28976 36.9599 0.721863 39.7363 0.721863Z"
|
||||
fill="url(#paint15_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M39.7363 40.5686C36.9599 40.5686 34.3162 40.0007 31.9149 38.9747H47.5577C45.1564 40.0007 42.5127 40.5686 39.7363 40.5686Z"
|
||||
fill="url(#paint16_linear_5015_976)"
|
||||
></path>
|
||||
<path
|
||||
d="M259.543 45.174V38.086H260.584V45.174H259.543ZM263.561 45.174L260.199 41.6977V41.5832L263.603 38.086H264.904L261.146 41.9475L261.25 41.3334L264.966 45.174H263.561Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M253.089 45.174V38.086H255.691C256.177 38.086 256.6 38.1901 256.961 38.3982C257.329 38.5995 257.613 38.8735 257.814 39.2205C258.016 39.5674 258.116 39.956 258.116 40.3862C258.116 40.8164 258.016 41.205 257.814 41.5519C257.613 41.8989 257.329 42.173 256.961 42.3742C256.6 42.5754 256.177 42.676 255.691 42.676H253.943V41.6977H255.514C255.972 41.6977 256.34 41.5832 256.618 41.3542C256.895 41.1183 257.034 40.7956 257.034 40.3862C257.034 39.9491 256.895 39.6195 256.618 39.3974C256.34 39.1754 255.972 39.0644 255.514 39.0644H253.932L254.13 38.825V45.174H253.089ZM257.044 45.174L255.389 42.2285H256.534L258.189 45.174H257.044Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M244.558 41.6352C244.558 41.1079 244.648 40.6221 244.829 40.1781C245.016 39.734 245.276 39.3489 245.609 39.0227C245.942 38.6966 246.331 38.4433 246.775 38.2629C247.226 38.0825 247.715 37.9923 248.242 37.9923C248.763 37.9923 249.245 38.0825 249.689 38.2629C250.133 38.4433 250.518 38.6966 250.845 39.0227C251.178 39.3489 251.434 39.734 251.615 40.1781C251.802 40.6221 251.896 41.1079 251.896 41.6352C251.896 42.1556 251.802 42.6379 251.615 43.082C251.434 43.5261 251.178 43.9146 250.845 44.2477C250.518 44.5738 250.133 44.8271 249.689 45.0075C249.245 45.1879 248.763 45.2781 248.242 45.2781C247.715 45.2781 247.226 45.1879 246.775 45.0075C246.331 44.8271 245.942 44.5738 245.609 44.2477C245.276 43.9146 245.016 43.5261 244.829 43.082C244.648 42.6379 244.558 42.1556 244.558 41.6352ZM245.62 41.6352C245.62 42.1418 245.734 42.5962 245.963 42.9987C246.192 43.3942 246.504 43.7065 246.9 43.9354C247.295 44.1644 247.743 44.2789 248.242 44.2789C248.742 44.2789 249.186 44.1644 249.575 43.9354C249.963 43.7065 250.269 43.3942 250.491 42.9987C250.72 42.5962 250.834 42.1418 250.834 41.6352C250.834 41.1217 250.72 40.6672 250.491 40.2717C250.269 39.8762 249.963 39.564 249.575 39.335C249.186 39.106 248.742 38.9915 248.242 38.9915C247.743 38.9915 247.295 39.106 246.9 39.335C246.504 39.564 246.192 39.8762 245.963 40.2717C245.734 40.6672 245.62 41.1217 245.62 41.6352Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M241.099 45.174L239.153 38.8562L238.914 38.086H239.934L241.922 44.6536L241.464 44.5495L243.191 38.086H244.243L242.317 45.174H241.099ZM236.53 45.174L234.605 38.086H235.656L237.384 44.5495L236.926 44.6536L238.914 38.086H239.934L239.694 38.8562L237.748 45.174H236.53Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M230.934 45.174V38.8666H231.975V45.174H230.934ZM228.717 39.0644V38.086H234.296V39.0644H228.717Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M224.567 42.1036V41.1252H227.429V42.1036H224.567ZM224.536 39.0644L224.775 38.7313V44.3518L224.484 44.1852H228.043V45.174H223.734V38.086H228.043V39.0644H224.536Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M221.078 45.174L216.498 39.2309L217.081 39.0644V45.174H216.04V38.086H216.925L221.348 43.821H220.922V38.086H221.962V45.174H221.078Z"
|
||||
fill="#7D919C"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #a0978b;"
|
||||
></path>
|
||||
<path
|
||||
d="M168.982 11.5674V30.7219H174.701V11.5674H168.982Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
d="M169.374 3.06732C168.773 3.69403 168.473 4.5166 168.473 5.53503C168.473 6.5274 168.773 7.33691 169.374 7.96362C170.001 8.56427 170.823 8.86456 171.842 8.86456C172.86 8.86456 173.67 8.56427 174.27 7.96362C174.897 7.33691 175.21 6.5274 175.21 5.53503C175.21 4.5166 174.897 3.69403 174.27 3.06732C173.67 2.44055 172.86 2.1272 171.842 2.1272C170.823 2.1272 170.001 2.44055 169.374 3.06732Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
d="M201.388 30.4085C202.746 31.0092 204.195 31.3094 205.736 31.3094C207.198 31.3094 208.504 31.0483 209.653 30.5261C210.802 30.0038 211.703 29.2726 212.356 28.3325C213.008 27.3663 213.335 26.2564 213.335 25.0029C213.335 23.3839 212.813 22.0912 211.768 21.1251C210.75 20.1588 209.052 19.3885 206.676 18.814C205.266 18.4745 204.326 18.1742 203.856 17.913C203.385 17.6519 203.15 17.3255 203.15 16.9338C203.15 16.5159 203.346 16.2026 203.738 15.9937C204.13 15.7847 204.6 15.6803 205.148 15.6803C206.167 15.6803 207.081 15.8631 207.89 16.2287C208.7 16.5943 209.392 17.0382 209.966 17.5605L213.492 14.5444C212.656 13.552 211.598 12.7164 210.319 12.0374C209.039 11.3323 207.485 10.9798 205.657 10.9798C204.117 10.9798 202.785 11.267 201.662 11.8416C200.539 12.4161 199.677 13.1864 199.077 14.1526C198.476 15.0927 198.176 16.1373 198.176 17.2863C198.176 18.8793 198.659 20.1588 199.625 21.1251C200.617 22.0651 202.119 22.7833 204.13 23.2794C205.227 23.5667 206.062 23.8148 206.637 24.0237C207.211 24.2326 207.603 24.4415 207.812 24.6504C208.021 24.8593 208.125 25.1205 208.125 25.4338C208.125 25.7994 207.942 26.1128 207.577 26.3739C207.237 26.6089 206.78 26.7264 206.206 26.7264C205.24 26.7264 204.352 26.5306 203.542 26.1389C202.733 25.7472 201.884 25.0944 200.996 24.1804L197.745 27.314C198.842 28.7764 200.056 29.8079 201.388 30.4085Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
d="M235.583 30.7219V11.5674H239.813L240.49 13.7548C240.738 13.5413 240.996 13.3344 241.263 13.1342C242.098 12.5074 243.012 12.0113 244.005 11.6457C244.997 11.2801 246.029 11.0973 247.099 11.0973C248.379 11.0973 249.397 11.3193 250.155 11.7632C250.938 12.181 251.526 12.7686 251.917 13.5259C251.976 13.6324 252.032 13.7411 252.085 13.8518C252.371 13.6038 252.668 13.3646 252.975 13.1342C253.81 12.5074 254.711 12.0113 255.678 11.6457C256.67 11.2801 257.701 11.0973 258.772 11.0973C260.052 11.0973 261.083 11.3193 261.867 11.7632C262.65 12.181 263.238 12.7686 263.629 13.5259C264.021 14.2832 264.295 15.145 264.452 16.1112C264.609 17.0513 264.687 18.0305 264.687 19.049V30.7219H258.929V19.3624C258.929 18.2656 258.733 17.5474 258.341 17.2079C257.976 16.8423 257.506 16.6595 256.931 16.6595C256.095 16.6595 255.286 16.9077 254.503 17.4038C253.953 17.7335 253.442 18.1337 252.97 18.6047C252.973 18.752 252.975 18.9001 252.975 19.049V30.7219H247.256V19.3624C247.256 18.2656 247.06 17.5474 246.668 17.2079C246.277 16.8423 245.794 16.6595 245.219 16.6595C244.409 16.6595 243.613 16.9077 242.83 17.4038C242.282 17.7323 241.773 18.1309 241.302 18.5997V30.7219H235.583Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
d="M221.532 31.192C220.122 31.192 218.973 30.983 218.085 30.5652C217.223 30.1474 216.544 29.5729 216.048 28.8417C215.578 28.0844 215.252 27.2357 215.069 26.2956C214.912 25.3293 214.834 24.3109 214.834 23.2402V11.5674H220.553V22.9269C220.553 23.9976 220.775 24.7157 221.219 25.0813C221.663 25.4208 222.211 25.5905 222.864 25.5905C223.438 25.5905 224 25.4991 224.548 25.3163C225.096 25.1074 225.632 24.8201 226.154 24.4546C226.43 24.2478 226.691 24.0192 226.938 23.7687V11.5674H232.696V30.7219H228.426L227.753 28.5454C227.517 28.7523 227.271 28.9555 227.016 29.155C226.206 29.7818 225.345 30.278 224.431 30.6436C223.517 31.0092 222.55 31.192 221.532 31.192Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M188.251 31.192C186.553 31.192 185.078 30.8133 183.824 30.056C183.75 30.0085 183.677 29.9599 183.605 29.9099C183.533 29.8605 183.463 29.8099 183.393 29.7581V38.1644H177.674V11.5674H181.944L182.509 13.4749C182.928 13.0288 183.393 12.641 183.903 12.3116C185.156 11.5021 186.618 11.0973 188.29 11.0973C190.039 11.0973 191.567 11.5282 192.873 12.39C194.205 13.2256 195.236 14.4007 195.967 15.9153C196.725 17.4299 197.103 19.1796 197.103 21.1642C197.103 23.1227 196.725 24.8593 195.967 26.3739C195.21 27.8885 194.165 29.0767 192.834 29.9385C191.502 30.7741 189.974 31.192 188.251 31.192ZM187.193 25.8256C188.368 25.8256 189.334 25.3947 190.092 24.5329C190.875 23.645 191.267 22.5222 191.267 21.1642C191.267 19.7802 190.875 18.6573 190.092 17.7955C189.334 16.9077 188.368 16.4637 187.193 16.4637C186.044 16.4637 185.078 16.9077 184.294 17.7955C183.511 18.6573 183.119 19.7671 183.119 21.1251C183.119 22.5091 183.511 23.645 184.294 24.5329C185.078 25.3947 186.044 25.8256 187.193 25.8256Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M157.015 31.192C155.03 31.192 153.28 30.7741 151.766 29.9385C150.251 29.0767 149.076 27.8885 148.24 26.3739C147.405 24.8593 146.987 23.1227 146.987 21.1642C146.987 19.1796 147.405 17.4299 148.24 15.9153C149.076 14.4007 150.251 13.2256 151.766 12.39C153.28 11.5282 155.03 11.0973 157.015 11.0973C159.025 11.0973 160.788 11.5282 162.303 12.39C163.817 13.2256 164.992 14.4007 165.828 15.9153C166.69 17.4299 167.121 19.1796 167.121 21.1642C167.121 23.1227 166.69 24.8593 165.828 26.3739C164.992 27.8885 163.817 29.0767 162.303 29.9385C160.788 30.7741 159.025 31.192 157.015 31.192ZM157.015 25.6297C158.294 25.6297 159.326 25.2249 160.109 24.4154C160.919 23.5798 161.323 22.496 161.323 21.1642C161.323 19.8063 160.919 18.7095 160.109 17.8738C159.326 17.0382 158.294 16.6204 157.015 16.6204C155.787 16.6204 154.769 17.0382 153.959 17.8738C153.176 18.6834 152.784 19.7671 152.784 21.1251C152.784 22.483 153.176 23.5798 153.959 24.4154C154.769 25.2249 155.787 25.6297 157.015 25.6297Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M132.363 38.086C133.434 38.3994 134.478 38.556 135.497 38.556C137.56 38.556 139.322 38.1513 140.785 37.3417C142.273 36.5322 143.409 35.331 144.193 33.738C144.976 32.1451 145.368 30.2257 145.368 27.9799V11.5674H141.098L140.466 13.6672C139.998 13.1277 139.464 12.6628 138.865 12.2725C137.664 11.489 136.267 11.0973 134.674 11.0973C132.977 11.0973 131.462 11.5021 130.13 12.3116C128.798 13.095 127.754 14.1918 126.997 15.6019C126.265 16.986 125.9 18.592 125.9 20.42C125.9 22.2218 126.278 23.8278 127.036 25.238C127.819 26.6481 128.864 27.7449 130.169 28.5283C131.501 29.3118 133.029 29.7034 134.752 29.7034C136.371 29.7034 137.769 29.3378 138.944 28.6067C139.19 28.4512 139.425 28.2826 139.649 28.1007V29.1942C139.649 30.7349 139.27 31.884 138.513 32.6412C137.755 33.4247 136.776 33.8164 135.575 33.8164C134.53 33.8164 133.669 33.5944 132.99 33.1505C132.337 32.7065 131.684 31.9753 131.031 30.9569L126.918 33.0721L127.232 33.738C127.832 34.9131 128.576 35.8533 129.464 36.5583C130.352 37.2896 131.318 37.7988 132.363 38.086ZM138.787 23.4753C138.03 24.2849 137.05 24.6896 135.849 24.6896C134.648 24.6896 133.656 24.2849 132.872 23.4753C132.115 22.6658 131.736 21.6473 131.736 20.42C131.736 19.1404 132.115 18.0958 132.872 17.2863C133.656 16.4767 134.648 16.072 135.849 16.072C137.05 16.072 138.03 16.4767 138.787 17.2863C139.57 18.0958 139.962 19.1404 139.962 20.42C139.962 21.6473 139.57 22.6658 138.787 23.4753Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M115.374 31.192C113.39 31.192 111.64 30.7741 110.125 29.9385C108.611 29.0767 107.436 27.8885 106.6 26.3739C105.764 24.8593 105.346 23.1227 105.346 21.1642C105.346 19.1796 105.764 17.4299 106.6 15.9153C107.436 14.4007 108.611 13.2256 110.125 12.39C111.64 11.5282 113.39 11.0973 115.374 11.0973C117.385 11.0973 119.148 11.5282 120.662 12.39C122.177 13.2256 123.352 14.4007 124.188 15.9153C125.049 17.4299 125.48 19.1796 125.48 21.1642C125.48 23.1227 125.049 24.8593 124.188 26.3739C123.352 27.8885 122.177 29.0767 120.662 29.9385C119.148 30.7741 117.385 31.192 115.374 31.192ZM115.374 25.6297C116.654 25.6297 117.685 25.2249 118.469 24.4154C119.278 23.5798 119.683 22.496 119.683 21.1642C119.683 19.8063 119.278 18.7095 118.469 17.8738C117.685 17.0382 116.654 16.6204 115.374 16.6204C114.147 16.6204 113.128 17.0382 112.319 17.8738C111.535 18.6834 111.144 19.7671 111.144 21.1251C111.144 22.483 111.535 23.5798 112.319 24.4154C113.128 25.2249 114.147 25.6297 115.374 25.6297Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<path
|
||||
d="M88.7671 30.7219H104.984V25.1988H94.486V4.04657H88.7671V30.7219Z"
|
||||
fill="#283841"
|
||||
data-darkreader-inline-fill=""
|
||||
style="--darkreader-inline-fill: #c7c2bb;"
|
||||
></path>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint6_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint8_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint9_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint10_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint11_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint12_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint13_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint14_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint15_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint16_linear_5015_976"
|
||||
x1="-6.27718e-07"
|
||||
y1="18.2949"
|
||||
x2="77.4801"
|
||||
y2="18.2949"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#0046F9" data-darkreader-inline-stopcolor="" style="--darkreader-inline-stopcolor: #0038c7;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.197917"
|
||||
stop-color="#16DBF6"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #07a7bd;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.401042"
|
||||
stop-color="#FFE713"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #908200;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.604167"
|
||||
stop-color="#FF7917"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #be5000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="0.802083"
|
||||
stop-color="#FB0000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #c90000;"
|
||||
></stop>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B30000"
|
||||
data-darkreader-inline-stopcolor=""
|
||||
style="--darkreader-inline-stopcolor: #8f0000;"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 37 KiB |
2
src/lib/dtos/reset-password/index.ts
Normal file
2
src/lib/dtos/reset-password/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from './reset-password-email.dto';
|
||||
export * from './reset-password-token.dto';
|
||||
5
src/lib/dtos/reset-password/reset-password-email.dto.ts
Normal file
5
src/lib/dtos/reset-password/reset-password-email.dto.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const resetPasswordEmailDto = z.object({
|
||||
email: z.string().trim().email().max(64, { message: 'Email must be less than 64 characters' }),
|
||||
});
|
||||
5
src/lib/dtos/reset-password/reset-password-token.dto.ts
Normal file
5
src/lib/dtos/reset-password/reset-password-token.dto.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const resetPasswordTokenDto = z.object({
|
||||
token: z.string().trim().min(6).max(6),
|
||||
});
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import {z} from "zod";
|
||||
|
||||
export const signinDto = z.object({
|
||||
identifier: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(3, { message: 'Must be at least 3 characters' })
|
||||
.max(50, { message: 'Must be less than 50 characters' }),
|
||||
password: z.string({ required_error: 'Password is required' }).trim(),
|
||||
});
|
||||
|
||||
export type signinDto = z.infer<typeof signinDto>;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { refinePasswords } from '../validations/account';
|
||||
import { refinePasswords } from '../../validations/account';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const signupUsernameEmailDto = z
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
import { inject, injectable } from '@needle-di/core';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { openApi } from 'hono-zod-openapi';
|
||||
import { createLoginRequestDto } from '../iam/login-requests/dtos/create-login-request.dto';
|
||||
import { createLoginRequestDto } from '../../../dtos/login/create-login-request.dto';
|
||||
import { LoginRequestsService } from '../iam/login-requests/login-requests.service';
|
||||
import { verifyLoginRequestDto } from '../iam/login-requests/dtos/verify-login-request.dto';
|
||||
import { verifyLoginRequestDto } from '../../../dtos/login/verify-login-request.dto';
|
||||
import { SessionsService } from '../iam/sessions/sessions.service';
|
||||
import { authState } from '../common/middleware/auth.middleware';
|
||||
import { Controller } from '../common/factories/controllers.factory';
|
||||
import { loginRequestDto } from './login-requests/dtos/login-request.dto';
|
||||
import { loginRequestDto } from '../../../dtos/login/login-request.dto';
|
||||
import { signInEmail } from './login-requests/routes/login.routes';
|
||||
import { rateLimit } from '../common/middleware/rate-limit.middleware';
|
||||
import { LoggerService } from '../common/services/logger.service';
|
||||
import { signinDto } from '../dtos/signin.dto';
|
||||
import { signinDto } from '../../../dtos/login/signin.dto';
|
||||
|
||||
@injectable()
|
||||
export class IamController extends Controller {
|
||||
constructor(
|
||||
private loggerService = inject(LoggerService),
|
||||
private loggerService = inject(LoggerService),
|
||||
private loginRequestsService = inject(LoginRequestsService),
|
||||
private sessionsService = inject(SessionsService),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import { CredentialsRepository } from '../../users/credentials.repository';
|
|||
import { UsersRepository } from '../../users/users.repository';
|
||||
import { UsersService } from '../../users/users.service';
|
||||
import { SessionsService } from '../sessions/sessions.service';
|
||||
import type { CreateLoginRequestDto } from './dtos/create-login-request.dto';
|
||||
import type { SignInDto } from '../../dtos/signin.dto';
|
||||
import type { VerifyLoginRequestDto } from './dtos/verify-login-request.dto';
|
||||
import type { CreateLoginRequestDto } from '../../../../dtos/login/create-login-request.dto';
|
||||
import type { SignInDto } from '../../../../dtos/login/signin.dto';
|
||||
import type { VerifyLoginRequestDto } from '../../../../dtos/login/verify-login-request.dto';
|
||||
import { LoginRequestsRepository } from './login-requests.repository';
|
||||
import { LoggerService } from '../../common/services/logger.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { StatusCodes } from '$lib/utils/status-codes';
|
||||
import { defineOpenApiOperation } from 'hono-zod-openapi';
|
||||
import { createErrorSchema } from 'stoker/openapi/schemas';
|
||||
import { loginRequestDto } from '../dtos/login-request.dto';
|
||||
import { loginRequestDto } from '../../../../../dtos/login/login-request.dto';
|
||||
|
||||
export const signInEmail = defineOpenApiOperation({
|
||||
tags: ['Login'],
|
||||
|
|
|
|||
12
src/lib/utils/flashMessages.ts
Normal file
12
src/lib/utils/flashMessages.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
export const notSignedInMessage = {
|
||||
type: 'error',
|
||||
message: 'You are not signed in',
|
||||
} as const;
|
||||
export const forbiddenMessage = {
|
||||
type: 'error',
|
||||
message: 'You are not allowed to access this',
|
||||
} as const;
|
||||
export const signedOutMessage = {
|
||||
type: 'success',
|
||||
message: 'Successfully signed out',
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import {crossfade} from 'svelte/transition';
|
||||
import { crossfade } from 'svelte/transition';
|
||||
|
||||
export const [send, receive] = crossfade({
|
||||
duration: d => Math.sqrt(d * 200),
|
||||
fallback() {
|
||||
return { duration: 600, easing: x => --x * x * x + 1 }; // Ease-out cubic
|
||||
}
|
||||
});
|
||||
duration: (d) => Math.sqrt(d * 200),
|
||||
fallback() {
|
||||
return { duration: 600, easing: (x) => --x * x * x + 1 }; // Ease-out cubic
|
||||
},
|
||||
});
|
||||
|
|
|
|||
43
src/lib/utils/page_loading_indicator.svelte
Normal file
43
src/lib/utils/page_loading_indicator.svelte
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<script lang="ts">
|
||||
import { onNavigate } from "$app/navigation";
|
||||
|
||||
let visible = $state(false);
|
||||
let progress = $state(0);
|
||||
let load_durations = $state<number[]>([]);
|
||||
let average_load = $derived(load_durations.reduce((a, b) => a + b, 0) / load_durations.length);
|
||||
|
||||
const increment = 1;
|
||||
|
||||
onNavigate((navigation) => {
|
||||
const typical_load_time = average_load || 200; //ms
|
||||
const frequency = typical_load_time / 100;
|
||||
let start = performance.now();
|
||||
// Start the progress bar
|
||||
visible = true;
|
||||
progress = 0;
|
||||
const interval = setInterval(() => {
|
||||
// Increment the progress bar
|
||||
progress += increment;
|
||||
}, frequency);
|
||||
// Resolve the promise when the page is done loading
|
||||
navigation?.complete.then(() => {
|
||||
progress = 100; // Fill out the progress bar
|
||||
clearInterval(interval);
|
||||
// after 100 ms hide the progress bar
|
||||
setTimeout(() => {
|
||||
visible = false;
|
||||
}, 500);
|
||||
// Log how long that one took
|
||||
const end = performance.now();
|
||||
const duration = end - start;
|
||||
load_durations = [...load_durations, duration];
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if visible}
|
||||
<div
|
||||
class="fixed top-0 left-0 right-0 h-1 bg-primary z-50 transition-all duration-300 ease-in-out"
|
||||
style="width: {progress}%;"
|
||||
></div>
|
||||
{/if}
|
||||
|
|
@ -2,7 +2,7 @@ import { toast } from "svelte-sonner";
|
|||
import { message, type ErrorStatus, type SuperForm, type SuperValidated } from "sveltekit-superforms";
|
||||
|
||||
export type Message = {
|
||||
type: 'error' | 'success',
|
||||
type: 'error' | 'success' | 'info',
|
||||
text: string
|
||||
}
|
||||
|
||||
|
|
|
|||
8
src/routes/(auth)/+layout.server.ts
Normal file
8
src/routes/(auth)/+layout.server.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export async function load(event) {
|
||||
const { parent } = event;
|
||||
const { authedUser } = await parent();
|
||||
|
||||
return {
|
||||
authedUser,
|
||||
};
|
||||
}
|
||||
148
src/routes/(auth)/+layout.svelte
Normal file
148
src/routes/(auth)/+layout.svelte
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import Logo from "@/components/logo.svelte";
|
||||
|
||||
let { data, children } = $props();
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<a href="/" class="auth-logo">
|
||||
<Logo />
|
||||
</a>
|
||||
<div class="auth-buttons">
|
||||
{#if page.url.pathname !== "/login"}
|
||||
<Button href="/login" variant="ghost">Login</Button>
|
||||
{/if}
|
||||
{#if page.url.pathname !== "/signup"}
|
||||
<Button href="/signup" variant="ghost">Sign up</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="auth-marketing">
|
||||
<div
|
||||
class="image"
|
||||
style="
|
||||
background-image:
|
||||
url(https://images.unsplash.com/photo-1730804518415-75297e8d2a41?q=80&w=1462&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
></div>
|
||||
<div class="quote-wrapper">
|
||||
<blockquote class="quote">
|
||||
<p>
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||
</p>
|
||||
<footer>John Doe</footer>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
|
||||
@media (width >= 768px) {
|
||||
display: grid;
|
||||
}
|
||||
@media (width >= 1024px) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.auth-marketing {
|
||||
display: none;
|
||||
position: relative;
|
||||
padding: 2.5rem;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
|
||||
@media (width >= 1024px) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.quote-wrapper {
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
margin-top: auto;
|
||||
|
||||
.quote {
|
||||
margin-top: 0.5rem;
|
||||
|
||||
p {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.auth-buttons) {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
|
||||
@media (min-width >= 768px) {
|
||||
top: 2rem;
|
||||
right: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-logo {
|
||||
display: flex;
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
font-weight: 500;
|
||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
|
||||
&:hover {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@media (width > 768px) {
|
||||
position: absolute;
|
||||
--fg: #2c3e50;
|
||||
}
|
||||
|
||||
@media (width >= 1024px) {
|
||||
color: white;
|
||||
--fg: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
26
src/routes/(auth)/auth/callback/google/+server.ts
Normal file
26
src/routes/(auth)/auth/callback/google/+server.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { StatusCodes } from '$lib/utils/status-codes';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
|
||||
export async function GET(event: RequestEvent): Promise<Response> {
|
||||
const { locals, url } = event;
|
||||
const code = url.searchParams.get('code');
|
||||
const state = url.searchParams.get('state');
|
||||
console.log('code', code, 'state', state);
|
||||
|
||||
const { data, error } = await locals.api.oauth.google.$get({ query: { code, state } }).then(locals.parseApiResponse);
|
||||
|
||||
if (error) {
|
||||
return new Response(JSON.stringify(error), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return new Response(JSON.stringify({ message: 'Invalid request' }), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
redirect(StatusCodes.TEMPORARY_REDIRECT, '/');
|
||||
}
|
||||
|
|
@ -4,7 +4,8 @@ import { redirect } from 'sveltekit-flash-message/server';
|
|||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { signinDto } from '@/server/api/dtos/signin.dto';
|
||||
import { signinDto } from '@/dtos/login/signin.dto';
|
||||
import { SHOW_OAUTH_BUTTONS } from '$env/static/private';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const { parent } = event;
|
||||
|
|
@ -16,10 +17,11 @@ export const load: PageServerLoad = async (event) => {
|
|||
throw redirect('/', message, event);
|
||||
// redirect(302, '/', message, event)
|
||||
}
|
||||
const form = await superValidate(event, zod(signinDto));
|
||||
const loginForm = await superValidate(event, zod(signinDto));
|
||||
|
||||
return {
|
||||
form,
|
||||
loginForm,
|
||||
showOAuthButtons: SHOW_OAUTH_BUTTONS === 'true',
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -34,25 +36,28 @@ export const actions: Actions = {
|
|||
throw redirect('/', message, event);
|
||||
}
|
||||
|
||||
const form = await superValidate(event, zod(signinDto));
|
||||
const loginForm = await superValidate(event, zod(signinDto));
|
||||
|
||||
const { error } = await locals.api.iam.login.$post({ json: form.data }).then(locals.parseApiResponse);
|
||||
const { error } = await locals.api.iam.login.$post({ json: loginForm.data }).then(locals.parseApiResponse);
|
||||
console.log('Login error', error);
|
||||
if (error) {
|
||||
loginForm.data.password = '';
|
||||
console.log('Setting error');
|
||||
return setError(form, 'identifier', 'An error occurred while logging in.');
|
||||
return setError(loginForm, 'identifier', 'An error occurred while logging in.');
|
||||
}
|
||||
|
||||
if (!form.valid) {
|
||||
form.data.password = '';
|
||||
if (!loginForm.valid) {
|
||||
loginForm.data.password = '';
|
||||
return fail(400, {
|
||||
form,
|
||||
loginForm,
|
||||
});
|
||||
}
|
||||
|
||||
form.data.identifier = '';
|
||||
form.data.password = '';
|
||||
loginForm.data.identifier = '';
|
||||
loginForm.data.password = '';
|
||||
|
||||
const message = { type: 'success', message: 'Signed In!' } as const;
|
||||
redirect(302, '/', message, event);
|
||||
// const { error: totpCredentialError, data } = await locals.api.mfa.totp.$get().then(locals.parseApiResponse);
|
||||
// if (totpCredentialError || !data) {
|
||||
// return setError(form, 'identifier', totpCredentialError ?? 'Something went wrong. Please try again.');
|
||||
|
|
@ -70,7 +75,5 @@ export const actions: Actions = {
|
|||
// } else {
|
||||
// return setError(form, 'identifier', 'Something went wrong. Please try again.');
|
||||
// }
|
||||
|
||||
redirect(StatusCodes.TEMPORARY_REDIRECT, '/');
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import * as Form from '$lib/components/ui/form';
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import * as Form from "$lib/components/ui/form";
|
||||
import { receive, send } from "$lib/utils/pageCrossfade";
|
||||
import { zodClient } from "sveltekit-superforms/adapters";
|
||||
import { superForm } from "sveltekit-superforms/client";
|
||||
import { signinDto } from '@/dtos/signin.dto';
|
||||
import { signinDto } from "$lib/dtos/login/signin.dto.js";
|
||||
|
||||
let { data } = $props();
|
||||
const { showOAuthButtons } = data;
|
||||
|
||||
const sf_login_password = superForm(data.form, {
|
||||
const sf_login_password = superForm(data.loginForm, {
|
||||
validators: zodClient(signinDto),
|
||||
resetForm: false
|
||||
resetForm: false,
|
||||
});
|
||||
|
||||
const { form: loginForm, enhance: loginEnhance, errors: loginErrors } = sf_login_password;
|
||||
|
|
@ -29,8 +30,10 @@
|
|||
</Card.Header>
|
||||
<Card.Content class="grid gap-4">
|
||||
{@render usernameEmailForm()}
|
||||
<!-- <span class="text-center text-sm text-muted-foreground">or sign in with</span> -->
|
||||
<!-- {@render oAuthButtons()} -->
|
||||
{#if showOAuthButtons}
|
||||
<span class="text-center text-sm text-muted-foreground">or sign in with</span>
|
||||
{@render oAuthButtons()}
|
||||
{/if}
|
||||
<p class="px-8 py-4 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our
|
||||
<a href="/terms" class="underline underline-offset-4 hover:text-primary"> Terms of Use </a>
|
||||
|
|
@ -47,7 +50,12 @@
|
|||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Form.Label for="identifier">Username / Email</Form.Label>
|
||||
<Input {...props} autocomplete="username" placeholder="john.doe@example.com" bind:value={$loginForm.identifier} />
|
||||
<Input
|
||||
{...props}
|
||||
autocomplete="username"
|
||||
placeholder="john.doe@example.com"
|
||||
bind:value={$loginForm.identifier}
|
||||
/>
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
|
|
@ -56,7 +64,13 @@
|
|||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Form.Label for="password">Password</Form.Label>
|
||||
<Input {...props} autocomplete="current-password" placeholder={"••••••••"} type="password" bind:value={$loginForm.password} />
|
||||
<Input
|
||||
{...props}
|
||||
autocomplete="current-password"
|
||||
placeholder={"••••••••"}
|
||||
type="password"
|
||||
bind:value={$loginForm.password}
|
||||
/>
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
|
|
@ -71,23 +85,8 @@
|
|||
{#snippet oAuthButtons()}
|
||||
<div class="grid gap-4">
|
||||
<Button href="/login/google" variant="outline" class="w-full flex items-center gap-2">
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
|
||||
><title>Google</title>
|
||||
<path
|
||||
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
|
||||
/>
|
||||
</svg>
|
||||
Google
|
||||
</Button>
|
||||
<Button href="/login/github" variant="outline" class="w-full flex items-center gap-2">
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
|
||||
><title>GitHub</title>
|
||||
<path
|
||||
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
|
||||
/>
|
||||
</svg>
|
||||
GitHub
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import { github } from '$lib/server/auth';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { generateState } from 'arctic';
|
||||
|
||||
export async function GET(event: RequestEvent): Promise<Response> {
|
||||
const state = generateState();
|
||||
const url = await github.createAuthorizationURL(state);
|
||||
|
||||
event.cookies.set('github_oauth_state', state, {
|
||||
path: '/',
|
||||
secure: import.meta.env.PROD,
|
||||
httpOnly: true,
|
||||
maxAge: 60 * 10,
|
||||
sameSite: 'lax',
|
||||
});
|
||||
|
||||
redirect(302, url.toString());
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import { github } from '$lib/server/auth';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { generateState } from 'arctic';
|
||||
|
||||
export async function GET(event: RequestEvent): Promise<Response> {
|
||||
const state = generateState();
|
||||
const url = await github.createAuthorizationURL(state);
|
||||
|
||||
event.cookies.set('github_oauth_state', state, {
|
||||
path: '/',
|
||||
secure: import.meta.env.PROD,
|
||||
httpOnly: true,
|
||||
maxAge: 60 * 10,
|
||||
sameSite: 'lax',
|
||||
});
|
||||
|
||||
redirect(302, url.toString());
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import { github } from '$lib/server/auth';
|
||||
import type { RequestEvent } from '@sveltejs/kit';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { generateState } from 'arctic';
|
||||
|
||||
export async function GET(event: RequestEvent): Promise<Response> {
|
||||
const state = generateState();
|
||||
const url = await github.createAuthorizationURL(state);
|
||||
|
||||
event.cookies.set('github_oauth_state', state, {
|
||||
path: '/',
|
||||
secure: import.meta.env.PROD,
|
||||
httpOnly: true,
|
||||
maxAge: 60 * 10,
|
||||
sameSite: 'lax',
|
||||
});
|
||||
|
||||
redirect(302, url.toString());
|
||||
}
|
||||
56
src/routes/(auth)/password/reset/+page.server.ts
Normal file
56
src/routes/(auth)/password/reset/+page.server.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { notSignedInMessage } from '$lib/utils/flashMessages';
|
||||
import { StatusCodes } from '$lib/utils/status-codes';
|
||||
import { resetPasswordEmailDto, resetPasswordTokenDto } from '$lib/dtos/reset-password';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
return {
|
||||
emailForm: await superValidate(zod(resetPasswordEmailDto)),
|
||||
tokenForm: await superValidate(zod(resetPasswordTokenDto)),
|
||||
};
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
passwordReset: async (event) => {
|
||||
const { request, locals } = event;
|
||||
|
||||
const authedUser = await locals.getAuthedUser();
|
||||
if (!authedUser) {
|
||||
throw redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const emailForm = await superValidate(request, zod(resetPasswordEmailDto));
|
||||
if (!emailForm.valid) {
|
||||
return fail(StatusCodes.BAD_REQUEST, { emailForm });
|
||||
}
|
||||
// const error = {};
|
||||
// // const { error } = await locals.api.iam.login.request.$post({ json: emailRegisterForm.data }).then(locals.parseApiResponse);
|
||||
// if (error) {
|
||||
// return setError(emailForm, 'email', error);
|
||||
// }
|
||||
return { emailForm };
|
||||
},
|
||||
verifyToken: async (event) => {
|
||||
const { request, locals } = event;
|
||||
|
||||
const authedUser = await locals.getAuthedUser();
|
||||
if (!authedUser) {
|
||||
throw redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const tokenForm = await superValidate(request, zod(resetPasswordTokenDto));
|
||||
if (!tokenForm.valid) {
|
||||
return fail(StatusCodes.BAD_REQUEST, { tokenForm });
|
||||
}
|
||||
const error = {};
|
||||
// const { error } = await locals.api.iam.login.verify.$post({ json: emailSignInForm.data }).then(locals.parseApiResponse)
|
||||
if (error) {
|
||||
return setError(tokenForm, 'token', error);
|
||||
}
|
||||
redirect(301, '/');
|
||||
},
|
||||
};
|
||||
98
src/routes/(auth)/password/reset/+page.svelte
Normal file
98
src/routes/(auth)/password/reset/+page.svelte
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<script lang="ts">
|
||||
import * as Card from "$lib/components/ui/card/index.js";
|
||||
import * as Form from '$lib/components/ui/form/index.js';
|
||||
import * as InputOTP from '$lib/components/ui/input-otp/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { receive, send } from '$lib/utils/pageCrossfade';
|
||||
import { resetPasswordEmailDto, resetPasswordTokenDto } from '$lib/dtos/reset-password';
|
||||
import { superForm } from 'sveltekit-superforms';
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
|
||||
const { data } = $props();
|
||||
|
||||
let showTokenVerification = $state(false);
|
||||
|
||||
const emailResetForm = superForm(data.emailForm, {
|
||||
validators: zodClient(resetPasswordEmailDto),
|
||||
resetForm: false,
|
||||
onUpdated: ({ form }) => {
|
||||
if (form.valid) {
|
||||
showTokenVerification = true;
|
||||
$emailFormData.email = form.data.email;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const tokenVerificationForm = superForm(data.tokenForm, {
|
||||
validators: zodClient(resetPasswordTokenDto),
|
||||
resetForm: false,
|
||||
});
|
||||
|
||||
const { form: emailFormData, enhance: emailResetEnhance } = emailResetForm;
|
||||
const { form: tokenFormData, enhance: tokenEnhance } = tokenVerificationForm;
|
||||
</script>
|
||||
|
||||
<div out:send={{ key: 'auth-card' }} in:receive={{ key: 'auth-card' }}>
|
||||
<Card.Root class="mx-auto max-w-sm">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-2xl">Reset Password</Card.Title>
|
||||
<Card.Description>Enter your email to reset your password</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="grid gap-4">
|
||||
{#if showTokenVerification}
|
||||
{@render tokenForm()}
|
||||
{:else}
|
||||
{@render emailForm()}
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
{#snippet emailForm()}
|
||||
<form method="POST" action="?/passwordReset" use:emailResetEnhance class="grid gap-4">
|
||||
<Form.Field form={emailResetForm} name="email">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Form.Label for="email">Email</Form.Label>
|
||||
<Form.Input
|
||||
{...props}
|
||||
type="email"
|
||||
placeholder="you@awesome.com"
|
||||
bind:value={$emailFormData.email}
|
||||
/>
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.Description />
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Button type="submit" class="w-full">Continue with Email</Button>
|
||||
</form>
|
||||
{/snippet}
|
||||
|
||||
{#snippet tokenForm()}
|
||||
<form method="POST" action="?/verifyToken" use:tokenEnhance class="space-y-4">
|
||||
<input hidden value={$tokenFormData.resetToken} name="email" />
|
||||
<Form.Field form={tokenVerificationForm} name="resetToken">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Form.Label for="resetToken">Enter the token that was sent to your email</Form.Label>
|
||||
<InputOTP.Root maxlength={6} {...props} bind:value={$tokenFormData.resetToken}>
|
||||
{#snippet children({ cells })}
|
||||
<InputOTP.Group>
|
||||
{#each cells as cell}
|
||||
<InputOTP.Slot {cell} />
|
||||
{/each}
|
||||
</InputOTP.Group>
|
||||
{/snippet}
|
||||
</InputOTP.Root>
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.Description />
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Button class="w-full" type="submit">Submit</Button>
|
||||
</form>
|
||||
{/snippet}
|
||||
|
|
@ -15,11 +15,10 @@ const signUpDefaults = {
|
|||
};
|
||||
|
||||
export const load = async (event) => {
|
||||
const { locals } = event;
|
||||
const { parent } = event;
|
||||
const { authedUser } = await parent();
|
||||
|
||||
const user = await locals.getAuthedUser();
|
||||
|
||||
if (user) {
|
||||
if (authedUser) {
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
}
|
||||
|
|
@ -32,25 +31,24 @@ export const load = async (event) => {
|
|||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async (event) => {
|
||||
default: async (event) => {
|
||||
const { locals } = event;
|
||||
const authedUser = await locals.getAuthedUser();
|
||||
|
||||
const user = await locals.getAuthedUser();
|
||||
|
||||
if (user) {
|
||||
if (authedUser) {
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
}
|
||||
|
||||
const form = await superValidate(event, zod(signupUsernameEmailDto));
|
||||
const form = await superValidate(event, zod(signupUsernameEmailDto));
|
||||
|
||||
console.log('form data', form.data);
|
||||
console.log('form data', form.data);
|
||||
|
||||
const { error } = await locals.api.signup.$post({ json: form.data }).then(locals.parseApiResponse);
|
||||
if (error) {
|
||||
console.log('error', error);
|
||||
form.data.password = '';
|
||||
form.data.confirm_password = '';
|
||||
if (error) {
|
||||
console.log('error', error);
|
||||
form.data.password = '';
|
||||
form.data.confirm_password = '';
|
||||
return setError(form, 'username', 'Unable to sign up.');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,70 +4,88 @@
|
|||
import * as Card from '$lib/components/ui/card/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { receive, send } from "$lib/utils/pageCrossfade";
|
||||
import { superForm } from 'sveltekit-superforms';
|
||||
import * as Form from '$lib/components/ui/form';
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
import { signupUsernameEmailDto } from '@/dtos/signup-username-email.dto';
|
||||
import { signupUsernameEmailDto } from '$lib/dtos/signup/signup-username-email.dto.js';
|
||||
|
||||
const { data } = $props();
|
||||
|
||||
const signupForm = superForm(data.signupForm, {
|
||||
const sf_signup = superForm(data.signupForm, {
|
||||
validators: zodClient(signupUsernameEmailDto),
|
||||
resetForm: false,
|
||||
});
|
||||
|
||||
const { form: signupFormData, errors: signupErrors, enhance: signupEnhance } = signupForm;
|
||||
const { form: signupForm, errors: signupErrors, enhance: signupEnhance } = sf_signup;
|
||||
</script>
|
||||
|
||||
<Card.Root class="mx-auto mt-24 max-w-sm">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-2xl">Signup for an account</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="grid gap-4">
|
||||
{@render signUpForm()}
|
||||
</div>
|
||||
<div class="mt-4 text-center text-sm">
|
||||
By registering, you agree to our <a href="##" class="underline">Terms of Service</a>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<svelte:head>
|
||||
<title>Acme | Sign Up</title>
|
||||
</svelte:head>
|
||||
|
||||
<div in:receive={{ key: 'auth-card' }} out:send={{ key: 'auth-card' }}>
|
||||
<Card.Root class="mx-auto mt-24 max-w-sm">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-2xl">Signup for an account</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="grid gap-4">
|
||||
{@render signUpForm()}
|
||||
</div>
|
||||
<div class="mt-4 text-center text-sm">
|
||||
By registering, you agree to our <a href="##" class="underline">Terms of Service</a>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
{#snippet signUpForm()}
|
||||
<form method="POST" action="/signup" use:signupEnhance class="grid gap-2 mt-4">
|
||||
<Label for="username">Username <small>(required)</small></Label>
|
||||
<Input type="text" id="username" class={$signupErrors.username && "outline outline-destructive"} name="username"
|
||||
placeholder="Username" autocomplete="username" data-invalid={$signupErrors.username} bind:value={$signupFormData.username} />
|
||||
{#if $signupErrors.username}
|
||||
<p class="text-sm text-destructive">{$signupErrors.username}</p>
|
||||
{/if}
|
||||
<Label for="password">Password <small>(required)</small></Label>
|
||||
<Input type="password" id="password" class={$signupErrors.password && "outline outline-destructive"} name="password"
|
||||
placeholder="Password" autocomplete="new-password" data-invalid={$signupErrors.password}
|
||||
bind:value={$signupFormData.password} />
|
||||
{#if $signupErrors.password}
|
||||
<p class="text-sm text-destructive">{$signupErrors.password}</p>
|
||||
{/if}
|
||||
<Label for="confirm_password">Confirm Password <small>(required)</small></Label>
|
||||
<Input type="password" id="confirm_password" class={$signupErrors.confirm_password && "outline outline-destructive"}
|
||||
name="confirm_password" placeholder="Confirm Password" autocomplete="new-password"
|
||||
data-invalid={$signupErrors.confirm_password} bind:value={$signupFormData.confirm_password} />
|
||||
{#if $signupErrors.confirm_password}
|
||||
<p class="text-sm text-destructive">{$signupErrors.confirm_password}</p>
|
||||
{/if}
|
||||
<Label for="email">Email</Label>
|
||||
<Input type="email" id="email" class={$signupErrors.email && "outline outline-destructive"} name="email"
|
||||
placeholder="Email" autocomplete="email" data-invalid={$signupErrors.email} bind:value={$signupFormData.email} />
|
||||
{#if $signupErrors.email}
|
||||
<p class="text-sm text-destructive">{$signupErrors.email}</p>
|
||||
{/if}
|
||||
<Form.Field form={sf_signup} name="username">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Label for="username">Username <small>(required)</small></Label>
|
||||
<Input {...props} type="text" id="username" class={$signupErrors.username && "outline outline-destructive"} name="username" placeholder="Username" autocomplete="username" data-invalid={$signupErrors.username} bind:value={$signupForm.username} />
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Field form={sf_signup} name="password">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Label for="password">Password <small>(required)</small></Label>
|
||||
<Input {...props} type="password" id="password" class={$signupErrors.password && "outline outline-destructive"} name="password" placeholder="Password" autocomplete="new-password" data-invalid={$signupErrors.password}
|
||||
bind:value={$signupForm.password} />
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Field form={sf_signup} name="confirm_password">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Label for="confirm_password">Confirm Password <small>(required)</small></Label>
|
||||
<Input {...props} type="password" id="confirm_password" class={$signupErrors.confirm_password && "outline outline-destructive"} name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" data-invalid={$signupErrors.confirm_password} bind:value={$signupForm.confirm_password} />
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Field form={sf_signup} name="email">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Label for="email">Email</Label>
|
||||
<Input {...props} type="email" id="email" class={$signupErrors.email && "outline outline-destructive"} name="email" placeholder="Email" autocomplete="email" data-invalid={$signupErrors.email} bind:value={$signupForm.email} />
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<div class="grid grid-cols-2">
|
||||
<Button type="submit">Signup</Button>
|
||||
<Form.Button type="submit">Signup</Form.Button>
|
||||
<Button variant="link" class="text-secondary-foreground" href="/">or Cancel</Button>
|
||||
</div>
|
||||
{#if !$signupFormData.email}
|
||||
{#if !$signupForm.email}
|
||||
<Alert.Root>
|
||||
<Alert.Title level="h3">Heads up!</Alert.Title>
|
||||
<Alert.Title level={3}>Heads up!</Alert.Title>
|
||||
<Alert.Description>
|
||||
Without an email address, you won't be able to reset your password. Submit only if you are sure. You can
|
||||
always add this later.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
export const load = async ({ locals }) => {
|
||||
import { loadFlash } from "sveltekit-flash-message/server";
|
||||
|
||||
export const load = loadFlash(async ({ locals }) => {
|
||||
const authedUser = await locals.getAuthedUser();
|
||||
console.log('authedUser', authedUser)
|
||||
|
||||
return {
|
||||
authedUser
|
||||
}
|
||||
}
|
||||
authedUser,
|
||||
};
|
||||
});
|
||||
|
|
@ -1,13 +1,51 @@
|
|||
<script>
|
||||
import '../app.css';
|
||||
import { page as pageStore } from '$app/stores';
|
||||
import { getFlash } from 'sveltekit-flash-message';
|
||||
import { ModeWatcher } from 'mode-watcher';
|
||||
import { Toaster } from "$lib/components/ui/sonner";
|
||||
import { i18n } from '$lib/i18n';
|
||||
import { ParaglideJS } from '@inlang/paraglide-sveltekit';
|
||||
import { toastMessage } from '@/utils/superforms';
|
||||
import { onNavigate } from '$app/navigation';
|
||||
import PageLoadingIndicator from '$lib/utils/page_loading_indicator.svelte';
|
||||
|
||||
const { children } = $props();
|
||||
const { data, children } = $props();
|
||||
|
||||
const flash = getFlash(pageStore, {
|
||||
clearOnNavigate: true,
|
||||
clearAfterMs: 3000,
|
||||
clearArray: true,
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
// console.log('flash', $flash);
|
||||
if ($flash) {
|
||||
toastMessage({ type: $flash.type, text: $flash.message });
|
||||
// Clearing the flash message could sometimes
|
||||
// be required here to avoid double-toasting.
|
||||
flash.set(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
onNavigate(async (navigation) => {
|
||||
if (!document.startViewTransition) return;
|
||||
|
||||
return new Promise((oldStateCaptureResolve) => {
|
||||
document.startViewTransition(async () => {
|
||||
oldStateCaptureResolve();
|
||||
await navigation.complete;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<PageLoadingIndicator />
|
||||
<ModeWatcher />
|
||||
<Toaster />
|
||||
<main class="antialiased">
|
||||
{@render children?.()}
|
||||
</main>
|
||||
|
||||
<ParaglideJS {i18n}>
|
||||
<main class="antialiased">
|
||||
{@render children?.()}
|
||||
</main>
|
||||
</ParaglideJS>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// import { app } from '$lib/server/api';
|
||||
import {app} from '../../../hooks.server';
|
||||
import { app } from '../../../hooks.server';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const GET: RequestHandler = ({ request }) => app.request(request);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const config = {
|
|||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
$lib: "./src/lib",
|
||||
"@/*": "./src/lib/*"
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue