summaryrefslogtreecommitdiff
path: root/views/pages
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'views/pages')
-rw-r--r--views/pages/blog-catalogue.html193
-rw-r--r--views/pages/blog-page.html97
-rw-r--r--views/pages/global-map.html583
-rw-r--r--views/pages/home-page.html123
-rw-r--r--views/pages/language-pick.html16
-rw-r--r--views/pages/robots.txt7
-rw-r--r--views/pages/sitemap.xml10
-rw-r--r--views/pages/unsubscribe-page.html77
-rw-r--r--views/pages/user-page.html206
9 files changed, 988 insertions, 324 deletions
diff --git a/views/pages/blog-catalogue.html b/views/pages/blog-catalogue.html
index a5f5256..8e1cf72 100644
--- a/views/pages/blog-catalogue.html
+++ b/views/pages/blog-catalogue.html
@@ -1,61 +1,150 @@
{{ define "body" }}
-<div class="flex flex-row ar-lt-0.8:flex-col text-[1vmax] h-[100%]">
- <form hx-get="/api/v1/blog-search" hx-vals='{"lang": "{{ .Lang }}"}' hx-target=".blog-cards" hx-swap="innerHTML"
- class="tags-list ar-gt-0.8:min-w-[10vh] ar-gt-0.8:max-w-[20vh] ar-gt-0.8:w-fit ar-lt-0.8:w-[100%] ar-lt-0.8:max-h-[25%] flex shrink-0 flex-col ar-gt-0.8:mr-[1.2vmin]">
- <div class="flex flex-col overflow-y-auto">
- <fieldset>
- <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.TagsHeader }}</legend>
- <div class="flex flex-col ar-lt-0.8:grid grid-cols-5 grid-flow-row-dense">
- <div class="m-[0.4vmin]">
- <label class="font-bold"><input type="checkbox" id="tagsAllCheckbox" onclick="selectAll();"> {{ .L.BlogSearch.ChooseAllTags }}</label>
+<!-- Streamline Icons: https://streamlinehq.com -->
+<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
+ <symbol id="icon-like" viewBox="-2 -2 28 28" fill="none">
+ <path fill="currentColor" d="M22.155 6.29294c-0.8113 -1.34837 -1.8229 -2.56561 -3 -3.61 -1.6282 -1.47261 -3.6782 -2.396134 -5.86 -2.6399952C11.1388 -0.137008 8.97321 0.252665 7.015 1.17294c-1.6708 0.75913 -3.14018 1.8997 -4.29 3.33C1.59785 5.92036 0.798705 7.56988 0.385003 9.33294c-0.010341 0.04271 -0.012051 0.08704 -0.005029 0.13041 0.007022 0.04337 0.022633 0.08491 0.045919 0.12216 0.023286 0.03726 0.053777 0.06949 0.089685 0.09481 0.035908 0.02532 0.07651 0.04321 0.119425 0.05262 0.083317 0.01503 0.169224 -0.00254 0.239953 -0.04907 0.070728 -0.04653 0.120867 -0.11846 0.140044 -0.20093 0.42729 -1.65655 1.22384 -3.19495 2.33 -4.5 1.0777 -1.30186 2.44846 -2.32993 4 -3 1.83266 -0.80027 3.84 -1.117035 5.83 -0.92 1.9654 0.25006 3.804 1.10643 5.26 2.45 1.0733 0.9746 1.9996 2.09963 2.75 3.34 0.77 1.20382 1.2366 2.57635 1.36 3.99996 0.1304 1.5877 -0.0565 3.1854 -0.55 4.7 -0.5032 1.5017 -1.4221 2.8298 -2.65 3.83 -0.7981 0.673 -1.7331 1.1644 -2.74 1.44 -1.5427 0.4432 -3.1354 0.6885 -4.74 0.73 -0.0778 0.0052 -0.1505 0.0404 -0.2028 0.0983 -0.0523 0.0579 -0.08 0.1338 -0.0772 0.2117 0 0.039 0.0078 0.0775 0.023 0.1134 0.0152 0.0358 0.0374 0.0683 0.0654 0.0953 0.028 0.0271 0.0612 0.0482 0.0976 0.0622 0.0363 0.014 0.0751 0.0205 0.114 0.0191 1.6629 -0.0085 3.3184 -0.2201 4.93 -0.63 1.0928 -0.2824 2.1146 -0.7899 3 -1.49 1.3927 -1.0653 2.454 -2.5046 3.06 -4.15 0.5754 -1.6287 0.8235 -3.3551 0.73 -5.08 -0.1076 -1.59917 -0.6055 -3.14765 -1.45 -4.50996Z" stroke-width="1"></path>
+ <path fill="currentColor" d="M15.935 15.903c0.6791 -0.2938 1.2468 -0.7964 1.6208 -1.4347 0.3741 -0.6384 0.5349 -1.3794 0.4592 -2.1153 -0.0284 -0.1682 -0.0994 -0.3264 -0.2061 -0.4594 -0.1068 -0.133 -0.2458 -0.2365 -0.4039 -0.3007 -0.4529 -0.1228 -0.927 -0.1466 -1.39 -0.0699 -1.22 0.07 -3.05 0.38 -4.54 0.54 -0.4 0.05 -0.78 0.08 -1.11 0.1 -0.0689 0.0127 -0.1312 0.0492 -0.1761 0.1031 -0.0448 0.0539 -0.0693 0.1217 -0.0693 0.1919 0 0.0701 0.0245 0.1379 0.0693 0.1918 0.0449 0.0539 0.1072 0.0904 0.1761 0.1032l5.66 -0.18h0.83c0.0328 0.5028 -0.0896 1.0037 -0.3508 1.4347 -0.2611 0.431 -0.6483 0.7715 -1.1092 0.9753 -0.4499 0.3065 -0.9606 0.5125 -1.4972 0.6039 -0.5367 0.0915 -1.0868 0.0663 -1.6128 -0.074 -0.4102 -0.1727 -0.7888 -0.4126 -1.12 -0.71 -0.3351 -0.2774 -0.6136 -0.6169 -0.82 -1 -0.0184 -0.0407 -0.0446 -0.0774 -0.0771 -0.108 -0.0326 -0.0305 -0.0709 -0.0544 -0.1127 -0.0702 -0.0418 -0.0158 -0.0862 -0.0232 -0.1309 -0.0218 -0.04465 0.0014 -0.08858 0.0116 -0.12929 0.03 -0.04037 0.0174 -0.07686 0.0426 -0.10734 0.0743 -0.03049 0.0316 -0.05435 0.069 -0.07018 0.11 -0.01584 0.041 -0.02333 0.0847 -0.02203 0.1286 0.00129 0.044 0.01133 0.0872 0.02955 0.1272 0.21114 0.4969 0.52069 0.9459 0.90999 1.32 0.3786 0.3811 0.8137 0.7015 1.29 0.95 0.6592 0.2289 1.361 0.3082 2.0546 0.2321 0.6936 -0.0762 1.3616 -0.3057 1.9554 -0.6721Z" stroke-width="1"></path>
+ <path fill="currentColor" d="M8.33499 10.9829c0.22252 0.0613 0.45748 0.0613 0.68 0 0.17653 -0.0617 0.33498 -0.1663 0.46112 -0.3044 0.12615 -0.1381 0.21605 -0.3053 0.26164 -0.4867 0.04559 -0.1814 0.04545 -0.37124 -0.00041 -0.55256 -0.04586 -0.18131 -0.136 -0.34841 -0.26235 -0.4863 -1 -1.24 -3 0.82 -1.74 1.71996 0.1869 0.0887 0.39382 0.1266 0.6 0.11Z" stroke-width="1"></path>
+ <path fill="currentColor" d="M19.1653 10.343c0.2247 0.0401 0.456 0.0194 0.67 -0.06 0.1784 -0.0611 0.3386 -0.1658 0.4661 -0.30464 0.1275 -0.13885 0.2183 -0.3074 0.264 -0.4903 0.0457 -0.1829 0.045 -0.37432 -0.0022 -0.55685 -0.0472 -0.18253 -0.1393 -0.35035 -0.2679 -0.48818 -1 -1.23 -3 0.83 -1.74 1.72997 0.1838 0.1117 0.3949 0.1705 0.61 0.17Z" stroke-width="1"></path>
+ <path fill="currentColor" d="M9.63505 20.0929c-0.10233 -0.204 -0.25778 -0.3768 -0.45 -0.5 0.19629 -0.3235 0.27075 -0.7064 0.21 -1.08 -0.04172 -0.3535 -0.15757 -0.6943 -0.34 -1 -0.13496 -0.1997 -0.31256 -0.3671 -0.52 -0.49 0.04212 -0.0952 0.06912 -0.1964 0.08 -0.3 0.05325 -0.3277 0.02651 -0.6634 -0.07796 -0.9786 -0.10447 -0.3151 -0.28357 -0.6003 -0.52204 -0.8314 -0.51428 -0.3306 -1.1194 -0.4915 -1.73 -0.46 -0.74972 -0.022 -1.49478 0.125 -2.18 0.43 0.05982 -0.8997 -0.19079 -1.7927 -0.71 -2.53 -0.9 -1 -2.54 -0.13 -2.71 1.36 -0.017326 0.6116 0.060262 1.2222 0.23 1.81 0.28 1 0.23 0.95 0.48 1.33 -0.22002 0.2395 -0.405175 0.5088 -0.55 0.8 -0.1 0.34 -0.28 0.74 -0.12 1 0.16 0.26 0.3 0.23 0.47 0.06 0.17 -0.17 0.09 -0.44 0.14 -0.6 0.07428 -0.2866 0.22256 -0.5487 0.43 -0.76 0.16 -0.21 0.28 -0.22 0.47 -0.4 1.85 -1.77 4.62 -1.97 5.12 -1.28 0.85 1.16 -1.16 1.29 -2.9 2.37 -0.03825 0.011 -0.07372 0.03 -0.10405 0.0557 -0.03034 0.0258 -0.05483 0.0577 -0.07187 0.0936 -0.01703 0.036 -0.0262 0.0752 -0.02691 0.1149 -0.0007 0.0398 0.00708 0.0793 0.02283 0.1158 0.01228 0.0374 0.03203 0.0719 0.05805 0.1014 0.02602 0.0295 0.05777 0.0534 0.09332 0.0702 0.03554 0.0168 0.07414 0.0263 0.11345 0.0277 0.0393 0.0015 0.07849 -0.0051 0.11518 -0.0193 0.41 -0.06 0.77 -0.06 1.12 -0.11 1 -0.17 1.25 -0.66 2.16 -0.51 0.15573 0.127 0.26274 0.3039 0.30284 0.5008 0.0401 0.1968 0.01083 0.4015 -0.08284 0.5792 -0.45993 0.315 -0.97588 0.539 -1.52 0.66 -0.36935 0.1765 -0.72678 0.377 -1.07 0.6 -0.03798 0.0103 -0.07348 0.0282 -0.10433 0.0526 -0.03085 0.0244 -0.05641 0.0549 -0.07512 0.0895 -0.01871 0.0346 -0.03018 0.0727 -0.03371 0.1119 -0.00353 0.0391 0.00094 0.0786 0.01316 0.116 0.01027 0.038 0.02815 0.0735 0.05258 0.1044 0.02442 0.0308 0.05486 0.0564 0.08948 0.0751 0.03461 0.0187 0.07267 0.0302 0.11185 0.0337 0.03919 0.0035 0.07869 -0.0009 0.11609 -0.0132 0.36103 -0.003 0.7216 -0.0264 1.08 -0.07 0.15662 -0.0212 0.31072 -0.0581 0.46 -0.11 0.36406 -0.2158 0.79585 -0.2872 1.21 -0.2 0.03286 0.0062 0.06407 0.0192 0.09162 0.0381 0.02755 0.019 0.05084 0.0435 0.06838 0.0719 0.03012 0.0772 0.03012 0.1629 0 0.24 -0.05277 0.2543 -0.17376 0.4893 -0.35 0.68 -0.20205 0.2292 -0.43028 0.434 -0.68 0.61 -0.66869 0.4607 -1.44234 0.7461 -2.25 0.83 -0.80071 0.1179 -1.61838 -0.0039 -2.35 -0.35 -0.53395 -0.2824 -0.95681 -0.737 -1.2 -1.29 -0.27045 -0.5855 -0.42982 -1.2162 -0.47 -1.86 -0.00126 -0.0442 -0.0114 -0.0877 -0.02981 -0.1279 -0.01841 -0.0403 -0.04473 -0.0764 -0.07738 -0.1062 -0.03265 -0.0299 -0.07097 -0.0529 -0.11269 -0.0676 -0.04171 -0.0148 -0.08596 -0.021 -0.13012 -0.0183 -0.044675 0.0026 -0.088408 0.0139 -0.12869 0.0334s-0.076321 0.0468 -0.106051 0.0802c-0.029729 0.0334 -0.052563 0.0724 -0.067194 0.1147 -0.014631 0.0423 -0.02077 0.0871 -0.018065 0.1317 0.012623 0.8862 0.235395 1.7567 0.65 2.54 0.30359 0.5453 0.74942 0.9981 1.29 1.31 0.8694 0.479 1.8607 0.6912 2.85 0.61 0.9936 -0.0912 1.94725 -0.4355 2.77 -1 0.4107 -0.274 0.77525 -0.6115 1.08 -1 0.2272 -0.2941 0.3845 -0.6361 0.46 -1 0.04902 -0.304 -0.00001 -0.6157 -0.14 -0.89Zm-7.81 -3.72 -0.09 -1c0 -0.75 -0.13 -1.73 0.37 -2.19 0.1 0 0.45 -0.59 0.88 0.22 0.2375 0.4432 0.38371 0.9294 0.43 1.43 -0.00039 0.0506 0.01118 0.1005 0.03377 0.1457 0.0226 0.0451 0.05557 0.0843 0.09623 0.1143 -0.63566 0.3358 -1.2158 0.7676 -1.72 1.28Z" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-view" viewBox="-2 -2 28 28" fill="none">
+ <path fill="currentColor" fill-rule="evenodd" d="M23.6534 10.5263c-1.3628 -1.56103 -3.0387 -2.81795 -4.9189 -3.68916 -1.8052 -0.8978 -3.7485 -1.48585 -5.7486 -1.7396 -0.998 -0.11306 -2.0067 -0.09289 -2.99934 0.05999 -2.63062 0.3739 -5.14267 1.33771 -7.34828 2.81934 -0.84337 0.55535 -1.63325 1.18793 -2.359454 1.88956 -0.08425 0.0868 -0.161162 0.18047 -0.2299462 0.27997C0.0169406 10.1973 0 10.2562 0 10.3163s0.0169406 0.1191 0.0488798 0.17c0.0179573 0.0358 0.0429176 0.0677 0.0734052 0.0937 0.030488 0.0261 0.065885 0.0457 0.104099 0.0578 0.038214 0.0122 0.078469 0.0165 0.118385 0.0128 0.039917 -0.0037 0.078686 -0.0154 0.114015 -0.0343C1.5971 9.42178 2.95486 8.45777 4.45785 7.77692c0.959 -0.48729 1.9636 -0.87909 2.9993 -1.16973 0.88979 -0.25558 1.79943 -0.43617 2.71935 -0.53987 0.8961 -0.11518 1.8033 -0.11518 2.6994 0 1.8879 0.28843 3.7154 0.88632 5.4087 1.76959 1.6883 0.80557 3.2029 1.93308 4.459 3.31919 0.0877 0.152 0.1339 0.3244 0.1339 0.4999s-0.0462 0.3479 -0.1339 0.4999c-0.2004 0.4189 -0.4747 0.7983 -0.8098 1.1197 -0.9132 0.9438 -1.9179 1.7945 -2.9993 2.5394 -1.0941 0.7277 -2.2767 1.3123 -3.5192 1.7396 -0.786 0.2536 -1.6039 0.395 -2.4294 0.4199 -1.2488 0.0246 -2.4978 -0.0321 -3.73917 -0.1699 -1.55221 -0.2376 -3.01813 -0.8673 -4.259 -1.8296 -1.29902 -0.9356 -2.40844 -2.1095 -3.26924 -3.4592 -0.02265 -0.0404 -0.05333 -0.0757 -0.09014 -0.1039 -0.03681 -0.0281 -0.07898 -0.0484 -0.12392 -0.0596 -0.04494 -0.0113 -0.0917 -0.0132 -0.13741 -0.0057s-0.08941 0.0243 -0.12842 0.0492c-0.07659 0.0529 -0.13044 0.1327 -0.15082 0.2235 -0.02039 0.0908 -0.0058 0.1859 0.04085 0.2664 0.8813 1.4449 2.02784 2.7102 3.37921 3.7292 1.34805 1.0808 2.9532 1.7938 4.65891 2.0695 1.26545 0.179 2.54115 0.2758 3.81915 0.2899 0.8996 0.0048 1.7952 -0.1198 2.6593 -0.3699 1.3434 -0.4251 2.6244 -1.0269 3.8092 -1.7896 1.1699 -0.7705 2.2556 -1.6619 3.2392 -2.6594 0.5478 -0.5108 0.9601 -1.1498 1.1997 -1.8595 0.0999 -0.2934 0.1302 -0.606 0.0886 -0.9131 -0.0417 -0.3071 -0.1541 -0.6003 -0.3285 -0.8565Z" clip-rule="evenodd" stroke-width="1"></path>
+ <path fill="currentColor" fill-rule="evenodd" d="M10.6964 9.1166c0.7827 -0.2444 1.6136 -0.29247 2.4194 -0.13997 0.3938 0.09551 0.7634 0.27195 1.0852 0.51809 0.3219 0.24613 0.589 0.55658 0.7844 0.91158 0.0189 0.0362 0.0448 0.0683 0.0762 0.0944 0.0314 0.0262 0.0677 0.0458 0.1067 0.0579 0.039 0.0121 0.08 0.0163 0.1207 0.0125 0.0407 -0.0038 0.0802 -0.0157 0.1163 -0.0348 0.0713 -0.04 0.124 -0.1066 0.1465 -0.1853 0.0224 -0.0786 0.0129 -0.163 -0.0266 -0.2346 -0.213 -0.44629 -0.5169 -0.84312 -0.8922 -1.16507 -0.3753 -0.32195 -0.8138 -0.56192 -1.2873 -0.70452 -0.9344 -0.26583 -1.92 -0.29674 -2.8693 -0.08998 -0.53345 0.13369 -1.02665 0.39446 -1.4375 0.76005 -0.41085 0.36559 -0.72716 0.82514 -0.92194 1.33942 -0.41881 1.0115 -0.41881 2.1478 0 3.1593 0.4668 0.9845 1.29879 1.7483 2.31944 2.1295 0.9793 0.3819 2.0556 0.438 3.0693 0.16 0.8982 -0.2612 1.6632 -0.8546 2.1395 -1.6596 0.4789 -0.7747 0.6995 -1.6814 0.6299 -2.5894 -0.0061 -0.0449 -0.0211 -0.0881 -0.0441 -0.127 -0.0231 -0.039 -0.0536 -0.073 -0.0899 -0.1 -0.0363 -0.027 -0.0777 -0.0465 -0.1216 -0.0573 -0.044 -0.0108 -0.0897 -0.0127 -0.1344 -0.0057 -0.0457 0.0049 -0.0899 0.019 -0.1301 0.0415 -0.0401 0.0224 -0.0752 0.0528 -0.1033 0.0893 -0.028 0.0364 -0.0484 0.0782 -0.0598 0.1227 -0.0114 0.0446 -0.0137 0.091 -0.0067 0.1364 -0.0016 0.7166 -0.2252 1.4151 -0.6398 1.9996 -0.3854 0.5945 -0.9884 1.0144 -1.6796 1.1697 -0.8061 0.1738 -1.6466 0.0863 -2.3995 -0.2499 -0.7468 -0.2609 -1.36555 -0.7974 -1.72958 -1.4997 -0.29453 -0.7244 -0.29453 -1.5351 0 -2.2595 0.1115 -0.3727 0.31161 -0.7129 0.58321 -0.99148 0.27161 -0.27856 0.60667 -0.48722 0.97647 -0.60812Z" clip-rule="evenodd" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-arrange-letter-asc" viewBox="-2 -2 28 28" fill="none">
+ <path fill="var(--color-accent-light)" d="M11.9999 20.9053c5.1771 0 9.3739 -4.1969 9.3739 -9.374 0 -5.17702 -4.1968 -9.37389 -9.3739 -9.37389 -5.17706 0 -9.37392 4.19687 -9.37392 9.37389 0 5.1771 4.19686 9.374 9.37392 9.374Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M5.90674 4.49902V18.5599" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m3.09473 15.7477 2.81215 2.8121 2.81224 -2.8121" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M19.874 22.3113h-3.3746c-0.0837 0 -0.1658 -0.0224 -0.2378 -0.0649 -0.0722 -0.0424 -0.1316 -0.1035 -0.1721 -0.1766 -0.0405 -0.0732 -0.0608 -0.1559 -0.0586 -0.2395 0.0022 -0.0836 0.0268 -0.1652 0.0711 -0.2361l3.7908 -6.065c0.0441 -0.0706 0.0687 -0.1518 0.0711 -0.2352 0.0023 -0.0833 -0.0175 -0.1657 -0.0577 -0.2387 -0.0401 -0.0731 -0.099 -0.1342 -0.1705 -0.1769 -0.0717 -0.0427 -0.1532 -0.0656 -0.2366 -0.0663h-3.3746" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M16.2183 9.18788V3.56349c0 -0.4972 0.1975 -0.97405 0.5491 -1.32569 0.3517 -0.35154 0.8285 -0.54908 1.3257 -0.54908 0.4971 0 0.974 0.19754 1.3256 0.54908 0.3516 0.35164 0.5492 0.82849 0.5492 1.32569v5.62439" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M16.2183 5.4364h3.7496" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-arrange-letter-desc" viewBox="-2 -2 28 28" fill="none">
+ <path fill="var(--color-accent-light)" d="M11.9999 20.9053c5.1771 0 9.3739 -4.1969 9.3739 -9.374 0 -5.17702 -4.1968 -9.37389 -9.3739 -9.37389 -5.17706 0 -9.37392 4.19687 -9.37392 9.37389 0 5.1771 4.19686 9.374 9.37392 9.374Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M5.90674 4.49902V18.5599" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m3.09473 6.49902 2.81215 -2.8121 2.81224 2.8121" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M19.874 22.3113h-3.3746c-0.0837 0 -0.1658 -0.0224 -0.2378 -0.0649 -0.0722 -0.0424 -0.1316 -0.1035 -0.1721 -0.1766 -0.0405 -0.0732 -0.0608 -0.1559 -0.0586 -0.2395 0.0022 -0.0836 0.0268 -0.1652 0.0711 -0.2361l3.7908 -6.065c0.0441 -0.0706 0.0687 -0.1518 0.0711 -0.2352 0.0023 -0.0833 -0.0175 -0.1657 -0.0577 -0.2387 -0.0401 -0.0731 -0.099 -0.1342 -0.1705 -0.1769 -0.0717 -0.0427 -0.1532 -0.0656 -0.2366 -0.0663h-3.3746" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M16.2183 9.18788V3.56349c0 -0.4972 0.1975 -0.97405 0.5491 -1.32569 0.3517 -0.35154 0.8285 -0.54908 1.3257 -0.54908 0.4971 0 0.974 0.19754 1.3256 0.54908 0.3516 0.35164 0.5492 0.82849 0.5492 1.32569v5.62439" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M16.2183 5.4364h3.7496" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-arrange-number-asc" viewBox="-2 -2 28 28" fill="none">
+ <path fill="var(--color-accent-light)" d="M12.0002 20.9833c4.9615 0 8.9836 -4.0221 8.9836 -8.9836 0 -4.9615 -4.0221 -8.98365 -8.9836 -8.98365 -4.96154 0 -8.9836 4.02215 -8.9836 8.98365 0 4.9615 4.02206 8.9836 8.9836 8.9836Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M6.16064 5.26019V18.7356" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m3.46533 16.0405 2.69509 2.6951 2.6951 -2.6951" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M15.5933 8.85364h4.4918" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M17.8392 8.85545V2.11767c-0.0001 -0.08451 -0.0241 -0.16729 -0.0692 -0.23879 -0.045 -0.0715 -0.1093 -0.12888 -0.1855 -0.16546 -0.0762 -0.03657 -0.1612 -0.05096 -0.2452 -0.04143 -0.0839 0.00953 -0.1636 0.04263 -0.2296 0.09533l-1.5164 1.21101" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M17.39 19.6338c1.2403 0 2.2458 -1.0054 2.2458 -2.2458s-1.0055 -2.2459 -2.2458 -2.2459c-1.2404 0 -2.246 1.0055 -2.246 2.2459 0 1.2404 1.0056 2.2458 2.246 2.2458Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M19.636 17.3898v2.2459c0 0.7147 -0.284 1.4003 -0.7895 1.9057 -0.5054 0.5054 -1.1909 0.7894 -1.9056 0.7894h-0.4492" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-arrange-number-desc" viewBox="-2 -2 28 28" fill="none">
+ <path fill="var(--color-accent-light)" d="M12.0002 20.9833c4.9615 0 8.9836 -4.0221 8.9836 -8.9836 0 -4.9615 -4.0221 -8.98365 -8.9836 -8.98365 -4.96154 0 -8.9836 4.02215 -8.9836 8.98365 0 4.9615 4.02206 8.9836 8.9836 8.9836Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M6.16064 5.26019V18.7356" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m3.09473 6.49902 2.81215 -2.8121 2.81224 2.8121" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M15.5933 8.85364h4.4918" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M17.8392 8.85545V2.11767c-0.0001 -0.08451 -0.0241 -0.16729 -0.0692 -0.23879 -0.045 -0.0715 -0.1093 -0.12888 -0.1855 -0.16546 -0.0762 -0.03657 -0.1612 -0.05096 -0.2452 -0.04143 -0.0839 0.00953 -0.1636 0.04263 -0.2296 0.09533l-1.5164 1.21101" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M17.39 19.6338c1.2403 0 2.2458 -1.0054 2.2458 -2.2458s-1.0055 -2.2459 -2.2458 -2.2459c-1.2404 0 -2.246 1.0055 -2.246 2.2459 0 1.2404 1.0056 2.2458 2.246 2.2458Z" stroke-width="1"></path>
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M19.636 17.3898v2.2459c0 0.7147 -0.284 1.4003 -0.7895 1.9057 -0.5054 0.5054 -1.1909 0.7894 -1.9056 0.7894h-0.4492" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-camera-settings-flip" viewBox="-2 -2 28 28" fill="none">
+ <path fill="currentColor" fill-rule="evenodd" d="M22.1058 13.4701c-0.7103 -0.2001 -0.2501 1.0004 -2.1609 3.7917 -0.7602 1.1535 -1.7872 2.1068 -2.9941 2.779 -1.2069 0.6722 -2.558 1.0436 -3.9389 1.0826 -4.60204 0.3902 -9.00396 -2.0008 -9.83432 -6.6328 1.14049 0.6302 1.59069 0.7203 2.64115 1.2205 0.07919 0.0398 0.1703 0.049 0.25586 0.0259 0.08557 -0.0232 0.1596 -0.0771 0.20791 -0.1514 0.04831 -0.0743 0.06751 -0.1639 0.05393 -0.2515 -0.01358 -0.0876 -0.05899 -0.1671 -0.12753 -0.2233 -3.83167 -2.8912 -2.89126 -2.2009 -3.05133 -2.301 -1.1505 -0.7503 -2.15094 1.9008 -3.041328 3.0814C0.0416301 15.9693 0 16.0732 0 16.1813c0 0.108 0.0416301 0.212 0.116242 0.2901 0.450196 0.4002 0.790344 -0.2701 2.200958 -1.8208 0.88039 7.0031 9.3841 10.0044 15.4968 6.3028 2.2409 -1.4206 3.8817 -4.472 4.5119 -7.0031 0.0176 -0.0459 0.0258 -0.0949 0.0242 -0.1441 -0.0016 -0.0491 -0.013 -0.0975 -0.0335 -0.1422 -0.0205 -0.0447 -0.0497 -0.0848 -0.0859 -0.1181 -0.0361 -0.0333 -0.0786 -0.0591 -0.1249 -0.0758Z" clip-rule="evenodd" stroke-width="1"></path>
+ <path fill="currentColor" fill-rule="evenodd" d="M23.8566 7.50752c-0.4502 -0.39017 -0.8804 0.37016 -2.0709 1.74076 -0.9504 -7.00306 -9.4141 -9.854303 -15.47677 -6.20271 -2.25098 1.42062 -3.88169 4.47195 -4.51196 7.00303 -0.02462 0.0915 -0.01217 0.1891 0.03465 0.2715 0.04682 0.0824 0.12423 0.143 0.21546 0.1687 0.72031 0.2001 0.26011 -1.00042 2.17094 -3.79164 0.75857 -1.15276 1.78388 -2.10565 2.98903 -2.77788 1.20515 -0.67224 2.55461 -1.04401 3.93395 -1.0838 4.602 -0.39017 9.004 2.00087 9.8443 6.6529l-2.6211 -1.21053c-0.0796 -0.05306 -0.177 -0.07234 -0.2708 -0.05358 -0.0938 0.01877 -0.1764 0.07403 -0.2294 0.15363 -0.0531 0.0796 -0.0724 0.17702 -0.0536 0.27082 0.0188 0.09381 0.074 0.17633 0.1536 0.22939l2.301 1.78079c0.3002 0.2101 0.9404 1.0004 1.5107 0.5202 1.0004 -0.7903 1.4606 -2.15092 2.1309 -3.09133 0.0683 -0.08444 0.1012 -0.19203 0.0918 -0.3002 -0.0093 -0.10817 -0.0601 -0.20853 -0.1418 -0.28005Z" clip-rule="evenodd" stroke-width="1"></path>
+ </symbol>
+ <symbol id="icon-search-magnifier" viewBox="-2 -2 28 28" fill="none">
+ <path fill="currentColor" d="M16.1952 8.05092c-0.1789 -0.9786 -0.609 -1.89392 -1.2482 -2.65625 -0.1897 -0.22968 -0.3894 -0.4993 -0.6191 -0.72898 -0.1672 -0.17504 -0.3631 -0.32026 -0.5792 -0.42939 -0.0751 -0.03803 -0.1616 -0.04682 -0.2428 -0.02468s-0.1512 0.07364 -0.1966 0.14451h-0.1298c-0.9986 0.57918 -1.9972 1.19831 -2.9159 1.85738 -0.46933 0.32954 -0.93867 0.65907 -1.39802 0.99859L7.52747 8.34051c-0.68903 0.60914 -1.418 1.22827 -2.08706 1.89729 -0.30956 0.3096 -0.59915 0.6291 -0.87876 0.9986 -0.1547 -0.5346 -0.20221 -1.0946 -0.1398 -1.64765 0.28862 -1.67274 1.08327 -3.21674 2.27679 -4.42376 0.32935 -0.3211 0.71532 -0.57841 1.13839 -0.75893 0.59833 -0.21847 1.23041 -0.33002 1.86737 -0.32953 1.0089 -0.00223 2.0145 0.11509 2.9958 0.3495 0.069 0.00477 0.1376 -0.01451 0.194 -0.05456 0.0564 -0.04004 0.0972 -0.09839 0.1155 -0.16513 0.0184 -0.07804 0.0058 -0.16017 -0.0352 -0.22908 -0.041 -0.06892 -0.1071 -0.11925 -0.1845 -0.1404 -1.0143 -0.27385 -2.0559 -0.43461 -3.10557 -0.47932 -0.72843 -0.02631 -1.45565 0.07854 -2.14697 0.30956 -2.127 0.74895 -3.92447 3.79465 -4.20407 5.79183 -0.12584 1.06047 0.04348 2.13517 0.48931 3.10567 0.44242 0.955 1.11493 1.7854 1.95724 2.4165 0.47792 0.3465 1.01643 0.6005 1.58776 0.749 0.53703 0.1498 1.09034 0.2337 1.64767 0.2496 1.55563 0.031 3.08183 -0.4265 4.36383 -1.3081 1.2904 -0.8722 2.2229 -2.1805 2.6263 -3.6848 0.2708 -0.9541 0.3355 -1.95488 0.1897 -2.93588ZM4.8812 12.0453c-0.02753 -0.0548 -0.0509 -0.1115 -0.0699 -0.1698 0.37992 -0.3657 0.78356 -0.706 1.2083 -1.0185 0.72897 -0.5792 1.49788 -1.09849 2.23684 -1.62774 0.73896 -0.52926 1.25823 -0.99859 1.86736 -1.4879 0.6091 -0.48931 1.2083 -0.9986 1.8274 -1.52785 0.6192 -0.52925 1.0585 -0.83882 1.5978 -1.21828 0.0847 0.06414 0.1648 0.13422 0.2396 0.2097 0.1998 0.21969 0.3795 0.47933 0.5493 0.69902 0.4793 0.5818 0.8207 1.2646 0.9986 1.99718 -1.0586 0.64908 -2.137 1.23825 -3.1955 1.87735 -0.7845 0.46302 -1.5444 0.96632 -2.27683 1.50792 -1.15599 0.8863 -2.21685 1.8903 -3.16553 2.9957l-0.21969 -0.1298c-0.69787 -0.5438 -1.24738 -1.2547 -1.59775 -2.0671v-0.0399Zm10.2655 -1.3481c-0.3753 1.2769 -1.2023 2.3736 -2.3267 3.0856 -1.1145 0.7131 -2.4231 1.062 -3.74471 0.9986 -0.47267 -0.0061 -0.94256 -0.0732 -1.39803 -0.1997 -0.12982 0 -0.24965 -0.0899 -0.36948 -0.1298 0.44937 -0.3895 0.89873 -0.749 1.36807 -1.0985 0.46934 -0.3495 0.99859 -0.659 1.46795 -0.9986l1.4779 -0.9985c1.2915 -0.8855 2.5597 -1.79751 3.8046 -2.73618 0.0318 0.71661 -0.0629 1.43318 -0.2796 2.11698v-0.0399Z" stroke-width="1"></path>
+ <path fill="currentColor" d="M23.2453 20.5533c-0.04 -0.2181 -0.1001 -0.4321 -0.1797 -0.6391 -0.1361 -0.3547 -0.3173 -0.6903 -0.5393 -0.9986 -0.3034 -0.4388 -0.637 -0.8559 -0.9986 -1.2482 -0.5284 -0.5741 -1.0956 -1.1113 -1.6976 -1.6078 -0.8288 -0.679 -1.6976 -1.2981 -2.5763 -1.9971 0.2631 -0.5055 0.4803 -1.0335 0.649 -1.5778 0.248 -0.8172 0.4349 -1.6516 0.5592 -2.4965 0.1569 -0.81258 0.2305 -1.63902 0.2197 -2.46652 -0.0078 -0.57747 -0.1055 -1.1502 -0.2896 -1.6976 -0.1575 -0.4947 -0.3476 -0.97841 -0.5692 -1.44796 -0.1562 -0.33202 -0.347 -0.64665 -0.5691 -0.93868 -0.3781 -0.48797 -0.8217 -0.92146 -1.3182 -1.28818 -0.7357 -0.52062 -1.53 -0.95298 -2.3666 -1.288183 -0.5827 -0.254108 -1.1835 -0.464396 -1.7975 -0.629112 -0.6518 -0.1693231 -1.324 -0.246631 -1.9972 -0.22967613C8.94606 0.0473495 8.12871 0.212165 7.34773 0.491599c-0.76731 0.278516 -1.50629 0.629611 -2.20689 1.048521 -0.60025 0.33964 -1.16553 0.73768 -1.68762 1.18832C1.21637 4.69567 0.757023 8.98961 0.727065 9.45895 0.620124 10.7287 0.804559 12.0061 1.2663 13.1937c0.12146 0.3013 0.26153 0.5948 0.41941 0.8787 0.22968 0.3995 0.48931 0.7889 0.75893 1.1784 0.5038 0.7726 1.12352 1.463 1.83741 2.0471 0.49826 0.396 1.06292 0.7003 1.66765 0.8987 0.69046 0.2254 1.39862 0.3924 2.11701 0.4993 0.49142 0.0823 0.99015 0.1124 1.4879 0.0899 0.77439 -0.05 1.53939 -0.1977 2.27679 -0.4394 0.7156 -0.2507 1.4101 -0.5579 2.0771 -0.9187 0.1351 0.1597 0.2617 0.3264 0.3794 0.4993 0.4294 0.6591 0.769 1.3681 1.1684 1.9972 0.2809 0.4341 0.5877 0.851 0.9187 1.2482 0.3126 0.3904 0.646 0.7638 0.9986 1.1184 0.9711 0.9019 2.1935 1.4871 3.505 1.6777 0.262 0.0471 0.5307 0.0413 0.7904 -0.0169 0.2597 -0.0582 0.5052 -0.1678 0.7219 -0.3222 0.2168 -0.1544 0.4005 -0.3506 0.5404 -0.5771 0.1398 -0.2264 0.233 -0.4785 0.2741 -0.7415 0.0404 -0.1745 0.0704 -0.3512 0.0898 -0.5292 0.0097 -0.1763 0.0097 -0.353 0 -0.5293 0.0036 -0.234 -0.0131 -0.4679 -0.0499 -0.699Zm-1.1584 1.4679c-0.0509 0.2532 -0.1979 0.4768 -0.4102 0.6239 -0.2122 0.1471 -0.4732 0.2062 -0.7282 0.165 -1.0467 -0.1308 -2.0325 -0.5647 -2.836 -1.2482 -0.3522 -0.313 -0.6856 -0.6464 -0.9986 -0.9986 -0.3312 -0.341 -0.6381 -0.7047 -0.9187 -1.0885 -0.4393 -0.6191 -0.8388 -1.3081 -1.2981 -1.9372 -0.1219 -0.1597 -0.2519 -0.313 -0.3895 -0.4594l0.1298 -0.0899c0.2213 -0.1586 0.4315 -0.3321 0.6292 -0.5192 0.0617 -0.0665 0.096 -0.1539 0.096 -0.2447 0 -0.0908 -0.0343 -0.1782 -0.096 -0.2447 -0.0637 -0.0634 -0.1499 -0.099 -0.2397 -0.099 -0.0898 0 -0.176 0.0356 -0.2397 0.099 -0.1708 0.1582 -0.3545 0.3018 -0.5492 0.4294 -0.1917 0.1358 -0.3918 0.2592 -0.5991 0.3695 -0.6447 0.3275 -1.3121 0.6078 -1.9972 0.8388 -0.6937 0.2123 -1.4121 0.3332 -2.13702 0.3595 -0.55091 0.0138 -1.10132 -0.0432 -1.63769 -0.1697 -0.5569 -0.1063 -1.10451 -0.2566 -1.63769 -0.4494 -0.62749 -0.2261 -1.19946 -0.5835 -1.67763 -1.0485 -0.49431 -0.4831 -0.93003 -1.0228 -1.29817 -1.6077 -0.22967 -0.3595 -0.46934 -0.719 -0.67904 -1.1185 -0.13067 -0.2462 -0.24735 -0.4996 -0.34951 -0.7589 -0.38354 -1.05 -0.52354 -2.1734 -0.40942 -3.28536 0.45935 -5.29254 3.14556 -6.55076 3.91448 -6.99014 0.63297 -0.38101 1.30193 -0.69877 1.99718 -0.94867 0.6757 -0.25505 1.38606 -0.40655 2.10703 -0.44936 0.56148 -0.01552 1.12238 0.04495 1.66768 0.17975 0.5643 0.13703 1.1183 0.31389 1.6576 0.52925 0.6401 0.2469 1.2581 0.54755 1.8474 0.89873 0.5688 0.32061 1.076 0.7399 1.4979 1.23825 0.1894 0.23504 0.3534 0.48943 0.4893 0.75893 0.2209 0.42872 0.4111 0.87254 0.5692 1.32813 0.1632 0.46345 0.2607 0.94748 0.2896 1.43797 0.0241 0.77857 -0.026 1.55767 -0.1498 2.32672 -0.0854 0.6722 -0.2088 1.3389 -0.3695 1.9972 -0.1609 0.6599 -0.3954 1.2996 -0.699 1.9073 -0.1608 0.3485 -0.3513 0.6826 -0.5692 0.9986 -0.2143 0.3034 -0.4549 0.5874 -0.719 0.8488 -0.0288 0.0275 -0.052 0.0605 -0.0681 0.097 -0.0161 0.0364 -0.0249 0.0757 -0.0258 0.1156 -0.0019 0.0805 0.0283 0.1585 0.084 0.2168 0.0556 0.0582 0.1321 0.092 0.2126 0.0939 0.0805 0.0019 0.1585 -0.0283 0.2168 -0.0839 0.2935 -0.2844 0.5639 -0.5916 0.8088 -0.9187 0.1099 -0.1498 0.1997 -0.3096 0.2996 -0.4694 0.8088 0.6791 1.6177 1.3182 2.3866 1.9972 0.5434 0.4957 1.0506 1.0297 1.5179 1.5978 0.3133 0.3747 0.6034 0.7682 0.8688 1.1783 0.1584 0.2534 0.2858 0.525 0.3794 0.8088 0.0505 0.1638 0.0905 0.3305 0.1198 0.4993 0.0099 0.1597 0.0099 0.3197 0 0.4794l-0.0599 0.8088Z" stroke-width="1"></path>
+ </symbol>
+</svg>
+<div class="flex flex-row ar-lt-0.8:flex-col text-base h-full">
+ <div class="relative flex shrink-0 ar-gt-0.8:min-w-1/10 ar-gt-0.8:max-w-1/4 ar-gt-0.8:w-fit ar-lt-0.8:w-full ar-lt-0.8:max-h-[30%]">
+ <div class="absolute w-full h-full inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div>
+ <form hx-get="/api/v1/blog-search" hx-vals='{"lang": "{{ .Lang }}"}' hx-target=".blog-cards" hx-swap="innerHTML"
+ class="tags-list relative flex flex-col w-full bg-paper bg-background-light">
+ <div class="flex flex-col overflow-y-auto">
+ <fieldset>
+ <legend class="font-bold w-full text-center">{{ .L.BlogSearch.OrderByHeader }}</legend>
+ <div class="flex flex-col ar-lt-0.8:grid grid-cols-3 grid-rows-2 grid-flow-col">
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortTitleAsc" name="sort" value="titleAsc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "titleAsc" }}checked{{ end }}>
+ {{ .L.BlogSearch.TitleOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-letter-asc"/></svg>
+ </label>
+ </div>
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortTitleDesc" name="sort" value="titleDesc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "titleDesc" }}checked{{ end }}>
+ {{ .L.BlogSearch.TitleOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-letter-desc"/></svg>
+ </label>
+ </div>
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortActionDateAsc" name="sort" value="actionDateAsc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "actionDateAsc" }}checked{{ end }}>
+ {{ .L.BlogSearch.ActionDateOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-asc"/></svg>
+ </label>
+ </div>
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortActionDateDesc" name="sort" value="actionDateDesc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "actionDateDesc" }}checked{{ end }}>
+ {{ .L.BlogSearch.ActionDateOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-desc"/></svg>
+ </label>
+ </div>
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortPublicationDateAsc" name="sort" value="publicationDateAsc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "publicationDateAsc" }}checked{{ end }}>
+ {{ .L.BlogSearch.PublicationDateOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-asc"/></svg>
+ </label>
+ </div>
+ <div>
+ <label class="flex justify-start gap-1 items-center">
+ <input type="radio" id="sortPublicationDateDesc" name="sort" value="publicationDateDesc" class="bg-accent-light border-transparent text-accent-deep focus:border-transparent focus:bg-accent-light focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" {{ if eq .QuerySort "publicationDateDesc" }}checked{{ end }}>
+ {{ .L.BlogSearch.PublicationDateOrdered }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-desc"/></svg>
+ </label>
+ </div>
</div>
- {{- range .Tags }}
- <div class="m-[0.4vmin]">
- <label><input type="checkbox" id="tag{{ .Name }}Checkbox" name="tags[]" value="{{ .Name }}" onclick="contextAll();" {{ if contains $.QueryTags .Name }}checked{{ end }}> {{ .Name }} <span class="text-secondary italic">{{ .Count }}</span></label>
+ </fieldset>
+ <fieldset class="mt-1">
+ <legend class="font-bold w-full text-center">{{ .L.BlogSearch.TagsHeader }}</legend>
+ <div class="flex flex-col ar-lt-0.8:grid grid-cols-3 xs:grid-cols-4 sm:grid-cols-5 grid-flow-row-dense">
+ <div class="m-1">
+ <label class="font-bold"><input type="checkbox" id="tagsAllCheckbox" onclick="selectAll();" class="bg-accent-light rounded border-transparent text-accent-deep focus:border-transparent focus:bg-background-dark focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep"> {{ .L.BlogSearch.ChooseAllTags }}</label>
+ </div>
+ {{- range .Tags }}
+ <div class="m-1">
+ <label><input type="checkbox" id="tag{{ .Name }}Checkbox" name="tags[]" value="{{ .Name }}" class="bg-accent-light rounded border-transparent text-accent-deep focus:border-transparent focus:bg-background-dark focus:ring-1 focus:ring-offset-2 focus:ring-accent-deep" onclick="contextAll();" {{ if contains $.QueryTags .Name }}checked{{ end }}> {{ .Name }} <span class="text-secondary italic">{{ .Count }}</span></label>
+ </div>
+ {{- end }}
</div>
- {{- end }}
- </div>
- </fieldset>
- <fieldset class="mt-[0.8vmin]">
- <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.OrderByHeader }}</legend>
- <div class="flex flex-col ar-lt-0.8:grid grid-cols-3 grid-rows-2 grid-flow-col">
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortTitleAsc" name="sort" value="titleAsc" {{ if eq .QuerySort "titleAsc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-a-z"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortTitleDesc" name="sort" value="titleDesc" {{ if eq .QuerySort "titleDesc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-z-a"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortActionDateAsc" name="sort" value="actionDateAsc" {{ if eq .QuerySort "actionDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortActionDateDesc" name="sort" value="actionDateDesc" {{ if eq .QuerySort "actionDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortPublicationDateAsc" name="sort" value="publicationDateAsc" {{ if eq .QuerySort "publicationDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortPublicationDateDesc" name="sort" value="publicationDateDesc" {{ if eq .QuerySort "publicationDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
- </div>
- </div>
- </fieldset>
- </div>
- <hr class="border-t-[0.2vmax] border-dotted border-main-dark my-[0.4vmin]">
- <div class="flex flex-row grow bg-background-light my-[2vmin] p-[0.4vmin] rounded-[0.4vmin] justify-items-center">
- <i onclick="defaultSearchParams(); cleanHrefParams();" class="fas fa-rotate-left flex-1 text-center text-[1.5vmax] hover:bg-background-dark cursor-pointer transition-colors duration-300"></i>
- <div class="w-[0.5vmin] bg-background-dark grow-0"></div>
- <button class="flex-1" type="submit">
- <i onclick="setHrefParams();" class="fas fa-magnifying-glass text-center text-[1.5vmax] hover:bg-background-dark cursor-pointer transition-colors duration-300"></i>
- </button>
- </div>
- </form>
+ </fieldset>
+ </div>
+ <hr class="border-t-2 border-dotted border-main-hard my-0.5">
+ <div class="flex flex-row bg-paper bg-background-dark p-0.5 rounded-1 h-12">
+ <button type="button" onclick="defaultSearchParams(); cleanHrefParams();" class="flex flex-1 justify-center text-main-hard bg-paper bg-accent-light cursor-pointer hover:bg-accent-deep active:text-background-dark transition-colors duration-500">
+ <svg viewBox="0 0 24 24"><use href="#icon-camera-settings-flip"/></svg>
+ </button>
+ <div class="w-1 bg-paper bg-background-light grow-0"></div>
+ <button type="submit" onclick="setHrefParams();" class="flex flex-1 justify-center text-main-hard bg-paper bg-accent-light cursor-pointer hover:bg-accent-deep active:text-background-dark transition-colors duration-500">
+ <svg viewBox="0 0 24 24"><use href="#icon-search-magnifier"/></svg>
+ </button>
+ </div>
+ </form>
+ </div>
- <div class="w-[0.5vh] border-r-[0.3vh] border-dotted border-main-dark bg-background-dark"></div>
+ <div class="w-[0.5dvh] border-r-2 border-dotted border-main-hard bg-paper bg-background-dark"></div>
- <div hx-get="/api/v1/blog-search" hx-vals='js:{lang: "{{ .Lang }}", tz: clientTimeZone}' hx-target="this" hx-swap="innerHTML" hx-trigger="load" hx-include=".tags-list"
- class="blog-cards grow flex flex-col overflow-y-auto bg-background-light inset-shadow p-[2.4vmin]">
- Loading...
+ <div class="relative flex grow h-full">
+ <div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div>
+ <div hx-get="/api/v1/blog-search" hx-vals='js:{lang: "{{ .Lang }}", tz: clientTimeZone}' hx-target="this" hx-swap="innerHTML" hx-trigger="load" hx-include=".tags-list"
+ class="blog-cards relative grow flex flex-col overflow-y-auto bg-paper bg-background-light pr-2">
+ Loading...
+ </div>
</div>
+
</div>
<script>
diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html
index e68fcab..8978eb8 100644
--- a/views/pages/blog-page.html
+++ b/views/pages/blog-page.html
@@ -1,33 +1,29 @@
-{{ define "top-embeds" }}
-<script>
- var galleryMap = new Map();
- var map;
-
- window.addEventListener('popout', (e) => {
- map.remove();
- galleryMap.forEach((_, g, m) => {
- g.destroy();
- });
- galleryMap.clear();
- }, {once: true});
-</script>
-{{ end }}
-
{{ define "body" }}
-<div class="bg-background-light flex flex-col inset-shadow p-[2.4vmin] overflow-y-auto">
+<div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div>
+<article class="relative bg-paper bg-background-light flex flex-col px-8 py-4 overflow-y-auto">
+ <h1 class="max-xs:block [@media(max-height:32rem)]:block hidden font-gentium text-2xl font-bold italic text-main-hard tracking-[.0125rem] mb-1">{{ .Title }}</h1>
+ <p class="block grow text-lg font-gentium text-secondary">
+ <b>{{ .L.Metadata.Published }}</b>:
+ <time datetime="{{ .PublishedDate }}" hx-get="/api/v1/tz" hx-vals='js:{timestamp: "{{ .PublishedDate }}", tz: clientTimeZone}' hx-target="this" hx-swap="innerHTML" hx-trigger="load">
+ {{ .PublishedDate }}
+ </time>
+ </p>
+ <p class="block grow text-lg font-gentium text-secondary"><b>{{ .L.Metadata.Action }}</b>: {{ .ActionDate }}</p>
+ <p class="block grow text-md font-gentium font-thin text-main-hard">{{ .ShortDescription }}</p>
+ <hr class="block border-t-2 border-dotted border-main-hard mt-1 mb-2 w-full ml-auto mr-auto">
{{ .ParsedMarkdown }}
{{- if .MapLocationX }}
- <hr class="border-t-4 border-dotted border-main-dark mt-[0.8vmin] mb-[0.8vmin] w-[80%] ml-auto mr-auto">
- <div id="map-container" class="relative p-[0.8vmin] flex-none ml-auto mr-auto w-[60%] ar-lt-0.8:w-[80%] h-[40vh] ar-lt-0.8:h-[30vh]"></div>
- <hr class="border-t-4 border-dotted border-main-dark mt-[0.8vmin] mb-[0.8vmin] w-[80%] ml-auto mr-auto">
+ <hr class="border-t-3 border-dotted border-main-hard mt-1 mb-2 w-[80%] ml-auto mr-auto">
+ <div id="map-container" class="relative p-1 flex-none ml-auto mr-auto w-[60%] ar-lt-0.8:w-[80%] h-[40dvh] ar-lt-0.8:h-[30dvh]"></div>
+ <hr class="border-t-3 border-dotted border-main-hard mt-1 mb-2 w-[80%] ml-auto mr-auto">
<script>
function initLocationMap(id, x, y, relativeErrorMeters = 0) {
map = L.map(id).setView([x, y], 8);
- L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 18,
- attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
+ L.tileLayer('https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', {
+ maxZoom: 20,
+ attribution: '<a href="https://github.com/cyclosm/cyclosm-cartocss-style/releases" title="CyclOSM - Open Bicycle render">CyclOSM</a> | Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
if (relativeErrorMeters != 0) {
@@ -46,48 +42,27 @@
.openPopup();
}
- document.addEventListener('htmx:afterRequest', (e) => {
- if (e.detail.target.id == 'general-page-body') {
- initLocationMap(
- 'map-container',
- {{ .MapLocationX }},
- {{ .MapLocationY }},
- {{ .MapLocationAreaMeters }}
- );
- }
- }, {once: true});
+ if (map) {
+ map.remove();
+ map = null;
+ }
+
+ setTimeout(() => initLocationMap(
+ 'map-container',
+ {{ .MapLocationX }},
+ {{ .MapLocationY }},
+ {{ .MapLocationAreaMeters }}
+ ), 1000);
+
+ var lightbox = GLightbox({
+ selector: '.glightbox',
+ moreLength: 0
+ });
</script>
{{- end }}
-</div>
+</article>
{{ end }}
-{{ define "footer" }}
+{{ define "header" }}
<div hx-get="/api/v1/like" hx-target="this" hx-swap="outerHTML" hx-trigger="load"></div>
{{ end }}
-
-{{ define "bottom-embeds" }}
-<script>
- let galleryResizeTimeout;
-
- function resizeCb() {
- clearTimeout(galleryResizeTimeout);
- galleryResizeTimeout = setTimeout(() => {
- if (map !== undefined) {
- map.invalidateSize();
- }
- var oldGalleryMap = new Map(galleryMap);
- oldGalleryMap.forEach((createFunc, g, map) => {
- galleryMap.delete(g);
- g.destroy();
- createFunc();
- });
- }, 300);
- }
-
- window.addEventListener('resize', resizeCb);
-
- document.addEventListener('popout', (e) => {
- window.removeEventListener('resize', resizeCb, {once: true});
- });
-</script>
-{{ end }} \ No newline at end of file
diff --git a/views/pages/global-map.html b/views/pages/global-map.html
index 569166f..ce9d5b1 100644
--- a/views/pages/global-map.html
+++ b/views/pages/global-map.html
@@ -1,267 +1,428 @@
-<!DOCTYPE html>
+<!doctype html>
<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>SAYA TODAY // {{ .L.GlobalMap.Header }}</title>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
- <link rel="preconnect" href="https://fonts.googleapis.com">
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
- <link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800&family=Patua+One&display=swap" rel="stylesheet">
- {{ block "header" . }}{{ end }}
- <link href="/output.css" rel="stylesheet">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/MarkerCluster.css">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css">
-</head>
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="description" content="{{ .L.GlobalMap.Description }}" />
+ <meta property="og:title" content="{{ .L.GlobalMap.Header }}" />
+ <meta
+ property="og:description"
+ content="{{ .L.GlobalMap.Description }}"
+ />
+ <meta
+ property="og:url"
+ content="{{ .CanonicalEndpoint }}/{{ .Lang }}/map"
+ />
+ <meta property="og:type" content="site" />
+ <title>{{ .L.GlobalMap.Header }} // SAYA.UZ</title>
+ <link rel="canonical" href="{{ .CanonicalEndpoint }}/{{ .Lang }}/map" />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/fonts/fonts.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/font-awesome/7.2.0/css/fontawesome.min.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/font-awesome/7.2.0/css/brands.min.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/font-awesome/7.2.0/css/solid.min.css"
+ />
+ {{ block "header" . }}{{ end }}
+ <link rel="stylesheet" href="/output.css" />
+ <link
+ rel="icon"
+ href="/favicon-light.svg"
+ type="image/svg+xml"
+ media="(prefers-color-scheme: light)"
+ />
+ <link
+ rel="icon"
+ href="/favicon-dark.svg"
+ type="image/svg+xml"
+ media="(prefers-color-scheme: dark)"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/leaflet/1.9.4/leaflet.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorageBaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"
+ />
+ </head>
-<body data-theme="ram" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-row ar-lt-0.8:flex-col">
-
- <script>
- function switchTheme(theme) {
- if (theme == "" || typeof theme == "undefined") {
- const currentTheme = document.body.getAttribute('data-theme');
- switch (currentTheme) {
- case "olive": theme = "lettuce"; break;
- case "lettuce": theme = "night"; break;
- case "night": theme = "ram"; break;
- case "ram": theme = "olive"; break;
+ <body
+ data-theme="ram"
+ class="font-m-plus text-main-hard overflow-hidden bg-interlocked-hexagons h-dvh"
+ >
+ <script>
+ function switchTheme(theme) {
+ if (theme == "" || typeof theme == "undefined") {
+ const currentTheme =
+ document.body.getAttribute("data-theme");
+ switch (currentTheme) {
+ case "olive":
+ theme = "lettuce";
+ break;
+ case "lettuce":
+ theme = "night";
+ break;
+ case "night":
+ theme = "ram";
+ break;
+ case "ram":
+ theme = "lilac";
+ break;
+ case "lilac":
+ theme = "olive";
+ break;
+ }
}
+ localStorage.setItem("theme", theme);
+ document.body.setAttribute("data-theme", theme);
}
- localStorage.setItem('theme', theme);
- document.body.setAttribute('data-theme', theme);
- }
- const savedTheme = localStorage.getItem('theme') || 'ram';
- switchTheme(savedTheme);
- </script>
+ const savedTheme = localStorage.getItem("theme") || "lilac";
+ switchTheme(savedTheme);
+ </script>
- <script>
- const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
- </script>
+ <script>
+ const clientTimeZone =
+ Intl.DateTimeFormat().resolvedOptions().timeZone;
- <div id="sidebar" class="bg-sidebar flex sticky flex-col ar-gt-0.8:items-center shadow-2xl z-20 w-[5vw] ar-lt-0.8:w-screen h-screen ar-lt-0.8:h-[8vh]">
- <div class="logo-custom ar-lt-0.8:hidden text-sidebar font-patua font-extrabold text-center relative z-20">
- saya.today
- </div>
- <div class="text-[3vw] ar-lt-0.8:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-0.8:flex-row gap-0 relative z-20">
- <i onclick="location.href='/';" class="fas fa-home w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/blog';" class="fas fa-search w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- </div>
- <div class="theme-wheel" id="theme-wheel">
- <div class="theme-icon" data-theme="olive"></div>
- <div class="theme-icon" data-theme="lettuce"></div>
- <div class="theme-icon" data-theme="night"></div>
- <div class="theme-icon" data-theme="ram"></div>
+ function convertRemToPixels(rem) {
+ return (
+ rem *
+ parseFloat(
+ getComputedStyle(document.documentElement).fontSize,
+ )
+ );
+ }
+ </script>
+
+ <div
+ id="sidebar"
+ class="bg-sidebar block fixed shadow-[0_0_0.4rem_black] z-1001 w-fit h-auto"
+ >
+ <div class="text-[3rem] flex flex-col gap-0 relative z-1001">
+ <a
+ href="./"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ class="fas fa-circle-left flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </a>
+ <a
+ href="/{{ .Lang }}"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ class="fas fa-home flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </a>
+ <a
+ href="/{{ .Lang }}/blog"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ class="fas fa-search flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </a>
+ <a
+ href="/{{ .Lang }}/map"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ class="fas fa-map flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </a>
+ <div
+ id="toolbar-theme-button"
+ onclick="toggleThemeWheel()"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ id="toolbar-theme-button-content"
+ class="fas fa-swatchbook flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </div>
+ <a
+ href="/{{ .Lang }}/user"
+ id="sidebar-user-button"
+ class="themed-button themed-button-sidebar w-fit h-fit"
+ draggable="false"
+ >
+ <i
+ onclick="return changeUrl('/{{ .Lang }}/user');"
+ class="fas fa-user flex faw-18 h-18 content-center text-center text-sidebar"
+ ></i>
+ </a>
+ </div>
+ <div class="theme-wheel" id="theme-wheel">
+ <div class="theme-icon" data-theme="olive"></div>
+ <div class="theme-icon" data-theme="lettuce"></div>
+ <div class="theme-icon" data-theme="night"></div>
+ <div class="theme-icon" data-theme="ram"></div>
+ <div class="theme-icon" data-theme="lilac"></div>
+ <div class="theme-pin"></div>
+ </div>
</div>
- </div>
- <div id="map-container" class="bg-background-dark flex z-10 w-[95vw] ar-lt-0.8:w-screen h-screen ar-lt-0.8:h-[92vh]"></div>
+ <div
+ id="map-container"
+ class="bg-paper bg-background-dark flex z-10 w-full h-full"
+ ></div>
- <script src="https://f003.backblazeb2.com/file/sayana-static/libs/htmx/2.0.6/htmx.min.js"></script>
- <script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.js"></script>
- <script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
+ <script src="{{ .StaticStorageBaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script>
+ <script src="{{ .StaticStorageBaseUrl }}/libs/leaflet/1.9.4/leaflet.js"></script>
+ <script src="{{ .StaticStorageBaseUrl }}/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
- <script>
- const themeWheel = document.getElementById('theme-wheel');
- const themeButton = document.getElementById('theme-button');
- const themeIcons = document.querySelectorAll('.theme-icon');
+ <script>
+ const themeWheel = document.getElementById("theme-wheel");
+ const themeButton = document.getElementById("toolbar-theme-button");
+ const themeIcons = document.querySelectorAll(".theme-icon");
+ const themeWheelRadius = convertRemToPixels(6);
+ const THUMB_BASE = "{{ .ThumbnailBaseUrl }}";
- themeIcons.forEach(icon => {
- if (icon.getAttribute('data-theme') == savedTheme) {
- icon.classList.add('active');
- }
- });
+ themeIcons.forEach((icon) => {
+ if (icon.getAttribute("data-theme") == savedTheme) {
+ icon.classList.add("active");
+ }
+ });
- function calculateVmax(percent) {
- const viewportWidth = window.innerWidth;
- const viewportHeight = window.innerHeight;
+ function calculateVmax(percent) {
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
- const largerDimension = Math.max(viewportWidth, viewportHeight);
+ const largerDimension = Math.max(viewportWidth, viewportHeight);
- const vmaxValue = (largerDimension / 100) * percent;
+ const vmaxValue = (largerDimension / 100) * percent;
- return vmaxValue;
- }
+ return vmaxValue;
+ }
- function positionThemeIcons() {
- const icons = themeWheel.querySelectorAll('.theme-icon');
- const iconCount = icons.length;
- const vmax = calculateVmax(1);
- const wheelRadius = 7.5*vmax; // Radius of the wheel
- const iconRadius = 4*vmax; // Distance from center to place icons
- const iconSize = 3*vmax; // Half of icon size for centering
+ function positionThemeIcons() {
+ const sliceAngle = 360 / themeIcons.length;
- icons.forEach((icon, index) => {
- const angle = (index * 360 / iconCount) - 90;
- const angleRad = (angle * Math.PI) / 180;
+ themeIcons.forEach((icon, index) => {
+ const startAngle = index * sliceAngle;
+ const endAngle = (index + 1) * sliceAngle;
- const x = Math.cos(angleRad) * iconRadius + wheelRadius - iconSize;
- const y = Math.sin(angleRad) * iconRadius + wheelRadius - iconSize;
+ const clipPath = createSliceClipPath(
+ startAngle,
+ endAngle,
+ themeWheelRadius,
+ );
+ icon.style.clipPath = clipPath;
+ });
+ }
- icon.style.left = x + 'px';
- icon.style.top = y + 'px';
- });
- }
+ function createSliceClipPath(startAngle, endAngle, radius) {
+ const centerX = radius;
+ const centerY = radius;
- function positionThemeWheel() {
- const buttonRect = themeButton.getBoundingClientRect();
- const buttonCenterX = buttonRect.left + buttonRect.width / 2;
- const buttonCenterY = buttonRect.top + buttonRect.height / 2;
+ let points = `${centerX}px ${centerY}px`;
- const wheelRadius = calculateVmax(7.5);
- const margin = calculateVmax(1);
+ const segments = Math.max(
+ 2,
+ Math.ceil(Math.abs(endAngle - startAngle) / 5),
+ );
+ const angleStep = (endAngle - startAngle) / segments;
- let wheelX = buttonCenterX - wheelRadius;
- let wheelY = buttonCenterY - wheelRadius;
+ for (let i = 0; i <= segments; i++) {
+ const angle =
+ ((startAngle + angleStep * i - 90) * Math.PI) / 180;
+ const x = centerX + Math.cos(angle) * radius;
+ const y = centerY + Math.sin(angle) * radius;
+ points += `, ${x}px ${y}px`;
+ }
- const viewportWidth = window.innerWidth;
- const viewportHeight = window.innerHeight;
+ points += `, ${centerX}px ${centerY}px`;
- if (wheelX < margin) {
- wheelX = margin;
- } else if (wheelX + (wheelRadius * 2) > viewportWidth - margin) {
- wheelX = viewportWidth - (wheelRadius * 2) - margin;
+ return `polygon(${points})`;
}
- if (wheelY < margin) {
- wheelY = margin;
- } else if (wheelY + (wheelRadius * 2) > viewportHeight - margin) {
- wheelY = viewportHeight - (wheelRadius * 2) - margin;
- }
+ function positionThemeWheel() {
+ const buttonRect = themeButton.getBoundingClientRect();
+ const buttonCenterX = buttonRect.left + buttonRect.width / 2;
+ const buttonCenterY = buttonRect.top + buttonRect.height / 2;
- themeWheel.style.left = wheelX + 'px';
- themeWheel.style.top = wheelY + 'px';
- }
+ const margin = 0;
- function hideThemeWheel() {
- themeWheel.classList.remove('active');
- }
+ let wheelX = buttonCenterX - themeWheelRadius;
+ let wheelY = buttonCenterY - themeWheelRadius;
- function showThemeWheel() {
- positionThemeWheel();
- positionThemeIcons();
- themeWheel.classList.add('active');
- }
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
- function toggleThemeWheel() {
- if (themeWheel.classList.contains('active')) {
- hideThemeWheel();
- } else {
- showThemeWheel();
- }
- }
+ if (wheelX < margin) {
+ wheelX = margin;
+ } else if (
+ wheelX + themeWheelRadius * 2 >
+ viewportWidth - margin
+ ) {
+ wheelX = viewportWidth - themeWheelRadius * 2 - margin;
+ }
- themeIcons.forEach(icon => {
- icon.addEventListener('click', (e) => {
- e.stopPropagation();
- const theme = icon.getAttribute('data-theme');
- switchTheme(theme);
- themeIcons.forEach(icon => {
- icon.classList.remove('active');
- })
- icon.classList.add('active');
- });
- });
+ if (wheelY < margin) {
+ wheelY = margin;
+ } else if (
+ wheelY + themeWheelRadius * 2 >
+ viewportHeight - margin
+ ) {
+ wheelY = viewportHeight - themeWheelRadius * 2 - margin;
+ }
- themeWheel.addEventListener('mouseleave', hideThemeWheel);
+ themeWheel.style.left = wheelX + "px";
+ themeWheel.style.top = wheelY + "px";
+ }
- document.addEventListener('click', (e) => {
- if (!themeWheel.contains(e.target) && e.target !== themeButton) {
- hideThemeWheel();
+ function hideThemeWheel() {
+ themeWheel.classList.remove("active");
}
- });
- </script>
- <script>
- var map;
- var markers = L.markerClusterGroup();
+ function showThemeWheel() {
+ positionThemeWheel();
+ positionThemeIcons();
+ themeWheel.classList.add("active");
+ }
- function createCustomIcon(color, borderColor = "var(--main-light-color)") {
- const svgIcon = `
- <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
- <path d="M12 1C7.5 1 4 4.5 4 9c0 6.5 8 14 8 14s8-7.5 8-14c0-4.5-3.5-8-8-8zm0 11c-1.5 0-3-1.5-3-3s1.5-3 3-3 3 1.5 3 3-1.5 3-3 3z"
- fill="${color}"
- stroke="${borderColor}"
- stroke-width="1"
- stroke-linejoin="round"/>
- </svg>
- `;
+ function toggleThemeWheel() {
+ if (themeWheel.classList.contains("active")) {
+ hideThemeWheel();
+ } else {
+ showThemeWheel();
+ }
+ }
- return L.divIcon({
- html: svgIcon,
- className: 'custom-svg-marker',
- iconSize: [32, 32],
- iconAnchor: [16, 32],
- popupAnchor: [0, -32]
+ themeIcons.forEach((icon) => {
+ icon.addEventListener("click", (e) => {
+ e.stopPropagation();
+ const theme = icon.getAttribute("data-theme");
+ switchTheme(theme);
+ themeIcons.forEach((icon) => {
+ icon.classList.remove("active");
+ });
+ icon.classList.add("active");
+ });
});
- }
- function initLocationMap() {
- map = L.map('map-container').setView([{{ .MapLocationLat }}, {{ .MapLocationLong }}], 4);
+ themeWheel.addEventListener("mouseleave", hideThemeWheel);
- L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 18,
- attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
- }).addTo(map);
+ document.addEventListener("click", (e) => {
+ if (
+ !themeWheel.contains(e.target) &&
+ e.target !== themeButton &&
+ !e.target.classList.contains("toolbar-theme-button-content")
+ ) {
+ hideThemeWheel();
+ }
+ });
+ </script>
- map.addLayer(markers);
- }
+ <script>
+ var map;
+ var markers = L.markerClusterGroup();
- function stringToColor(str) {
- let hash = 0;
- for (let i = 0; i < str.length; i++) {
- hash = str.charCodeAt(i) + ((hash << 5) - hash);
- }
+ function createCustomIcon(color, borderColor = "var(--color-main-soft)") {
+ const svgIcon = `
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M12 1C7.5 1 4 4.5 4 9c0 6.5 8 14 8 14s8-7.5 8-14c0-4.5-3.5-8-8-8zm0 11c-1.5 0-3-1.5-3-3s1.5-3 3-3 3 1.5 3 3-1.5 3-3 3z"
+ fill="${color}"
+ stroke="${borderColor}"
+ stroke-width="1"
+ stroke-linejoin="round"/>
+ </svg>
+ `;
- let color = '#';
- for (let i = 0; i < 3; i++) {
- const value = (hash >> (i * 8)) & 0xFF;
- color += ('00' + value.toString(16)).substr(-2);
+ return L.divIcon({
+ html: svgIcon,
+ className: 'custom-svg-marker',
+ iconSize: [32, 32],
+ iconAnchor: [16, 32],
+ popupAnchor: [0, -32]
+ });
}
- return color;
- }
+ function initLocationMap() {
+ map = L.map('map-container').setView([{{ .MapLocationLat }}, {{ .MapLocationLong }}], 4);
- function mapAddMarker(x, y, relativeErrorMeters = 0, title = "", link = "", thumbnail = "") {
- const titleColor = stringToColor(title);
+ L.tileLayer('https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', {
+ maxZoom: 20,
+ attribution: '<a href="https://github.com/cyclosm/cyclosm-cartocss-style/releases" title="CyclOSM - Open Bicycle render">CyclOSM</a> | Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
+ zoomControl: false
+ }).addTo(map);
- if (relativeErrorMeters != 0) {
- var circle = L.circle([x, y], {
- color: titleColor,
- fillColor: titleColor,
- fillOpacity: 0.15,
- radius: relativeErrorMeters
+ L.control.zoom({
+ position: 'topright'
}).addTo(map);
+
+ map.addLayer(markers);
}
- var marker = L.marker([x, y], {
- icon: createCustomIcon(titleColor),
- title: title,
- }).bindPopup(`
- <div class="flex flex-row justify-center justify-items-center">
- <img onclick="location.href='${link}';" class="cursor-pointer object-cover rounded-[10%] select-none w-[3vmax] h-[3vmax] mr-[0.5vmax]" src="https://f003.backblazeb2.com/file/sayana-photos/webp-320p/${thumbnail}.webp">
- <span><b><a href="${link}">${title}</a></b><br><a href="https://www.openstreetmap.org/#map=13/${x}/${y}">${x}, ${y}</a></span>
- </div>`);
+ function markerToHsl(str, newCoef) {
+ let hash = 0;
+ for (let i = 0; i < str.length / 2; i++) {
+ hash = str.charCodeAt(i) + ((hash << 5) - hash);
+ hash = str.charCodeAt(str.length - i - 1) + ((hash << 5) - hash);
+ hash %= 360;
+ }
- markers.addLayer(marker);
- }
+ return [hash, (20 + newCoef * 80).toFixed(0), (20 + newCoef * 75).toFixed(0)];
+ }
+
+ function mapAddMarker(x, y, relativeErrorMeters = 0, title = "", link = "", thumbnail = "", newCoef = 1) {
+ const [h, s, l] = markerToHsl(title, newCoef);
+ const color = `hsl(${h} ${s}% ${l}%)`;
+
+ if (relativeErrorMeters != 0) {
+ var circle = L.circle([x, y], {
+ color: color,
+ fillColor: color,
+ fillOpacity: 0.15,
+ radius: relativeErrorMeters
+ }).addTo(map);
+ }
- document.addEventListener('DOMContentLoaded', () => {
- initLocationMap();
- {{- range .MapMarkers }}
- mapAddMarker({{ .Lat }}, {{ .Long }}, {{ .AccuracyMeters }}, {{ .Title }}, {{ .PageLink }}, {{ .Thumbnail }});
- {{- end }}
- });
+ var marker = L.marker([x, y], {
+ icon: createCustomIcon(color),
+ title: title,
+ }).bindPopup(`
+ <div class="flex flex-row justify-center justify-items-center">
+ <img onclick="location.href='${link}';" class="cursor-pointer object-cover rounded-[10%] select-none w-12 h-12 mr-1" src="${THUMB_BASE.replace('%s', thumbnail)}">
+ <span><b><a href="${link}">${title}</a></b><br><a href="https://www.openstreetmap.org/#map=13/${x}/${y}">${x}, ${y}</a></span>
+ </div>`);
- window.addEventListener('resize', function() {
- setTimeout(() => {
- map.invalidateSize();
- }, 100);
- });
- </script>
+ markers.addLayer(marker);
+ }
+
+ document.addEventListener('DOMContentLoaded', () => {
+ initLocationMap();
+ {{- range .MapMarkers }}
+ mapAddMarker({{ .Lat }}, {{ .Long }}, {{ .AccuracyMeters }}, {{ .Title }}, {{ .PageLink }}, {{ .Thumbnail }}, {{ fdiv .Index (len $.MapMarkers) }});
+ {{- end }}
+ });
-</body>
+ window.addEventListener('resize', function() {
+ setTimeout(() => {
+ map.invalidateSize();
+ }, 100);
+ });
+ </script>
+ </body>
</html>
diff --git a/views/pages/home-page.html b/views/pages/home-page.html
new file mode 100644
index 0000000..c966fc2
--- /dev/null
+++ b/views/pages/home-page.html
@@ -0,0 +1,123 @@
+{{ define "body" }}
+<div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div>
+<div class="relative bg-paper bg-background-light font-gentium flex flex-row ar-lt-0.6:flex-col w-full h-full overflow-y-auto text-base/loose tracking-wide z-10">
+ <div class="ar-gt-0.6:flex-3/5 justify-center content-start p-8">
+ <div class="flex flex-col justify-start items-start bg-paper bg-background-dark mb-8 shadow-[0.4rem_0.4rem_0.4rem_black]">
+ <p class="text-3xl/loose sm:text-4xl/loose lg:text-5xl/loose tracking-widest uppercase w-full font-m-plus font-thin italic text-left
+ border-l-4 border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ .L.HomePage.Hymn1 }}</p>
+ <hr class="w-full border-t-2 border-dotted border-main-hard mb-1">
+ <p class="text-xl/loose sm:text-2xl/loose lg:text-3xl/loose -indent-8 ml-12 p-1">{{ .L.HomePage.Hymn2 }}</p>
+ <p class="text-xl/loose sm:text-2xl/loose lg:text-3xl/loose -indent-8 ml-12 p-1">{{ .L.HomePage.Hymn3 }}</p>
+ <p class="text-xl/loose sm:text-2xl/loose lg:text-3xl/loose -indent-8 ml-12 p-1">{{ .L.HomePage.Hymn4 }}</p>
+ </div>
+
+ <div class="flex flex-col justify-center items-center">
+ <p class="text-xl sm:text-2xl lg:text-3xl p-1 w-full font-m-plus font-thin italic text-left
+ border-l-1.5 border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ .L.HomePage.DidYouKnowThat }}</p>
+ <hr class="w-full border-t-2 border-dotted border-main-hard mb-1">
+ <ul class="w-full text-left list-[circle]">
+ <li class="ml-4 mb-1">{{ index .FunFacts 0 }}</li>
+ <li class="ml-4 mb-1">{{ index .FunFacts 1 }}</li>
+ <li class="ml-4">{{ index .FunFacts 2 }}</li>
+ </ul>
+ </div>
+ </div>
+
+ <div class="ar-gt-0.6:flex-2/5 justify-center content-start p-8">
+ <div class="flex flex-col justify-center items-start mb-4">
+ <p class="text-xl sm:text-2xl lg:text-3xl p-1 w-full font-m-plus font-thin italic text-left
+ border-l-1.5 border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ .L.HomePage.Contacts }}</p>
+ <hr class="w-full border-t-2 border-dotted border-main-hard mb-1">
+ <a href="https://t.me/EarlInisMona">
+ <i class="fa-brands fa-telegram faw-4 h-4 mr-1"></i>
+ <span class="font-bold">Telegram:</span>
+ <span>@EarlInisMona</span>
+ </a>
+ <a href="https://discord.com/users/356057270951346176">
+ <i class="fa-brands fa-discord faw-4 h-4 mr-1"></i>
+ <span class="font-bold">Discord:</span>
+ <span>montferrat</span>
+ </a>
+ <a href="mailto:saya.andy@posteo.com">
+ <i class="fas fa-envelope faw-4 h-4 mr-1"></i>
+ <span class="font-bold">E-mail:</span>
+ <span>saya.andy@posteo.com</span>
+ </a>
+ </div>
+
+ <div class="flex relative aspect-square justify-center content-center mb-4">
+ {{- range $_ := iterate .FilledHeartCount }}
+ <div class="home-page-heart z-50">♥</div>
+ {{- end }}
+ {{- range $_ := iterate .OutlineHeartCount }}
+ <div class="home-page-heart z-50">♡</div>
+ {{- end }}
+ <img src="{{ .GifUrl }}"
+ class="home-page-gif z-49 -rotate-12 max-w-[70%] max-h-[70%] border-4 border-background-dark border-inset">
+ </div>
+
+ <script>
+ function shuffleHearts() {
+ vmin = calculateVmin(1);
+ document.querySelectorAll('.home-page-heart').forEach((e) => {
+ let top, left;
+ do {
+ top = Math.floor(rand() * 90) + 5;
+ left = Math.floor(rand() * 90) + 5;
+ } while (top > 30 && top < 70 && left > 30 && left < 70);
+ const opacity = rand() * 0.7 + 0.2;
+ const size = rand() * 3.2 + 0.8;
+ e.style["top"] = `calc(${top}% - ${size}vmin / 2)`;
+ e.style["left"] = `calc(${left}% - ${size}vmin / 2)`;
+ e.style["opacity"] = `${opacity}`;
+ e.style["font-size"] = `${size}vmin`;
+ });
+ }
+
+ let shuffleHeartsResizeTimeout;
+ function shuffleHeartsResizeCb() {
+ clearTimeout(shuffleHeartsResizeTimeout);
+ shuffleHeartsResizeTimeout = setTimeout(shuffleHearts, 300);
+ }
+ window.addEventListener('resize', shuffleHeartsResizeCb);
+
+ document.addEventListener('popout', (e) => {
+ window.removeEventListener('resize', shuffleHeartsResizeCb);
+ shuffleHeartsResizeCb = null;
+ });
+ </script>
+
+ <script>
+ document.addEventListener('htmx:afterRequest', (e) => {
+ if (e.detail.xhr.status == 404 || e.detail.successful != true) {
+ return console.error(e);
+ }
+ if (e.detail.target.id == 'general-page-body') {
+ shuffleHearts();
+ }
+ }, {once: true});
+ </script>
+
+ <div class="flex flex-col justify-center items-center">
+ <p class="text-xl sm:text-2xl lg:text-3xl p-1 w-full font-m-plus font-thin italic text-left
+ border-l-1.5 border-solid border-color-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ .L.HomePage.SidebarDescription }}</p>
+ <hr class="w-full border-t-2 border-dotted border-main-hard mb-1">
+ <div class="w-full grid grid-cols-[1fr_4fr] content-center items-center
+ [&>*:nth-child(4n+2)]:bg-background-medium/50 [&>*:nth-child(4n+3)]:bg-background-medium/50" style="container-type: inline-size;">
+ <i class="fas fa-home faw-full h-full text-[10cqi] content-center text-center text-main-hard"></i>
+ <p class="p-1">{{ .L.HomePage.HomePageDescription }}</p>
+ <i class="fas fa-search faw-full h-full text-[10cqi] content-center text-center text-main-hard"></i>
+ <p class="p-1">{{ .L.HomePage.BlogSearchDescription }}</p>
+ <i class="fas fa-map faw-full h-full text-[10cqi] content-center text-center text-main-hard"></i>
+ <p class="p-1">{{ .L.HomePage.MarkerMapDescription }}</p>
+ <i class="fas fa-swatchbook faw-full h-full text-[10cqi] content-center text-center text-main-hard"></i>
+ <p class="p-1">{{ .L.HomePage.ThemeSwitchDescription }}</p>
+ </div>
+ </div>
+ </div>
+</div>
+{{ end }}
diff --git a/views/pages/language-pick.html b/views/pages/language-pick.html
new file mode 100644
index 0000000..f4119e4
--- /dev/null
+++ b/views/pages/language-pick.html
@@ -0,0 +1,16 @@
+{{ define "body" }}
+<div class="flex flex-col justify-center text-3xl h-full">
+ {{- range .AvailableLanguages }}
+ <hr class="border-t-2 border-dotted border-main-hard">
+ <div class="nth-[2n+1_of_div]:bg-background-medium/50 nth-[2n_of_div]:bg-background-light/50 p-2.5 flex flex-row justify-center justify-items-center">
+ <a href="/{{ .Name }}" class="w-12 h-12 basis-12 shrink-0 mr-4">
+ <img onclick="return changeUrl('{{ .Name }}');" class="w-full h-full aspect-square cursor-pointer object-cover rounded-md select-none" src="{{ .Flag }}">
+ </a>
+ <a href="/{{ .Name }}" onclick="return changeUrl('{{ .Name }}');" class="cursor-pointer">
+ {{ .Alt }}
+ </a>
+ </div>
+ {{- end }}
+ <hr class="border-t-2 border-dotted border-main-hard">
+</div>
+{{ end }}
diff --git a/views/pages/robots.txt b/views/pages/robots.txt
new file mode 100644
index 0000000..aaef3f4
--- /dev/null
+++ b/views/pages/robots.txt
@@ -0,0 +1,7 @@
+User-agent: *
+Allow: /
+Disallow: /api/v1/email/
+Disallow: /ru/user/
+Disallow: /en/user/
+
+Sitemap: {{ .CanonicalEndpoint }}/sitemap.xml \ No newline at end of file
diff --git a/views/pages/sitemap.xml b/views/pages/sitemap.xml
new file mode 100644
index 0000000..1474a56
--- /dev/null
+++ b/views/pages/sitemap.xml
@@ -0,0 +1,10 @@
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {{- range .URLs }}
+ <url>
+ <loc>{{ $.CanonicalEndpoint }}{{ .Loc }}</loc>
+ <lastmod>{{ .LastModified.UTC.Format "2006-01-02T15:04:05Z" }}</lastmod>
+ <changefreq>{{ .ChangeFreq }}</changefreq>
+ <priority>{{ printf "%.1f" .Priority }}</priority>
+ </url>
+ {{- end }}
+</urlset>
diff --git a/views/pages/unsubscribe-page.html b/views/pages/unsubscribe-page.html
new file mode 100644
index 0000000..a917746
--- /dev/null
+++ b/views/pages/unsubscribe-page.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="robots" content="noindex,nofollow" />
+ <link
+ rel="icon"
+ href="/favicon-light.svg"
+ type="image/svg+xml"
+ media="(prefers-color-scheme: light)"
+ />
+ <link
+ rel="icon"
+ href="/favicon-dark.svg"
+ type="image/svg+xml"
+ media="(prefers-color-scheme: dark)"
+ />
+ <title>{{ .L.UnsubscribePage.Header }} // SAYA.UZ</title>
+ <style>
+ .bg-paper {
+ background-image: url(data:image/webp;base64,UklGRi4BAABXRUJQVlA4ICIBAABQCQCdASqAAIAAPm02lUmkIqIkIImIgA2JaW3rMFmGDAOKLAoJtP591ByFR74Tun2DP+Lygpfsz5FH7+cKgxi2Islfd03i5AJdXUfU0SDc8SXYAAD++hlzeYAJWQEF8ZdkJdlcA+5btZg0FMGaso8SHoBph0qAOQysElJ5C5SJFNoKIV1J550UyL7Y9Gh0/c/uzLnBmr8lvz7k1WeA81H4S5ViU/wBqa7aM1m8D9rDtrk8cSTqx+xWF6MS8UfZGSsks6CT/igtgv6syFN9uNA3LjnjiCJKYOvFcMkX+jB2578GWVo3nyLaM1QNPYCxn3TiUbnf7U0MdD2NsBpg1+Jd1wu6yW/U+goN+IQS6Nt4RMWltVcZHlxrneKJi0SobO0AAA==);
+ background-size: 128px;
+ background-repeat: repeat;
+ background-blend-mode: multiply;
+ }
+ </style>
+ </head>
+
+ <body
+ style="
+ width: 100dvw;
+ height: 100dvh;
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ "
+ >
+ <div
+ class="bg-paper"
+ style="flex: 3 0 0; background-color: rgba({{ .StatusColor }}, 0.1)"
+ ></div>
+
+ <div class="bg-paper" style="flex: 1 0 0; align-content: center">
+ <p
+ style="
+ position: relative;
+ width: 100%;
+ margin-inline: auto;
+ text-align: center;
+ font-size: 2rem;
+ "
+ >
+ {{ .StatusEmoji }}
+ </p>
+ </div>
+
+ <div class="bg-paper" style="flex: 1 0 0; align-content: center">
+ <p
+ style="
+ position: relative;
+ width: 100%;
+ margin-inline: auto;
+ text-align: center;
+ font-size: 1.5rem;
+ "
+ >
+ {{ .StatusText }}
+ </p>
+ </div>
+
+ <div
+ class="bg-paper"
+ style="flex: 3 0 0; background-color: rgba({{ .StatusColor }}, 0.2)"
+ ></div>
+ </body>
+</html>
diff --git a/views/pages/user-page.html b/views/pages/user-page.html
new file mode 100644
index 0000000..0dd006a
--- /dev/null
+++ b/views/pages/user-page.html
@@ -0,0 +1,206 @@
+{{ define "body" }}
+<div class="absolute w-full h-full inset-0 inset-shadow-[0_0_0.4rem_black] pointer-events-none z-20"></div>
+<div class="relative bg-paper bg-background-light flex flex-col px-8 py-4">
+ <form id="email-form" class="w-full mb-2 flex flex-col relative crossable"
+ hx-get="/api/v1/email/is-in-verification" hx-target="#email-message" hx-swap="outerHTML" hx-trigger="load" hx-indicator="this">
+ <div class="flex flex-row w-full mb-4 z-21">
+ <div class="flex flex-col w-full sm:flex-3/5 grow-0">
+ <label class="block text-main-medium font-bold mb-1 z-22">
+ {{ .L.UserProfile.EmailHeader }}
+ </label>
+ <input class="bg-background-medium appearance-none border-background-medium rounded ml-6 mr-4 py-2 px-4 text-main-medium leading-tight inset-shadow-[0_0_0.4rem_black] focus:outline-none focus:bg-background-light focus:text-main-hard z-22"
+ id="email-input" name="email" type="text" value="{{ .Email }}" placeholder="{{ .L.UserProfile.TypeEmail }}" maxlength="64"
+ data-validated-email="{{ .Email }}" onchange="checkIfValidated(this);">
+ </div>
+ </div>
+ <button class="w-max mx-auto bg-main-hard hover:bg-main-medium active:bg-main-soft active:inset-shadow-[0.2em_0.2em_0.2rem_black] transition-colors transition-300 text-background-light font-bold py-2 px-4 rounded z-22"
+ hx-post="/api/v1/email/send-verification-code" hx-target="#email-message" hx-swap="outerHTML" hx-indicator="#email-form">
+ {{ .L.UserProfile.SendCodeButton }}
+ </button>
+ </form>
+ <div id="email-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-[0_0_0.4rem_black] py-2 px-4 text-center"></div>
+
+ <hr class="my-2 border-t-4 border-dotted border-main-hard">
+
+ <form id="email-verification-form" class="w-full mb-2 flex flex-col relative hidden crossable"
+ {{ if .EmailCode }}hx-post="/api/v1/email/verify" hx-target="#verification-message" hx-swap="outerHTML" hx-trigger="load" hx-indicator="this"{{ end }}>
+ <div class="flex flex-row w-full mb-4 z-21">
+ <div class="flex flex-col w-full sm:flex-2/5 grow-0">
+ <label class="block text-main-medium font-bold ml-1 z-22">
+ {{ .L.UserProfile.VerificationCodeHeader }}
+ </label>
+ <input class="bg-background-medium appearance-none border-background-medium rounded ml-6 mr-4 py-2 px-4 text-main-medium leading-tight inset-shadow-[0_0_0.4rem_black] focus:outline-none focus:bg-background-light focus:text-main-hard z-22"
+ name="email_code" type="text" value="{{ .EmailCode }}" placeholder="0123456789ABCDEF" maxlength="16" autocapitalize="characters">
+ </div>
+ </div>
+ <button class="w-max mx-auto bg-main-hard hover:bg-main-medium active:bg-main-soft active:inset-shadow-[0.2em_0.2em_0.2rem_black] transition-colors transition-300 text-background-light font-bold py-2 px-4 rounded z-22"
+ hx-post="/api/v1/email/verify" hx-target="#verification-message" hx-swap="outerHTML" hx-indicator="#email-verification-form">
+ {{ .L.UserProfile.VerifyButton }}
+ </button>
+ </form>
+ <div id="verification-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-[0_0_0.4rem_black] py-2 px-4 text-center"></div>
+</div>
+
+<hr class="my-4 border-t-4 border-dotted border-main-hard">
+
+<div class="bg-paper bg-background-light flex flex-col inset-shadow-[0_0_0.4rem_black] px-8 py-4">
+ <form id="subs-form" class="w-full mb-2 flex flex-col relative crossable">
+ <div class="flex flex-col w-full mb-4 z-21">
+ <label class="block text-main-medium font-bold mb-1 z-22">
+ {{ .L.UserProfile.SubscriptionHeader }}
+ </label>
+ <div class="flex flex-col sm:flex-row w-full">
+ <div class="m-1 w-1/3">
+ <label><input class="mr-1" type="radio" id="tagsNone" name="tags" value="none" {{ if eq .TagsPicked "none" }}checked{{ end }} onclick="toggleTagsPick(this);">{{ .L.UserProfile.TagsNone }}</label>
+ </div>
+ <div class="m-1 w-1/3">
+ <label><input class="mr-1" type="radio" id="tagsAll" name="tags" value="all" {{ if eq .TagsPicked "all" }}checked{{ end }} onclick="toggleTagsPick(this);">{{ .L.UserProfile.TagsAll }}</label>
+ </div>
+ <div class="m-1 w-1/3">
+ <label><input class="mr-1" type="radio" id="tagsSpecific" name="tags" value="specific" {{ if eq .TagsPicked "specific" }}checked{{ end }} onclick="toggleTagsPick(this);">{{ .L.UserProfile.TagsSpecific }}</label>
+ </div>
+ </div>
+ <div id="pick-tags-form" class="flex flex-col w-full relative crossable">
+ <input type="text" class="bg-background-medium appearance-none border-background-medium rounded ml-6 mr-4 py-2 px-4 text-main-medium leading-tight inset-shadow-[0_0_0.4rem_black] focus:outline-none focus:bg-background-light focus:text-main-hard z-22"
+ list="existing-tags" onchange="addTag(this.value);" onkeydown="if (event.keyCode === 13) {addTag(this.value); this.value=''; return false;}">
+ <datalist id="existing-tags">
+ {{- range .ExistingTags }}
+ <option value="{{ .Name }}">
+ {{- end }}
+ </datalist>
+ <div id="tags-picked-list" class="bg-paper bg-background-dark flex flex-wrap inset-shadow-[0_0_0.4rem_black] p-2 m-4 w-full">
+ {{- range .TagsPickedList }}
+ <div id="tagPicked{{ . }}" class="bg-paper bg-main-hard text-background-light m-2 flex flex-row">
+ <p class="py-1 px-2">{{ . }}</p>
+ <p class="py-1 px-2 bg-paper bg-main-soft cursor-pointer" onclick="htmx.remove(htmx.find('#tagPicked{{ . }}'));">✘</p>
+ <input type="hidden" name="tags_picked" value="{{ . }}">
+ </div>
+ {{- end }}
+ </div>
+ </div>
+ <button class="w-max mx-auto bg-color-main-hard hover:bg-main-medium active:bg-color-main-soft active:inset-shadow-[0.2em_0.2em_0.2rem_black] transition-colors transition-300 text-background-light font-bold py-2 px-4 rounded z-22"
+ hx-put="/api/v1/subs" hx-target="#subs-message" hx-swap="outerHTML" hx-indicator="#subs-form">
+ {{ .L.UserProfile.SaveButton }}
+ </button>
+ </div>
+ </form>
+ <div id="subs-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-[0_0_0.4rem_black] py-2 px-4 text-center"></div>
+</div>
+
+<script>
+htmx.on("htmx:beforeSwap", (e) => {
+ if (e.detail.xhr.status === 422) {
+ e.detail.shouldSwap = true;
+ e.detail.isError = false;
+ }
+});
+
+var formAllowTimeout;
+var verificationHideTimeout;
+
+var url = new URL(window.location.href);
+url.searchParams.delete('email_code');
+window.history.pushState({}, '', url.toString());
+
+htmx.on("htmx:afterSwap", (e) => {
+ emailMessage = htmx.find("#email-message");
+ verificationMessage = htmx.find("#verification-message");
+ emailForm = htmx.find("#email-form");
+ emailInput = htmx.find("#email-input");
+ emailVerificationForm = htmx.find("#email-verification-form");
+ subsForm = htmx.find("#subs-form");
+ tryAgainTimeDiff = parseInt(emailMessage.dataset.strikedEndTime || "0") - new Date().getTime();
+ verificationWaitingTimeDiff = parseInt(emailMessage.dataset.codeExpiryTime || "0") - new Date().getTime();
+
+ if (tryAgainTimeDiff > 0) {
+ emailForm.classList.add("disabled");
+ formAllowTimeout = setTimeout(() => {
+ emailForm.classList.remove("disabled");
+ emailMessage.classList.add("hidden");
+ }, tryAgainTimeDiff);
+ } else {
+ emailForm.classList.remove("disabled");
+ }
+
+ if (verificationWaitingTimeDiff > 0) {
+ verificationHideTimeout = setTimeout(() => emailVerificationForm.classList.add("hidden"), verificationWaitingTimeDiff);
+ emailVerificationForm.classList.remove("hidden");
+ } else {
+ emailVerificationForm.classList.add("hidden");
+ }
+
+ if ((verificationMessage.dataset.hideVerificationPanel || "false") == "true") {
+ emailVerificationForm.classList.add("hidden");
+ }
+
+ if (emailInput.dataset.validatedEmail != "") {
+ subsForm.classList.remove("disabled");
+ } else {
+ subsForm.classList.add("disabled");
+ }
+});
+
+function checkIfValidated(elem) {
+ if ((elem.dataset.validatedEmail != "") && (elem.value == elem.dataset.validatedEmail)) {
+ elem.classList.add("!bg-green-300/20");
+ } else {
+ elem.classList.remove("!bg-green-300/20");
+ }
+}
+
+checkIfValidated(htmx.find("#email-input"));
+
+function toggleTagsPick(elem) {
+ const pickTagsForm = htmx.find("#pick-tags-form");
+ if (elem.value === "specific" && elem.checked) {
+ pickTagsForm.classList.remove("disabled");
+ } else {
+ pickTagsForm.classList.add("disabled");
+ }
+}
+
+toggleTagsPick(htmx.find("#tagsSpecific"));
+
+function addTag(name) {
+ name = name.trim();
+ const subsMessage = htmx.find("#subs-message");
+ const existingTags = htmx.findAll(htmx.find("#existing-tags"), "option");
+ found = [...existingTags].find(opt => opt.value===name);
+ if (!found) {
+ subsMessage.classList.remove("hidden");
+ subsMessage.innerHTML = "{{ .L.UserProfile.TagDoesNotExist }}".replace("{}", name);
+ return;
+ }
+
+ const tagsPickedList = htmx.find("#tags-picked-list");
+ const subscribedTags = htmx.findAll(tagsPickedList, "div input");
+ found = [...subscribedTags].find(opt => opt.value===name);
+ if (found) {
+ subsMessage.classList.remove("hidden");
+ subsMessage.innerHTML = "{{ .L.UserProfile.TagAlreadyAdded }}".replace("{}", name);
+ return;
+ }
+
+ tagsPickedList.innerHTML += `
+ <div id="tagPicked${name}" class="bg-paper bg-main-hard text-background-light m-2 flex flex-row">
+ <p class="py-1 px-2">${name}</p>
+ <p class="py-1 px-2 bg-paper bg-main-soft cursor-pointer" onclick="htmx.remove(htmx.find('#tagPicked${name}'));">✘</p>
+ <input type="hidden" name="tags_picked" value="${name}">
+ </div>
+ `;
+}
+
+htmx.on("htmx:configRequest", (e) => {
+ const params = e.detail.parameters;
+
+ if (Array.isArray(params.tags_picked)) {
+ tags_join = params.tags_picked[0] || "";
+ for (i = 1; i < params.tags_picked.length; i++) {
+ tags_join += ",";
+ tags_join += params.tags_picked[i];
+ }
+ params.tags_picked = tags_join;
+ }
+})
+</script>
+{{ end }} \ No newline at end of file