summaryrefslogtreecommitdiff
path: root/views
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'views')
-rw-r--r--views/layouts/general-mail.html124
-rw-r--r--views/layouts/general-page.html835
-rw-r--r--views/messages/new-post.html19
-rw-r--r--views/messages/verify-email.html10
-rw-r--r--views/pages/blog-catalogue.html239
-rw-r--r--views/pages/blog-page.html59
-rw-r--r--views/pages/global-map.html370
-rw-r--r--views/pages/home-page.html144
-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.html82
-rw-r--r--views/pages/user-page.html206
-rw-r--r--views/partials/blog-page-like-button.html28
-rw-r--r--views/partials/catalogue-blog-card-tags.html1
-rw-r--r--views/partials/catalogue-blog-cards.html39
-rw-r--r--views/partials/general-page-body.html2
-rw-r--r--views/partials/general-page-bottom-embeds.html1
-rw-r--r--views/partials/general-page-footer.html23
-rw-r--r--views/partials/general-page-header.html9
-rw-r--r--views/partials/general-page-top-embeds.html1
-rw-r--r--views/partials/global-map-widget.html109
-rw-r--r--views/partials/personal-page-status.html12
23 files changed, 2346 insertions, 0 deletions
diff --git a/views/layouts/general-mail.html b/views/layouts/general-mail.html
new file mode 100644
index 0000000..452982a
--- /dev/null
+++ b/views/layouts/general-mail.html
@@ -0,0 +1,124 @@
+<!doctype html>
+<html lang="en">
+ <meta charset="UTF-8" />
+ <head>
+ <style>
+ @font-face {
+ font-family: "Gentium Plus";
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src:
+ local("Gentium Plus"),
+ url(https://fonts.gstatic.com/s/gentiumplus/v2/Iurd6Ytw-oSPaZ00r2bNe8VZj5FNym499r7e.woff2)
+ format("woff2");
+ unicode-range:
+ U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+ }
+ @font-face {
+ font-family: "Gentium Plus";
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src:
+ local("Gentium Plus"),
+ url(https://fonts.gstatic.com/s/gentiumplus/v2/Iurd6Ytw-oSPaZ00r2bNe8VZi5FNym499g.woff2)
+ format("woff2");
+ unicode-range:
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
+ U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
+ U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+ }
+ html {
+ font-family: "Gentium Plus", sans-serif;
+ --bg-paper: url(data:image/webp;base64,UklGRi4BAABXRUJQVlA4ICIBAABQCQCdASqAAIAAPm02lUmkIqIkIImIgA2JaW3rMFmGDAOKLAoJtP591ByFR74Tun2DP+Lygpfsz5FH7+cKgxi2Islfd03i5AJdXUfU0SDc8SXYAAD++hlzeYAJWQEF8ZdkJdlcA+5btZg0FMGaso8SHoBph0qAOQysElJ5C5SJFNoKIV1J550UyL7Y9Gh0/c/uzLnBmr8lvz7k1WeA81H4S5ViU/wBqa7aM1m8D9rDtrk8cSTqx+xWF6MS8UfZGSsks6CT/igtgv6syFN9uNA3LjnjiCJKYOvFcMkX+jB2578GWVo3nyLaM1QNPYCxn3TiUbnf7U0MdD2NsBpg1+Jd1wu6yW/U+goN+IQS6Nt4RMWltVcZHlxrneKJi0SobO0AAA==);
+ }
+ body {
+ background-color: #e3e6ff;
+ }
+ a {
+ text-decoration: underline;
+ text-shadow: none !important;
+ }
+ .header {
+ width: 100%;
+ padding: 8px 8px 8px 32px;
+ font-size: 48px;
+ color: white;
+ text-shadow:
+ -2px 0 #343b58,
+ 0 2px #343b58,
+ 2px 0 #343b58,
+ 0 -2px #343b58;
+ background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='80'><path fill='#e5e8ff' d='M0 0h40v80H0z'/><g fill='none' stroke-linecap='square' stroke-width='4.5'><path stroke='#8d4453' d='m-10 5 20 10L30 5l20 10'/><path stroke='#375e0d' d='m-10 25 20 10 20-10 20 10'/><path stroke='#006a85' d='m-10 45 20 10 20-10 20 10'/><path stroke='#5a3e8e' d='m-10 65 20 10 20-10 20 10'/></g></svg>");
+ background-color: #e3e6ff;
+ background-size: contain;
+ background-repeat: repeat-x;
+ }
+ .content {
+ margin: 0 32px 0 32px;
+ padding: 16px 16px 32px 16px;
+ font-size: 24px;
+ text-shadow:
+ -1px 0 #343b58,
+ 0 1px #343b58,
+ 1px 0 #343b58,
+ 0 -1px #343b58;
+ color: white;
+ background-color: #c3caff;
+ background-image: var(--bg-paper);
+ background-blend-mode: multiply;
+ background-repeat: repeat;
+ background-size: 128px;
+ }
+ .footer {
+ margin: 0;
+ padding: 1px 8px 1px 8px;
+ font-size: 16px;
+ color: white;
+ }
+ .darkened {
+ background-color: #9aa5f4;
+ background-image: var(--bg-paper);
+ background-blend-mode: multiply;
+ background-repeat: repeat;
+ background-size: 128px;
+ }
+ .outlier {
+ padding-inline: 4px;
+ background-color: #6c6e75;
+ background-image: var(--bg-paper);
+ background-blend-mode: multiply;
+ background-repeat: repeat;
+ background-size: 128px;
+ }
+ table,
+ th,
+ td {
+ border: 1px solid black;
+ }
+ td {
+ padding: 5px;
+ }
+ img {
+ width: 200px;
+ }
+ </style>
+ </head>
+
+ <body>
+ <div id="header" class="header">saya.uz</div>
+
+ <div
+ id="content"
+ class="content"
+ style="background-color: #e3e6ff !important"
+ >
+ {{ block "body" . }}{{ end }}
+ </div>
+
+ <div id="footer" class="footer darkened">
+ {{ block "footer" . }}{{ end }}
+ </div>
+ </body>
+</html>
diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html
new file mode 100644
index 0000000..06ef625
--- /dev/null
+++ b/views/layouts/general-page.html
@@ -0,0 +1,835 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ {{- range .Meta }}
+ <meta
+ {{with
+ .Name}}name="{{.}}"
+ {{end}}{{with
+ .Property}}property="{{.}}"
+ {{end}}{{with
+ .Content}}content="{{.}}"
+ {{end}}
+ />
+ {{- if eq .Property "og:title" }}
+ <title>{{.Content}}</title>
+ {{- end }} {{- if eq .Property "og:description" }}
+ <meta name="description" content="{{.Content}}" />
+ {{- end }} {{- if eq .Property "og:url" }}
+ <link rel="canonical" href="{{.Content}}" />
+ {{- end }} {{- end }}
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/fonts/fonts.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet/1.9.4/leaflet.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/glightbox/3.3.0/css/glightbox.min.css"
+ />
+ <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="icon"
+ href="/favicon.ico"
+ type="image/x-icon"
+ />
+ {{- with .LinkedData }}
+ <script type="application/ld+json">
+ {{ . }}
+ </script>
+ {{- end }}
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/leaflet/1.9.4/leaflet.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/protomaps-leaflet/5.0.0/dist/protomaps-leaflet.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/glightbox/3.3.0/js/glightbox.min.js"></script>
+ </head>
+
+ <body
+ data-theme="ram"
+ class="font-m-plus text-main-hard overflow-hidden bg-interlocked-hexagons h-dvh @container flex"
+ >
+ <!-- Streamline Icons: https://streamlinehq.com -->
+ <svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
+ <symbol id="icon-back" viewBox="-4 -4 32 32"><g>
+ <path d="M23.9 10.45a12.31 12.31 0 0 0 -1.15 -3.61 9.12 9.12 0 0 0 -2.29 -3A13 13 0 0 0 19 2.88c-0.81 -0.48 -1.73 -1 -2.2 -1.18a0.34 0.34 0 0 0 -0.29 0.62c0.39 0.18 1.09 0.56 1.77 1A14.8 14.8 0 0 1 20 4.38a8.27 8.27 0 0 1 2 2.81 11.57 11.57 0 0 1 1 3.37 9.88 9.88 0 0 1 -4.18 9 11.15 11.15 0 0 1 -9.82 2 20.19 20.19 0 0 1 -2 -0.68A13.23 13.23 0 0 1 5.2 20a8.59 8.59 0 0 1 -3.7 -4.66 8.84 8.84 0 0 1 0.08 -6A12.88 12.88 0 0 1 6 3.31a10.45 10.45 0 0 1 7.24 -1.72 0.3 0.3 0 0 0 0.06 -0.6 11.16 11.16 0 0 0 -7.69 1.69A13.82 13.82 0 0 0 0.71 9a9.81 9.81 0 0 0 -0.23 6.69A9.63 9.63 0 0 0 4.62 21a14.35 14.35 0 0 0 2 1 21.55 21.55 0 0 0 2.09 0.72 12.23 12.23 0 0 0 10.78 -2.27 10.81 10.81 0 0 0 4.41 -10Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ <path d="M18.68 13.8a0.29 0.29 0 0 0 0.36 -0.22 7.5 7.5 0 0 0 -0.4 -4.82 0.6 0.6 0 0 0 -0.44 -0.3 4.51 4.51 0 0 0 -0.95 0c-0.46 0 -3.32 0.39 -5.08 0.58l-0.68 0.07 0 -0.67a18.15 18.15 0 0 0 -0.16 -2.34 1.16 1.16 0 0 0 -0.15 -0.42 0.57 0.57 0 0 0 -0.46 -0.25 2.88 2.88 0 0 0 -1.27 0.41A17.24 17.24 0 0 0 6 8.49a10.89 10.89 0 0 0 -1.68 2 2.28 2.28 0 0 0 -0.41 1.33A5.09 5.09 0 0 0 5.28 14a32.9 32.9 0 0 0 4 3.68 10.06 10.06 0 0 0 1.07 0.5 0.63 0.63 0 0 0 0.55 -0.06 2 2 0 0 0 0.42 -1c0.14 -0.82 0.23 -2.12 0.28 -2.72l0.31 0c1.43 0.11 4.57 0.35 5.94 0.4a5.59 5.59 0 0 0 0.64 0 0.48 0.48 0 0 0 0.29 -0.13 0.34 0.34 0 0 0 -0.36 -0.55c0 -0.08 -0.29 0 -0.54 0 -1.36 -0.08 -4.48 -0.4 -5.9 -0.55l-0.65 -0.07a0.51 0.51 0 0 0 -0.52 0.27 34 34 0 0 1 -0.49 3.45c-0.22 -0.13 -0.49 -0.35 -0.56 -0.4a34.25 34.25 0 0 1 -3.12 -3 13.83 13.83 0 0 1 -1.29 -1.54 1.39 1.39 0 0 1 -0.35 -0.55 1.61 1.61 0 0 1 0.39 -0.84 13 13 0 0 1 2 -2.17A16.1 16.1 0 0 1 9.8 6.91l0.54 -0.3a16.11 16.11 0 0 1 0.15 1.8l0 1.19a0.5 0.5 0 0 0 0.5 0.5c0.23 0 0.71 -0.06 1.32 -0.15 1.72 -0.25 4.5 -0.74 5 -0.74 0.15 0 0.65 0.14 0.79 0a6.76 6.76 0 0 1 0.54 2 6.61 6.61 0 0 1 -0.12 2.23 0.3 0.3 0 0 0 0.16 0.36Zm-8.07 3.46c0 0.07 -0.1 0.06 -0.2 0 0.1 -0.04 0.24 -0.11 0.2 0ZM10.26 6.2l0 0.08v0.08c-0.07 -0.06 -0.13 -0.12 0 -0.16Z" fill="var(--color-main)" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-logo" role="img" viewBox="-20 -20 160 160">
+ <defs>
+ <linearGradient gradientTransform="rotate(150, 0.5, 0.5)" x1="50%" y1="0%" x2="50%" y2="100%" id="gradient">
+ <stop stop-color="var(--color-accent-deep)" stop-opacity="1" offset="0%"></stop><stop stop-color="var(--color-main)" stop-opacity="1" offset="100%"></stop>
+ </linearGradient>
+ </defs>
+ <path d="m106.155 94.45 0.005 -0.01c-6.465 16.215 -26.09 26.16 -47.235 25.525C26.5 119.965 0 92.4 0 59.53S26.38 0.005 58.925 0.005c8.965 0 17.465 2.03 25.075 5.65 0.405 -0.885 1.355 -2.72 2.255 -2.785 1.19 -0.085 1.87 0.685 2.63 1.545 0.77 0.86 2.3 2.145 2.3 2.145s6.965 -2.405 14.775 1.885c7.815 4.29 8.915 5.58 10.45 8.58 0.76 1.505 0.975 4.145 1 6.41a3.98 3.98 0 0 0 -0.35 -0.015c-2.48 0 -4.8 2.275 -4.8 5.4 0 1.315 0.41 2.48 1.075 3.39l-0.05 0.035a7.525 7.525 0 0 0 -0.66 0.05 93.52 93.52 0 0 0 -1.945 -0.71 12.65 12.65 0 0 1 -4.1 -2.36 7.01 7.01 0 0 0 -5.98 -10.56c-1.915 0 -3.65 0.78 -4.91 2.05 -2.36 -1.355 -5.87 -2.41 -12.635 -2.825l-2.035 -0.055c-11.41 0.06 -18.055 1.395 -29.895 6.505 -3.015 1.415 -6.03 3.075 -8.925 5.005 -2.115 1.5 -3.195 3.35 -3.545 5.685a6.63 6.63 0 0 0 6.15 6.865h0.210c6.35 0.3 10.195 9.95 10.315 12.485 0.02 0.25 0.02 0.115 0.015 0.4 -0.16 3.635 -1.85 6.335 -5.44 6.23a6.155 6.155 0 0 1 -4.88 -2.47c-0.315 -0.385 -0.515 -0.86 -0.795 -1.27 -3.33 -5.405 -8.66 -6.80 -13.855 -7.615 -2.19 -0.34 -5.365 -0.61 -6.55 1.25a41.4 41.4 0 0 0 -2.885 15.315c-0.1 25.18 20.205 45.59 45.13 45.59 12.875 0 26.745 -4.76 34.965 -13.5l-0.175 0.15c-8.86 7.365 -23.3 9.705 -30.135 9.705 -21.51 0 -39.09 -16.16 -39.09 -37.89 0 -6.38 1.44 -11.98 4.07 -16.8 2.475 0.915 4.735 2.415 6.4 5.11a1.2 1.2 0 0 0 0.065 0.1050c0.32 0.46 0.555 0.985 0.91 1.42 2.12 2.62 4.405 3.29 6.71 3.4h0.05c2.15 0.065 3.84 -0.6 5.12 -1.71 1.735 -1.5 2.75 -3.95 2.885 -6.91v-0.07c0.01 -0.425 0 -0.265 -0.02 -0.56 -0.12 -1.88 -1.665 -6.59 -4.53 -10.135 -1.33 -1.655 -2.935 -3.035 -4.75 -3.87l0.6 -0.37c3.78 -2.285 11.82 -4.885 22.96 -3.19 5.65 0.865 10.275 2.095 17.415 4.395 8.285 2.67 12.895 6.395 19.27 7.135 0.75 0.085 1.505 0.09 2.25 0.015 2.05 5.645 3.17 11.75 3.17 18.105 0 10.34 -2.95 19.975 -8.055 28.1zm9.735 -61.37s-0.575 1.005 -1.82 1.61c-0.515 0.25 -1.41 -0.375 -2.25 0.5 -1.795 3.63 2.58 6.66 4.615 6.575 2.04 -0.085 3.65 -2.16 3.56 -3.965 -0.085 -2.79 -4.1 -4.72 -4.1 -4.72zm1.17 -7.16c1.275 0 2.31 1.3 2.31 2.9 0 1.6 -1.035 2.9 -2.31 2.9 -1.27 0 -2.3 -1.3 -2.3 -2.9 0 -1.6 1.03 -2.9 2.3 -2.9zm-16.46 -4.755c2.46 0 4.45 2.015 4.45 4.5a4.475 4.475 0 0 1 -4.45 4.49 4.475 4.475 0 0 1 -4.45 -4.495c0 -2.48 1.995 -4.495 4.45 -4.495z" fill="url(#gradient)" stroke-width="5"></path>
+ </symbol>
+ <symbol id="icon-newspaper" viewBox="-4 -4 32 32"><g>
+ <path d="M13.3 5.15c-1.68 -0.31 -9.3 -1.08 -9.61 0.47 -0.58 2.8 -0.8 3.4 -0.8 3.76 0 0.87 1.94 1 2.81 1.14s1.94 0.29 2.92 0.4a11.4 11.4 0 0 0 3.85 -0.28c0.29 0 0.68 0 0.9 -0.34a2.66 2.66 0 0 0 0.15 -1.3c0.34 -2.77 0.4 -3 0.3 -3.34a0.67 0.67 0 0 0 -0.52 -0.51Zm-1 4.36 -1.7 0.28a30.3 30.3 0 0 1 -4.81 -0.23 6.67 6.67 0 0 1 -2 -0.28c0 -0.19 -0.09 0.74 0.29 -2.08 0 0 0.36 -1.37 0.36 -1.45 0.15 0.37 5 -0.24 7.2 0.14q0.55 0.09 1.08 0.21l0 0.46c-0.52 3.63 -0.44 2.72 -0.45 2.95Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M17.54 7a0.34 0.34 0 0 0 0.46 -0.17c0.58 -0.9 -1.81 -1.11 -3.24 -0.87a0.35 0.35 0 0 0 -0.37 0.32c-0.04 0.72 2.45 0.41 3.15 0.72Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M14.44 9.13a5 5 0 0 0 3.08 0.48c0.43 0.14 1.06 -0.56 0.19 -0.86a3.36 3.36 0 0 0 -0.6 -0.09c-0.96 -0.15 -3.11 -0.4 -2.67 0.47Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M7.78 12.72c-4.92 -0.13 -4.67 -0.09 -4.8 0.13a0.28 0.28 0 0 0 0.15 0.42c0.16 0.09 0.06 0.05 4.61 0.52a73.45 73.45 0 0 0 9.5 0 0.34 0.34 0 0 0 0 -0.68c-2.38 0 -3 -0.23 -9.46 -0.39Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M16.68 16.61c-5.44 -0.27 -3.68 -0.55 -8.64 -0.47 -0.89 0 -1.78 0.05 -2.67 0 -0.35 0 -2.17 -0.26 -2.3 -0.23a0.32 0.32 0 0 0 0 0.61c0.1 0 -0.16 0 2.25 0.44a77.28 77.28 0 0 0 7.73 0.39l1.13 0c4.08 0.01 3.37 -0.77 2.5 -0.74Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M24 10.27c-0.13 -3.52 -0.05 -2.5 -0.14 -4.86a0.44 0.44 0 0 0 -0.76 -0.28 2.72 2.72 0 0 1 -2.33 1.25 21.46 21.46 0 0 0 0.56 -2.94 0.88 0.88 0 0 0 -0.22 -0.6c-0.31 -0.3 -3 -0.21 -3.48 -0.2 -3.05 0.09 -5.71 -0.27 -9.06 -0.2 -4.62 0.1 -5.83 -0.73 -5.47 0.2a0.45 0.45 0 0 0 0.3 0.24 33.56 33.56 0 0 0 5.17 0.37c4.41 0.09 4.28 0.53 11.32 0.53l0.17 0c0 1.27 -1 3.8 -1 8.45 0 1.64 0.13 6.24 0.85 7.56a2.26 2.26 0 0 0 0.4 0.51c-3.31 1.08 -15.91 0.5 -17.78 -0.21 -0.32 -0.12 -0.77 -0.16 -0.9 -0.36 -1.17 -1.73 0.06 -9.79 0.28 -11.81a27.82 27.82 0 0 1 0.67 -3.53A7.91 7.91 0 0 0 3 2.69a0.31 0.31 0 0 0 -0.58 0c0.09 -0.1 -0.89 2.79 -1.25 5.18C0.72 10.49 -0.86 18.1 0.61 20.33c0.4 0.61 1 0.63 1.45 0.81a11.09 11.09 0 0 0 3.14 0.51c2.08 0.13 15.3 0.61 16.69 -1.21 2.16 -2.82 2.2 -6.66 2.11 -10.17ZM21.3 20a1 1 0 0 1 -0.8 -0.58c-0.61 -1.2 -0.59 -5.82 -0.53 -7.19A33.39 33.39 0 0 1 20.61 7a3.11 3.11 0 0 0 1.24 -0.07 3.52 3.52 0 0 0 1.09 -0.52C22.61 13 23.52 16.56 21.3 20Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M21.43 8.91c-0.57 -0.41 -0.55 1 -0.68 2.15a19.8 19.8 0 0 0 0.06 4.15 0.34 0.34 0 0 0 0.68 0 20.13 20.13 0 0 0 0.31 -4.15c-0.28 -2.29 -0.19 -2.06 -0.37 -2.15Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-map" viewBox="-4 -4 32 32"><g>
+ <path d="M18.47 13.42a0.31 0.31 0 0 0 0.41 0.11 0.29 0.29 0 0 0 0.11 -0.41C18 11.2 16.38 9.18 15.71 7A5.35 5.35 0 0 1 16 2.86a3.54 3.54 0 0 1 2.4 -1.53 4.18 4.18 0 0 1 2.93 0.18 3.19 3.19 0 0 1 1.16 1.2A3.59 3.59 0 0 1 23 4.34a6.78 6.78 0 0 1 -0.53 2.76 34 34 0 0 1 -2.1 4l-1.11 1.62a0.35 0.35 0 0 0 0.1 0.48 0.34 0.34 0 0 0 0.47 -0.09L21 11.45a33.28 33.28 0 0 0 2.3 -4 7.51 7.51 0 0 0 0.7 -3.14 4.62 4.62 0 0 0 -0.6 -2.14A4.23 4.23 0 0 0 21.86 0.52 5.38 5.38 0 0 0 18.08 0.2 4.66 4.66 0 0 0 15 2.38a6.25 6.25 0 0 0 -0.12 4.94c0.74 2.18 2.44 4.18 3.59 6.1Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M18.36 6.15C21 7 21 4.49 20 3.73c-1.39 -1.32 -3.48 1.84 -1.64 2.42Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M8.79 9a1.43 1.43 0 0 1 -0.37 0.77c-0.31 0.31 -0.89 0.45 -1.26 0.74a1.36 1.36 0 0 0 -0.49 0.85 3.43 3.43 0 0 0 0.21 1.58 8 8 0 0 1 0.55 1.79 1 1 0 0 1 -0.3 0.86 1.51 1.51 0 0 1 -0.65 0.35 1.9 1.9 0 0 1 -0.81 0.08 8.41 8.41 0 0 0 -1.15 -0.14 1.73 1.73 0 0 0 -0.94 0.23 1.93 1.93 0 0 0 -0.67 0.8c-0.15 0.31 -0.28 0.67 -0.44 1s0 1.08 0.51 0.57a2.55 2.55 0 0 0 0.51 -0.86 1.53 1.53 0 0 1 0.51 -0.76 0.87 0.87 0 0 1 0.48 -0.06 6.7 6.7 0 0 1 1 0.21 3.13 3.13 0 0 0 1.25 0 2.54 2.54 0 0 0 1.18 -0.59 2.11 2.11 0 0 0 0.66 -1.77 6.48 6.48 0 0 0 -0.53 -1.77 3.24 3.24 0 0 1 -0.37 -1.37 0.52 0.52 0 0 1 0.24 -0.34A6.52 6.52 0 0 0 9 10.31a2.07 2.07 0 0 0 0.48 -1.25 4.3 4.3 0 0 0 -0.07 -1c-0.26 -0.34 -0.71 -0.22 -0.63 0.07a2.49 2.49 0 0 1 0.01 0.87Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ <path d="m23.83 20.17 -0.44 -2.79 -0.67 -5.76a0.3 0.3 0 0 0 -0.6 0.08l0.54 5.77 0.34 2.77c0 0.17 0.06 0.38 0.08 0.58a0.5 0.5 0 0 1 0 0.18 0.63 0.63 0 0 1 -0.26 0.22c-0.16 0.09 -0.34 0.15 -0.49 0.22 -0.33 0.13 -0.67 0.25 -1 0.36 -0.52 0.16 -1 0.28 -1.58 0.41 -0.84 0.2 -1.7 0.45 -2.57 0.61a7.67 7.67 0 0 1 -1.65 0.14 4.8 4.8 0 0 1 -1.13 -0.21c-0.39 -0.11 -4.47 -1.38 -6 -1.81a8.17 8.17 0 0 0 -2.35 -0.33 10.19 10.19 0 0 0 -2.33 0.32 5.3 5.3 0 0 0 -1.21 0.27l0 -0.21c0 -0.22 0 -0.45 -0.06 -0.67 0 -0.47 -0.28 -2.86 -0.33 -3.26 -0.3 -2.29 -0.7 -4.78 -0.88 -7.09l-0.08 -1.36A9.09 9.09 0 0 1 1 7.34 0.4 0.4 0 0 1 1.14 7a2.44 2.44 0 0 1 1.07 -0.33 12.47 12.47 0 0 1 1.94 0A12.63 12.63 0 0 1 6 6.88a14.23 14.23 0 0 1 1.81 0.49c0.24 0.08 2.74 0.92 3.32 1.09a22.06 22.06 0 0 0 2.3 0.6 0.35 0.35 0 1 0 0.12 -0.68 20.56 20.56 0 0 1 -2.2 -0.61c-1.28 -0.42 -2.6 -0.91 -3.28 -1.15a15.84 15.84 0 0 0 -1.9 -0.55 13.16 13.16 0 0 0 -2 -0.28 12.94 12.94 0 0 0 -2.08 0 3.2 3.2 0 0 0 -1.47 0.44A1.27 1.27 0 0 0 0 7a5.65 5.65 0 0 0 0.19 1.71L0.22 10c0.15 2.33 0.63 4.62 0.9 6.93 0.07 0.57 0.13 1.13 0.16 1.7s0 1.12 0 1.69a7 7 0 0 0 0.07 0.79 3.24 3.24 0 0 0 0.16 0.8 1.51 1.51 0 0 0 0.27 0.42 0.76 0.76 0 0 0 0.63 0.22A11.69 11.69 0 0 0 4 22.06a8.45 8.45 0 0 1 2.06 -0.29 7 7 0 0 1 2 0.28l4.16 1.13c0.62 0.2 1.22 0.43 1.84 0.6a5.67 5.67 0 0 0 1.37 0.21 8 8 0 0 0 1.88 -0.19c0.89 -0.18 1.76 -0.47 2.6 -0.69 0.56 -0.14 1.1 -0.29 1.63 -0.47 0.37 -0.12 0.73 -0.26 1.08 -0.41a4.65 4.65 0 0 0 0.7 -0.36 1.35 1.35 0 0 0 0.45 -0.5 1 1 0 0 0 0.1 -0.47 6.79 6.79 0 0 0 -0.04 -0.73Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M13.27 21.36a3 3 0 0 0 -0.93 -2 8.73 8.73 0 0 1 -0.87 -0.85 0.56 0.56 0 0 1 -0.11 -0.62 1.94 1.94 0 0 1 0.76 -0.83 3 3 0 0 1 1.12 -0.51 8.59 8.59 0 0 0 2.07 -0.43 1.88 1.88 0 0 0 1 -1.23l0.12 -0.7a0.3 0.3 0 0 0 -0.29 -0.32 0.29 0.29 0 0 0 -0.31 0.29l-0.15 0.5a1.21 1.21 0 0 1 -0.71 0.71 7.5 7.5 0 0 1 -1.89 0.14 4 4 0 0 0 -1.62 0.59 3 3 0 0 0 -1.19 1.35 1.56 1.56 0 0 0 0.12 1.5 6.3 6.3 0 0 0 1.26 1.15 2.41 2.41 0 0 1 0.8 1.19 0.92 0.92 0 0 1 0 0.52c0 0.33 0.6 0.64 0.75 0.14a1.84 1.84 0 0 0 0.07 -0.59Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-palette" viewBox="-4 -4 32 32"><g>
+ <path d="M10 19.26a0.32 0.32 0 0 0 0 0.59 5.85 5.85 0 0 0 1.62 0.42 1 1 0 0 0 0.93 -0.34 5.08 5.08 0 0 0 0.63 -1.35c0.33 -1 0.46 -2.23 0.71 -3.15 0.09 -0.34 0.2 -0.67 0.32 -1 0.28 -0.79 0.61 -1.56 0.88 -2.36 0.14 -0.4 0.27 -0.81 0.39 -1.22 0.27 -0.94 0.5 -1.9 0.78 -2.84 0.2 -0.69 0.43 -1.39 0.62 -2.1a12.59 12.59 0 0 0 0.32 -1.48 8.09 8.09 0 0 0 0.16 -1 0.83 0.83 0 0 0 -0.19 -0.58 1.68 1.68 0 0 0 -0.64 -0.41 7.51 7.51 0 0 0 -1.33 -0.37l-4.3 -0.78c-0.4 -0.1 -0.73 0.1 -0.95 0.57 -0.33 0.7 -0.42 2.14 -0.77 2.79a0.3 0.3 0 0 0 0.11 0.39 0.28 0.28 0 0 0 0.42 -0.04 18.6 18.6 0 0 0 0.77 -2.47 1.87 1.87 0 0 1 0.19 -0.4s0 -0.07 0.08 -0.06L15 3a4.45 4.45 0 0 1 1.41 0.53 5.74 5.74 0 0 1 -0.24 0.71 12.78 12.78 0 0 1 -0.32 1.36c-0.2 0.7 -0.43 1.4 -0.63 2.09l-1.1 4c-0.24 0.81 -0.54 1.58 -0.79 2.38 -0.11 0.35 -0.21 0.7 -0.3 1.07 -0.21 0.92 -0.3 2.11 -0.58 3.15a4.64 4.64 0 0 1 -0.45 1.23s-0.08 0 -0.13 0a1.89 1.89 0 0 1 -0.57 0 6.94 6.94 0 0 1 -1 -0.28 0.33 0.33 0 0 0 -0.24 0 4 4 0 0 0 0.83 -0.27 1.74 1.74 0 0 0 0.68 -0.57 0.83 0.83 0 0 0 0.14 -0.54 5.77 5.77 0 0 0 -0.17 -0.79l-0.59 -2.83c-0.22 -1.19 -0.48 -2.38 -0.76 -3.56 -0.43 -1.77 -0.91 -3.53 -1.37 -5.27A24.28 24.28 0 0 0 8 2.73 5.29 5.29 0 0 0 6.85 1a0.74 0.74 0 0 0 -0.54 -0.17 3.48 3.48 0 0 0 -0.67 0.17l-2.21 0.66A10.36 10.36 0 0 0 0.91 2.77 1.91 1.91 0 0 0 0 4a2.51 2.51 0 0 0 0.08 1c0.14 0.61 0.44 1.28 0.58 1.73L2.17 12l2.27 8a0.27 0.27 0 0 0 0.35 0.2 0.29 0.29 0 0 0 0.2 -0.35l-2 -8.1 -1.37 -5.36c-0.1 -0.38 -0.32 -0.94 -0.46 -1.47a1.93 1.93 0 0 1 -0.1 -0.79c0 -0.27 0.38 -0.45 0.74 -0.65a9.89 9.89 0 0 1 2 -0.78L6 2l0.24 0a4.41 4.41 0 0 1 0.7 1.2 21 21 0 0 1 0.8 2.55c0.49 1.72 1 3.46 1.46 5.21 0.31 1.16 0.6 2.33 0.84 3.49l0.66 2.86 0.18 0.71a1 1 0 0 1 -0.39 0.32 3.81 3.81 0 0 1 -0.91 0.32l-3.64 0.93a0.33 0.33 0 0 0 -0.24 0.39 0.32 0.32 0 0 0 0.39 0.25l3.67 -0.86a2 2 0 0 0 0.24 -0.11Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M23.73 9.93a7.66 7.66 0 0 0 -0.8 -0.88 13.75 13.75 0 0 0 -1.45 -1.31c-0.77 -0.63 -1.61 -1.25 -2.23 -1.75a0.58 0.58 0 0 0 -0.68 0.11c-0.37 0.29 -1.05 1 -1.5 1.41l-0.18 0.19 -0.08 0 -0.07 0a0.25 0.25 0 0 0 -0.17 0.1 0.27 0.27 0 0 0 0 0.4c0.07 0.07 0.32 0.12 0.62 -0.1s1.09 -1 1.55 -1.34l0.26 -0.1c0.57 0.5 1.3 1.11 2 1.71a15.9 15.9 0 0 1 1.3 1.3c0.15 0.17 1.1 0.88 0.77 1a1.06 1.06 0 0 1 -0.23 0.41c-0.15 0.2 -0.34 0.39 -0.47 0.54s-0.49 0.51 -0.74 0.76c-0.61 0.6 -1.25 1.17 -1.86 1.77 -1.47 1.51 -2.86 3.12 -4.32 4.65 -0.62 0.65 -1.24 1.29 -1.9 1.9 -0.33 0.3 -0.65 0.6 -1 0.88s-0.45 0.37 -0.68 0.54 -0.46 0.2 -0.42 0.33a1.38 1.38 0 0 1 -0.74 -0.32 7.64 7.64 0 0 1 -1.13 -1.17 0.33 0.33 0 0 0 -0.51 0.41 8.44 8.44 0 0 0 1.21 1.32 2 2 0 0 0 1.27 0.51 0.62 0.62 0 0 0 0.31 -0.1c0.15 -0.09 0.36 -0.28 0.45 -0.34 0.26 -0.18 0.51 -0.36 0.75 -0.55s0.7 -0.57 1.05 -0.86c0.7 -0.6 1.37 -1.22 2 -1.87 1.46 -1.48 2.89 -3.1 4.37 -4.58 0.6 -0.61 1.24 -1.17 1.84 -1.78 0.27 -0.27 0.53 -0.54 0.78 -0.83a5.83 5.83 0 0 0 0.71 -1 1.66 1.66 0 0 0 0.19 -0.65 1.3 1.3 0 0 0 -0.27 -0.71Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m16.85 7.71 -0.09 0h0.05Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M14.33 8.68a5.87 5.87 0 0 0 0.29 -0.75 11.92 11.92 0 0 0 0.62 -1.7 3.66 3.66 0 0 0 0.08 -1.38 0.61 0.61 0 0 0 -0.38 -0.43 4.9 4.9 0 0 0 -0.51 -0.12L12.84 4l-1.31 -0.29 -0.36 0a0.45 0.45 0 0 0 -0.47 0.28l-0.33 1.81a0.28 0.28 0 0 0 0.22 0.34 0.29 0.29 0 0 0 0.34 -0.22l0.41 -1.42 1.22 0.42 1.58 0.43h0.1a3.68 3.68 0 0 1 -0.09 0.63 12.53 12.53 0 0 1 -0.49 1.59s0 0.17 0 0.32c-0.18 -0.07 -0.43 -0.09 -0.51 -0.12 -0.37 -0.13 -0.74 -0.25 -1.12 -0.36l-1.13 -0.29a0.32 0.32 0 0 0 -0.4 0.22 0.32 0.32 0 0 0 0.22 0.4c0.36 0.12 0.72 0.24 1.07 0.38l1 0.43c0.13 0.06 0.47 0.29 0.71 0.38A0.86 0.86 0 0 0 14 9a0.57 0.57 0 0 0 0.33 -0.32Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M12.42 12.21s-0.07 0.14 -0.12 0.27l-0.71 -0.21a0.33 0.33 0 0 0 -0.4 0.24 0.32 0.32 0 0 0 0.24 0.39c0.27 0.1 0.57 0.31 0.86 0.44l0.31 0.1a0.55 0.55 0 0 0 0.49 -0.34c0.07 -0.15 0.23 -0.55 0.25 -0.59a11.17 11.17 0 0 0 0.49 -1.3 2.71 2.71 0 0 0 0.09 -1.11 0.59 0.59 0 0 0 -0.34 -0.44 4.71 4.71 0 0 0 -0.66 -0.13l-2 -0.19a0.28 0.28 0 0 0 -0.32 0.25 0.29 0.29 0 0 0 0.24 0.32l1.89 0.57 0.15 0c0 0.14 -0.06 0.29 -0.09 0.44 -0.12 0.47 -0.27 0.93 -0.37 1.29Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m18.71 12.05 -0.09 0.15a2.08 2.08 0 0 0 -0.19 -0.23l-1.57 -1.45a0.33 0.33 0 0 0 -0.46 0.46l1.41 1.67a5.31 5.31 0 0 0 0.38 0.46 0.67 0.67 0 0 0 0.35 0.2 0.6 0.6 0 0 0 0.43 -0.09 5.42 5.42 0 0 0 0.43 -0.34c0.22 -0.18 0.43 -0.36 0.64 -0.56s0.38 -0.4 0.57 -0.61c0 0 0.31 -0.37 0.39 -0.51a0.57 0.57 0 0 0 -0.05 -0.72c-0.44 -0.36 -0.86 -0.72 -1.27 -1.1s-0.54 -0.51 -0.81 -0.78a0.29 0.29 0 0 0 -0.4 0 0.3 0.3 0 0 0 0 0.41c0.28 0.4 0.57 0.77 0.88 1.15s0.42 0.51 0.64 0.76l-0.15 0.1Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M15.08 15.8a0.33 0.33 0 0 0 0.41 0.52c2.89 -1.7 2.2 -1.19 2.45 -1.42a0.59 0.59 0 0 0 0.19 -0.34 0.57 0.57 0 0 0 -0.13 -0.46 6.23 6.23 0 0 0 -0.56 -0.6A16.32 16.32 0 0 0 16 12.36a0.3 0.3 0 0 0 -0.41 0 0.29 0.29 0 0 0 0 0.41l1.21 1.54 -0.27 0.21Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M4.42 15.19a0.43 0.43 0 0 0 0.34 0.32 1.3 1.3 0 0 0 0.44 0c0.26 0 0.54 -0.14 0.75 -0.18 0.43 -0.11 0.88 -0.17 1.32 -0.27a5.69 5.69 0 0 0 0.59 -0.16 7.54 7.54 0 0 0 0.81 -0.27 0.66 0.66 0 0 0 0.33 -0.52 2.87 2.87 0 0 0 0 -0.76c-0.1 -0.49 -0.54 -1.9 -0.67 -2.31a4.6 4.6 0 0 0 -0.23 -0.63 0.57 0.57 0 0 0 -0.26 -0.26 1 1 0 0 0 -0.56 0 6.66 6.66 0 0 0 -0.8 0.28c-2.84 1.09 -2.89 0.66 -2.81 1.08l0.65 3.09s0.05 0.4 0.1 0.59Zm2.26 -3.95c0.13 0 0.33 -0.11 0.53 -0.16l0.07 0a3 3 0 0 0 0.12 0.3c0.09 0.33 0.46 1.65 0.55 2.05a2.79 2.79 0 0 1 0.07 0.38 3.67 3.67 0 0 1 -0.45 0.06l-1.85 0.54 -0.61 0.2c-0.05 -0.11 -0.12 -0.22 -0.12 -0.24l-0.67 -2.43Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M2.88 8.84a0.44 0.44 0 0 0 0.34 0.33 1.15 1.15 0 0 0 0.45 0A6.18 6.18 0 0 0 4.41 9c0.44 -0.1 0.88 -0.16 1.32 -0.26 0.2 -0.05 0.4 -0.1 0.6 -0.17 0 0 0.6 -0.17 0.81 -0.27a0.62 0.62 0 0 0 0.36 -0.52A2.88 2.88 0 0 0 7.44 7c-0.11 -0.48 -0.55 -1.9 -0.68 -2.3a6.1 6.1 0 0 0 -0.22 -0.63 0.57 0.57 0 0 0 -0.27 -0.27 1 1 0 0 0 -0.56 0 5.82 5.82 0 0 0 -0.79 0.29C2.08 5.14 2 4.71 2.1 5.14l0.65 3.09s0.08 0.46 0.13 0.61Zm2.26 -3.95 0.53 -0.15 0.07 0c0 0.12 0.11 0.25 0.12 0.29 0.09 0.33 0.46 1.65 0.55 2.05a2.66 2.66 0 0 1 0.07 0.39c-0.19 0 -0.42 0 -0.45 0.06L4.19 8l-0.62 0.2c0 -0.11 -0.12 -0.22 -0.12 -0.23l-0.67 -2.39Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-account" viewBox="-4 -4 32 32"><g>
+ <path d="M18.33 20a0.35 0.35 0 0 0 0.35 -0.34 10.26 10.26 0 0 0 -0.22 -2.9 8.42 8.42 0 0 0 -0.36 -1.21 7.92 7.92 0 0 0 -0.54 -1.14 6 6 0 0 0 -1.92 -2 4.54 4.54 0 0 0 1.53 -3.5 7.58 7.58 0 0 0 -0.23 -2.56 4.49 4.49 0 0 0 -0.88 -1.53 0.34 0.34 0 0 0 -0.49 0 0.35 0.35 0 0 0 -0.05 0.49 3.53 3.53 0 0 1 0.77 1.67 7.89 7.89 0 0 1 0 1.95 3.63 3.63 0 0 1 -2.71 3.47A5.37 5.37 0 0 1 9 11.54a2.77 2.77 0 0 1 -0.92 -1.41 4.19 4.19 0 0 1 -0.19 -1.8 5.55 5.55 0 0 1 0.86 -2.46 3.65 3.65 0 0 1 2 -1.5 7.27 7.27 0 0 1 1.94 -0.31 4.75 4.75 0 0 1 1.89 0.35 0.3 0.3 0 0 0 0.25 -0.55 5.19 5.19 0 0 0 -2.13 -0.51 8.53 8.53 0 0 0 -2.16 0.23A4.58 4.58 0 0 0 8 5.3a6.6 6.6 0 0 0 -1.18 2.86A5.17 5.17 0 0 0 7 10.48a3.85 3.85 0 0 0 1.34 2l0.22 0.14a6.23 6.23 0 0 0 -2.34 1.88 6 6 0 0 0 -0.94 1.8 7.45 7.45 0 0 0 -0.33 2 12.07 12.07 0 0 0 -0.08 1.48 1.82 1.82 0 0 0 0.17 0.76 0.32 0.32 0 0 0 0.42 0.13 0.31 0.31 0 0 0 0.13 -0.42 1.25 1.25 0 0 1 0 -0.64c0.07 -0.45 0.22 -0.93 0.28 -1.2a8.28 8.28 0 0 1 0.5 -1.69 7.87 7.87 0 0 1 0.78 -1.53A6.48 6.48 0 0 1 9.4 13.1a6.41 6.41 0 0 0 4.53 0.29 5.19 5.19 0 0 0 1.21 -0.58 6.56 6.56 0 0 1 1.59 2.5c0.24 0.55 0.46 1.12 0.65 1.69a11.51 11.51 0 0 1 0.62 2.67 0.35 0.35 0 0 0 0.33 0.33Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M0.24 6.28a0.5 0.5 0 0 0 0 0.14 0.29 0.29 0 0 0 0.31 0.18c0.38 -0.06 0.26 -0.41 0.27 -0.82a29.28 29.28 0 0 1 0.3 -3.08 4.73 4.73 0 0 1 0.24 -1.14 0.48 0.48 0 0 1 0.3 -0.28 8.85 8.85 0 0 1 1.25 -0.16A7.63 7.63 0 0 1 3.86 1l2.36 0a0.35 0.35 0 0 0 0.35 -0.33 0.35 0.35 0 0 0 -0.35 -0.35C5.43 0.28 4.66 0.13 3.87 0.08A6.36 6.36 0 0 0 2.8 0.07a7.65 7.65 0 0 0 -1.49 0.1 1.53 1.53 0 0 0 -1 0.92A4.77 4.77 0 0 0 0 2.6a22.83 22.83 0 0 0 0.18 3.21 3.73 3.73 0 0 0 0.06 0.47Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m6.29 23 -2.37 0a7.47 7.47 0 0 1 -0.92 -0.12 9 9 0 0 1 -1.26 -0.16 0.46 0.46 0 0 1 -0.29 -0.29 4.46 4.46 0 0 1 -0.25 -1.13 28.94 28.94 0 0 1 -0.26 -3.08 2.37 2.37 0 0 0 0 -0.64c0 -0.09 -0.51 -0.33 -0.6 0.14l-0.06 0.47a21.56 21.56 0 0 0 -0.2 3.21 4.77 4.77 0 0 0 0.28 1.51 1.52 1.52 0 0 0 1 0.92 7.66 7.66 0 0 0 1.49 0.11 7.79 7.79 0 0 0 1.08 0c0.79 -0.06 1.56 -0.2 2.35 -0.24a0.35 0.35 0 0 0 0 -0.7Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M17.71 1c0.79 0.05 1.58 0 2.37 0a7.47 7.47 0 0 1 0.94 0.09 9 9 0 0 1 1.26 0.16 0.47 0.47 0 0 1 0.29 0.28 4.56 4.56 0 0 1 0.25 1.14 32.83 32.83 0 0 1 0.28 3.72c0 0.09 0.51 0.32 0.6 -0.14l0.06 -0.47a21.7 21.7 0 0 0 0.16 -3.22 4.7 4.7 0 0 0 -0.28 -1.5 1.53 1.53 0 0 0 -1 -0.93 8.59 8.59 0 0 0 -1.49 -0.1 9.73 9.73 0 0 0 -1.08 0c-0.79 0.06 -1.56 0.2 -2.35 0.25a0.34 0.34 0 0 0 -0.34 0.34 0.34 0.34 0 0 0 0.33 0.38Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M23.82 18.17c0 -0.42 -0.05 -0.84 -0.4 -0.78s-0.26 0.35 -0.27 0.81a28.84 28.84 0 0 1 -0.27 3.08 4.63 4.63 0 0 1 -0.24 1.14 0.46 0.46 0 0 1 -0.3 0.28 7.6 7.6 0 0 1 -1.25 0.16 7.63 7.63 0 0 1 -0.95 0.09l-2.36 0a0.35 0.35 0 1 0 0 0.69c0.79 0.05 1.56 0.19 2.35 0.25a9.53 9.53 0 0 0 1.07 0 8.52 8.52 0 0 0 1.49 -0.1 1.55 1.55 0 0 0 1 -0.93 4.7 4.7 0 0 0 0.28 -1.5 23 23 0 0 0 -0.15 -3.19Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <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>
+ </svg>
+
+ <script>
+ let map = null;
+ </script>
+
+ <script>
+ function changeUrl(path, toAppend = false) {
+ const urlParams = new URLSearchParams(window.location.search);
+ newPathname = location.pathname.endsWith("/")
+ ? location.pathname.slice(0, -1)
+ : location.pathname;
+ while (path.slice(-3) == "/.." && toAppend) {
+ newPathname = newPathname.replace(/\/[^\/]+$/, "");
+ path = path.slice(0, -3);
+ }
+ newPath = toAppend ? `${newPathname}${path}` : `${path}`;
+ if (newPath.length == 0) {
+ newPath = "/";
+ }
+
+ history.pushState(
+ {},
+ "",
+ `${newPath}${urlParams.entries.length == 0 ? "" : "?" + urlParams.toString()}`,
+ );
+ window.dispatchEvent(new Event("popstate"));
+ return false;
+ }
+
+ function convertRemToPixels(rem) {
+ return (
+ rem *
+ parseFloat(
+ getComputedStyle(document.documentElement).fontSize,
+ )
+ );
+ }
+ </script>
+
+ <script>
+ function sfc32(a, b, c, d) {
+ return function () {
+ a |= 0;
+ b |= 0;
+ c |= 0;
+ d |= 0;
+ let t = (((a + b) | 0) + d) | 0;
+ d = (d + 1) | 0;
+ a = b ^ (b >>> 9);
+ b = (c + (c << 3)) | 0;
+ c = (c << 21) | (c >>> 11);
+ c = (c + t) | 0;
+ return (t >>> 0) / 4294967296;
+ };
+ }
+
+ function cyrb128(str) {
+ let h1 = 1779033703,
+ h2 = 3144134277,
+ h3 = 1013904242,
+ h4 = 2773480762;
+ for (let i = 0, k; i < str.length; i++) {
+ k = str.charCodeAt(i);
+ h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
+ h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
+ h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
+ h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
+ }
+ h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
+ h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
+ h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
+ h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
+ ((h1 ^= h2 ^ h3 ^ h4), (h2 ^= h1), (h3 ^= h1), (h4 ^= h1));
+ return [h1 >>> 0, h2 >>> 0, h3 >>> 0, h4 >>> 0];
+ }
+
+ var seed = cyrb128("{{ .Title }}");
+ var rand = sfc32(seed[0], seed[1], seed[2], seed[3]);
+
+ function calculateRem(remNum) {
+ return remNum * parseFloat(getComputedStyle(document.documentElement).fontSize);
+ }
+
+ const _probe = document.createElement('div');
+ _probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none';
+ document.body.appendChild(_probe);
+ const _ctx = document.createElement('canvas').getContext('2d');
+
+ function resolveColor(cssValue) {
+ // Step 1: let the DOM resolve color-mix/oklch/var to its computed form
+ _probe.style.backgroundColor = '';
+ _probe.style.backgroundColor = cssValue;
+ const computed = getComputedStyle(_probe).backgroundColor;
+ if (!computed) return [0,0,0];
+
+ // Step 2: funnel through canvas to force sRGB
+ _ctx.fillStyle = '#000';
+ _ctx.fillStyle = computed;
+ const s = _ctx.fillStyle; // "#rrggbb" or "rgba(...)"
+
+ if (s.startsWith('#')) {
+ return [
+ parseInt(s.slice(1,3),16)/255,
+ parseInt(s.slice(3,5),16)/255,
+ parseInt(s.slice(5,7),16)/255,
+ ];
+ }
+ const m = s.match(/[\d.]+/g);
+ return [+m[0]/255, +m[1]/255, +m[2]/255];
+ }
+
+ function oklchMix(c1, c2, t) {
+ // Use the browser's color-mix() to interpolate in oklch
+ return `color-mix(in oklch, ${c1} ${(1-t)*100}%, ${c2})`;
+ }
+
+ function makeMultitoneOklch(id, stops, ...vars) {
+ if (vars.length < 2) {
+ console.error('Less than 2 colors set in input');
+ return;
+ }
+
+ const root = getComputedStyle(document.body);
+ const rs = [], gs = [], bs = [];
+
+ for (let i = 0; i < vars.length - 1; i++) {
+ const c1 = root.getPropertyValue(vars[i]).trim();
+ const c2 = root.getPropertyValue(vars[i+1]).trim();
+
+ if (!c1) {
+ console.error(`CSS variable ${vars[i]} not found`);
+ return;
+ }
+ if (!c2) {
+ console.error(`CSS variable ${vars[i+1]} not found`);
+ return;
+ }
+
+ for (let i = 0; i < stops; i++) {
+ const t = i / (stops - 1);
+ const [r, g, b] = resolveColor(oklchMix(c1, c2, t));
+ rs.push(r.toFixed(4));
+ gs.push(g.toFixed(4));
+ bs.push(b.toFixed(4));
+ }
+ }
+
+ let svg = document.getElementById(id + '-svg');
+ if (svg) svg.remove();
+ document.body.insertAdjacentHTML('beforeend', `
+ <svg id="${id}-svg" width="0" height="0" style="position:absolute">
+ <filter id="${id}">
+ <feColorMatrix type="matrix" values="
+ 0.299 0.587 0.114 0 0
+ 0.299 0.587 0.114 0 0
+ 0.299 0.587 0.114 0 0
+ 0 0 0 1 0"/>
+ <feComponentTransfer color-interpolation-filters="sRGB">
+ <feFuncR type="table" tableValues="${rs.join(' ')}"/>
+ <feFuncG type="table" tableValues="${gs.join(' ')}"/>
+ <feFuncB type="table" tableValues="${bs.join(' ')}"/>
+ </feComponentTransfer>
+ </filter>
+ </svg>`);
+ }
+
+ function switchThemeDecor(theme) {
+ document.querySelectorAll(".theme-decor").forEach((e) => {
+ e.remove();
+ });
+
+ if (theme == "" || typeof theme == "undefined") {
+ theme = document.body.getAttribute("data-theme");
+ }
+
+ rem = calculateRem(1);
+ var clWidth = document.documentElement.clientWidth;
+ var clHeight = document.documentElement.clientHeight;
+
+ switch (theme) {
+ case "olive":
+ break;
+ case "lettuce":
+ break;
+ case "night":
+ for (i = 0; i < 25; i++) {
+ let star = document.createElement("div");
+ star.append("*");
+ star.classList.add(
+ "night-star",
+ "theme-decor",
+ "z-0",
+ "absolute",
+ );
+ const rot = rand() * 90;
+ const animDuration = rand() * 10 + 3;
+ const sz = Math.floor(rand() * 8) + 12;
+ const x = Math.floor(rand() * clWidth - 1.42 * sz); // 1.42 ~ sqrt(2)
+ const y = Math.floor(rand() * clHeight * 0.8);
+ star.style.transform = `translateX(${x}px) translateY(${y}px) rotate(${rot}deg)`;
+ star.style.animationDuration = `${animDuration}s`;
+ star.style.fontSize = `${sz}px`;
+ document.body.append(star);
+ }
+ break;
+ case "ram":
+ const frameCenters = new Array(4);
+ for (i = 1; i <= 4; i++) {
+ let frame = document.createElement("img");
+ frame.src = `{{ .StaticStorage.BaseUrl }}/themes/ram/ram-frame${i}.webp`;
+ frame.classList.add(
+ "ram-frame",
+ "theme-decor",
+ "z-0",
+ "absolute",
+ );
+ let x, y;
+ outerLoop: while (true) {
+ x = Math.floor(rand() * clWidth - 22.64 * rem) + 11.32 * rem; // 11.32 ~ 8 * sqrt(2)
+ y = Math.floor(rand() * clHeight - 22.64 * rem) + 11.32 * rem;
+ for (j = 0; j < i - 1; j++) {
+ const xd = frameCenters[j].x - x;
+ const yd = frameCenters[j].y - y;
+ if (
+ Math.sqrt(xd * xd + yd * yd) <
+ 23 * rem
+ ) {
+ continue outerLoop;
+ }
+ }
+ break;
+ }
+ frameCenters[i - 1] = { x: x, y: y };
+ const rot = rand() * 90 - 45;
+ frame.style.transform = `translateX(${x}px) translateY(${y}px) rotate(${rot}deg)`;
+ document.body.append(frame);
+ }
+ break;
+ case "lilac":
+ break;
+ }
+ }
+
+ 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);
+ switchThemeDecor(theme);
+ switchColorScheme(matchMedia('(prefers-color-scheme: dark)').matches);
+ }
+
+ const savedTheme = localStorage.getItem("theme") || "lilac";
+ switchTheme(savedTheme);
+
+ function switchColorScheme(isNightMode) {
+ if (isNightMode) {
+ makeMultitoneOklch('multitone', 4, '--color-background-dark', '--color-accent-light', '--color-background-light');
+ } else {
+ makeMultitoneOklch('multitone', 4, '--color-background-light', '--color-accent-light', '--color-background-dark');
+ }
+ }
+
+ const mq = matchMedia('(prefers-color-scheme: dark)');
+ switchColorScheme(mq.matches);
+ mq.addEventListener('change', (e) => switchColorScheme(e.matches));
+ </script>
+
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/imagesloaded/5.0.0/imagesloaded.pkgd.min.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/packery/3.0.0/dist/packery.pkgd.min.js"></script>
+
+ <script>
+ // Enable fitWidth-like attribute for Packery. Source: https://codepen.io/desandro/pen/kVmLYz
+ var __resetLayout = Packery.prototype._resetLayout;
+ Packery.prototype._resetLayout = function () {
+ __resetLayout.call(this);
+ var parentSize = getSize(this.element.parentNode);
+ var colW = this.columnWidth + this.gutter;
+ this.fitWidth =
+ Math.floor((parentSize.innerWidth + this.gutter) / colW) *
+ colW;
+ this.packer.width = this.fitWidth;
+ this.packer.height = Number.POSITIVE_INFINITY;
+ this.packer.reset();
+ };
+
+ Packery.prototype._getContainerSize = function () {
+ var emptyWidth = 0;
+ for (var i = 0, len = this.packer.spaces.length; i < len; i++) {
+ var space = this.packer.spaces[i];
+ if (
+ space.y === 0 &&
+ space.height === Number.POSITIVE_INFINITY
+ ) {
+ emptyWidth += space.width;
+ }
+ }
+
+ return {
+ width: this.fitWidth - this.gutter - emptyWidth,
+ height: this.maxY - this.gutter,
+ };
+ };
+
+ Packery.prototype.needsResizeLayout = function () {
+ return true;
+ };
+ </script>
+
+ <div id="general-page-top-embeds" class="flex">{{ .RenderedTopEmbeds }}</div>
+ <div
+ id="general-page-top-embeds-trigger"
+ hx-get="/api/v1/general-page/top-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}"
+ hx-trigger="popstate from:window"
+ hx-target="#general-page-top-embeds"
+ hx-swap="innerHTML"
+ ></div>
+
+ <script>
+ const clientTimeZone =
+ Intl.DateTimeFormat().resolvedOptions().timeZone;
+ </script>
+
+ <div class="flex flex-col md:flex-row w-full lg:w-11/12 xl:w-10/12 2xl:w-9/12 h-full @container/main">
+ <nav
+ id="sidebar"
+ aria-label="Main navigation"
+ class="flex flex-row w-full h-24 md:flex-col md:w-24 md:h-full bg-paper bg-background shadow-elevation-6 z-2 shrink-0"
+ >
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="return changeUrl('/..', true);"
+ href="../"
+ id="sidebar-back-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-back"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="return changeUrl('/{{ .Lang }}');"
+ href="/{{ .Lang }}"
+ id="sidebar-home-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-logo"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="return changeUrl('/{{ .Lang }}/blog');"
+ href="/{{ .Lang }}/blog"
+ id="sidebar-blog-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-newspaper"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ href="/{{ .Lang }}/map"
+ id="sidebar-map-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-map"/></svg>
+ </a>
+ <div
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="toggleThemeWheel()"
+ id="sidebar-theme-button"
+ draggable="false"
+ >
+ <svg class="sidebar-theme-button-content" viewBox="0 0 24 24"><use href="#icon-palette"/></svg>
+ </div>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="return changeUrl('/{{ .Lang }}/user');"
+ href="/{{ .Lang }}/user"
+ id="sidebar-user-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-account"/></svg>
+ </a>
+ <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>
+ <script>
+ sidebarHomeButton = document.getElementById(
+ "sidebar-home-button",
+ );
+ sidebarMapButton =
+ document.getElementById("sidebar-map-button");
+ sidebarBlogButton = document.getElementById(
+ "sidebar-blog-button",
+ );
+ sidebarBackButton = document.getElementById(
+ "sidebar-back-button",
+ );
+ sidebarUserButton = document.getElementById(
+ "sidebar-user-button",
+ );
+
+ function updateSidebar() {
+ sidebarHomeButton.classList.remove("active");
+ sidebarMapButton.classList.remove("active");
+ sidebarBlogButton.classList.remove("active");
+ sidebarBackButton.classList.remove("active");
+ sidebarUserButton.classList.remove("active");
+ if (
+ location.pathname == "" ||
+ location.pathname == "/"
+ ) {
+ sidebarHomeButton.classList.add("hidden");
+ sidebarMapButton.classList.add("hidden");
+ sidebarBlogButton.classList.add("hidden");
+ sidebarBackButton.classList.add("hidden");
+ sidebarUserButton.classList.add("hidden");
+ } else {
+ sidebarHomeButton.classList.remove("hidden");
+ sidebarMapButton.classList.remove("hidden");
+ sidebarBlogButton.classList.remove("hidden");
+ sidebarBackButton.classList.remove("hidden");
+ sidebarUserButton.classList.remove("hidden");
+ lang = location.pathname.split("/")[1];
+ sidebarHomeButton.setAttribute("href", `/${lang}`);
+ sidebarHomeButton.setAttribute(
+ "onclick",
+ `return changeUrl('/${lang}', false);`,
+ );
+ if (location.pathname == `/${lang}`) {
+ sidebarHomeButton.classList.add("active");
+ }
+ sidebarMapButton.setAttribute(
+ "href",
+ `/${lang}/map`,
+ );
+ sidebarBlogButton.setAttribute(
+ "href",
+ `/${lang}/blog`,
+ );
+ sidebarBlogButton.setAttribute(
+ "onclick",
+ `return changeUrl('/${lang}/blog', false);`,
+ );
+ if (location.pathname.startsWith(`/${lang}/blog`)) {
+ sidebarBlogButton.classList.add("active");
+ }
+ sidebarUserButton.setAttribute(
+ "href",
+ `/${lang}/user`,
+ );
+ sidebarUserButton.setAttribute(
+ "onclick",
+ `return changeUrl('/${lang}/user', false);`,
+ );
+ if (location.pathname.startsWith(`/${lang}/user`)) {
+ sidebarUserButton.classList.add("active");
+ }
+ }
+ }
+ window.addEventListener("popstate", updateSidebar);
+ window.addEventListener("load", updateSidebar, {
+ once: true,
+ });
+ </script>
+ </nav>
+
+ <div
+ class="flex flex-1 min-h-0 z-1 bg-paper bg-background shadow-elevation-3 @container/body"
+ >
+ <div
+ class="bg-paper bg-background-dark border-r-[0.25rem] border-dashed border-main-hard"
+ ></div>
+
+ <div
+ class="max-h-full max-w-full flex flex-col grow bg-paper bg-background-dark relative md:pr-4"
+ >
+ <header
+ id="general-page-header"
+ class="max-xs:hidden [@media(max-height:32rem)]:hidden pt-4 flex flex-col ml-8 basis-8"
+ >{{ .RenderedHeader }}</header>
+ <div
+ id="general-page-header-trigger"
+ hx-get="/api/v1/general-page/header{{ if .QueryString }}?{{ .QueryString }}{{ end }}"
+ hx-trigger="popstate from:window"
+ hx-target="#general-page-header"
+ hx-swap="innerHTML"
+ ></div>
+
+ <hr
+ class="max-xs:hidden [@media(max-height:32rem)]:hidden border-t-[0.5rem] border-dotted border-main-hard mb-2"
+ />
+
+ <main
+ id="general-page-body"
+ class="relative flex-1 overflow-y-auto @container-size inset-shadow-elevation-8"
+ >{{ .RenderedBody }}</main>
+ <div
+ id="general-page-body-trigger"
+ hx-get="/api/v1/general-page/body{{ if .QueryString }}?{{ .QueryString }}{{ end }}"
+ hx-trigger="popstate from:window"
+ hx-target="#general-page-body"
+ hx-swap="innerHTML"
+ hx-include="#general-page-body .htmx-exit-trigger"
+ ></div>
+
+ <footer
+ id="general-page-footer"
+ class="flex flex-row basis-4 my-1"
+ >{{ .RenderedFooter }}</footer>
+ <div
+ id="general-page-footer-trigger"
+ hx-get="/api/v1/general-page/footer{{ if .QueryString }}?{{ .QueryString }}{{ end }}"
+ hx-trigger="popstate from:window"
+ hx-target="#general-page-footer"
+ hx-swap="innerHTML"
+ ></div>
+ </div>
+
+ <div
+ class="bg-paper bg-background-dark shadow-2xl border-l-[0.25rem] border-dotted border-main-hard"
+ ></div>
+ </div>
+ </div>
+
+ <div class="grow bg-split-right"></div>
+
+ <div id="general-page-bottom-embeds" class="flex">{{ .RenderedBottomEmbeds }}</div>
+ <div
+ id="general-page-bottom-embeds-trigger"
+ hx-get="/api/v1/general-page/bottom-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}"
+ hx-trigger="popstate from:window"
+ hx-target="#general-page-bottom-embeds"
+ hx-swap="innerHTML"
+ ></div>
+
+ <script>
+ const themeWheel = document.getElementById("theme-wheel");
+ const themeButton = document.getElementById("sidebar-theme-button");
+ const themeIcons = document.querySelectorAll(".theme-icon");
+
+ themeIcons.forEach((icon) => {
+ if (icon.getAttribute("data-theme") == savedTheme) {
+ icon.classList.add("active");
+ }
+ });
+
+ function positionThemeIcons() {
+ const sliceAngle = 360 / themeIcons.length;
+
+ themeIcons.forEach((icon, index) => {
+ const startAngle = index * sliceAngle;
+ const endAngle = (index + 1) * sliceAngle;
+
+ const clipPath = createSliceClipPath(
+ startAngle,
+ endAngle,
+ convertRemToPixels(6),
+ );
+ icon.style.clipPath = clipPath;
+ });
+ }
+
+ function createSliceClipPath(startAngle, endAngle, radius) {
+ const centerX = radius;
+ const centerY = radius;
+
+ let points = `${centerX}px ${centerY}px`;
+
+ const segments = Math.max(
+ 2,
+ Math.ceil(Math.abs(endAngle - startAngle) / 5),
+ );
+ const angleStep = (endAngle - startAngle) / segments;
+
+ 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`;
+ }
+
+ points += `, ${centerX}px ${centerY}px`;
+
+ return `polygon(${points})`;
+ }
+
+ function positionThemeWheel() {
+ const buttonRect = themeButton.getBoundingClientRect();
+ const buttonCenterX = buttonRect.left + buttonRect.width / 2;
+ const buttonCenterY = buttonRect.top + buttonRect.height / 2;
+ const themeWheelRadius = convertRemToPixels(6);
+
+ const margin = 0;
+
+ let wheelX = buttonCenterX - themeWheelRadius;
+ let wheelY = buttonCenterY - themeWheelRadius;
+
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
+
+ if (wheelX < margin) {
+ wheelX = margin;
+ } else if (
+ wheelX + themeWheelRadius * 2 >
+ viewportWidth - margin
+ ) {
+ wheelX = viewportWidth - themeWheelRadius * 2 - margin;
+ }
+
+ if (wheelY < margin) {
+ wheelY = margin;
+ } else if (
+ wheelY + themeWheelRadius * 2 >
+ viewportHeight - margin
+ ) {
+ wheelY = viewportHeight - themeWheelRadius * 2 - margin;
+ }
+
+ themeWheel.style.left = wheelX + "px";
+ themeWheel.style.top = wheelY + "px";
+ }
+
+ function hideThemeWheel() {
+ themeWheel.classList.remove("active");
+ }
+
+ function showThemeWheel() {
+ positionThemeWheel();
+ positionThemeIcons();
+ themeWheel.classList.add("active");
+ }
+
+ function toggleThemeWheel() {
+ if (themeWheel.classList.contains("active")) {
+ hideThemeWheel();
+ } else {
+ showThemeWheel();
+ }
+ }
+
+ 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");
+ });
+ });
+
+ themeWheel.addEventListener("mouseleave", hideThemeWheel);
+
+ document.addEventListener("click", (e) => {
+ if (
+ !themeWheel.contains(e.target) &&
+ e.target !== themeButton &&
+ !e.target.classList.contains("sidebar-theme-button-content")
+ ) {
+ hideThemeWheel();
+ }
+ });
+ </script>
+
+ <script>
+ let decorResizeTimeout;
+ window.addEventListener("resize", function () {
+ clearTimeout(decorResizeTimeout);
+ decorResizeTimeout = setTimeout(switchThemeDecor, 300);
+ });
+ </script>
+ </body>
+</html>
diff --git a/views/messages/new-post.html b/views/messages/new-post.html
new file mode 100644
index 0000000..4e586e2
--- /dev/null
+++ b/views/messages/new-post.html
@@ -0,0 +1,19 @@
+{{ define "body" }}
+<p>{{ l $.Lang "Mail" "NewPost" "Intro" }}</p>
+<table>
+ <tr>
+ <td rowspan="3"><a href="https://{{ .ClientHost }}/{{ .Lang }}/blog/{{ .Post.FileName }}"><img src="{{ printf .PhotoStorage.Thumbnail320p.BaseUrl .Post.Metadata.Thumbnail }}"></a></td>
+ <td class="darkened" style="font-size: 24px"><a style="color: #273de1 !important;" href="https://{{ .ClientHost }}/{{ .Lang }}/blog/{{ .Post.FileName }}">{{ .Post.Metadata.Title }}</a></td>
+ </tr>
+ <tr>
+ <td class="darkened" style="font-size: 16px">{{ .Post.Metadata.ShortDescription }}</td>
+ </tr>
+ <tr>
+ <td class="darkened" style="font-size: 16px">{{ l $.Lang "Mail" "NewPost" "CapturedOn" }} {{ .Post.Metadata.ActionDate }}</td>
+ </tr>
+</table>
+{{ end }}
+
+{{ define "footer" }}
+<p>{{ .UnsubscribeFooter }}</p>
+{{ end }}
diff --git a/views/messages/verify-email.html b/views/messages/verify-email.html
new file mode 100644
index 0000000..e6fff76
--- /dev/null
+++ b/views/messages/verify-email.html
@@ -0,0 +1,10 @@
+{{ define "body" }}
+<p>{{ l $.Lang "Mail" "VerifyEmail" "Welcome" }}</p>
+<p>{{ l $.Lang "Mail" "VerifyEmail" "Intro" }}</p>
+<ol>
+ <li>{{ l $.Lang "Mail" "VerifyEmail" "GotoLink" }} <a href="https://{{ .ClientHost }}/{{ .Lang }}/user?email_code={{ .VerificationCode }}" class="outlier">&gt;&gt;&gt;</a></li>
+ <li>{{ l $.Lang "Mail" "VerifyEmail" "InputCode" }} <span class="outlier">{{ .VerificationCode }}</span><span></li>
+</ol>
+<p>{{ l $.Lang "Mail" "VerifyEmail" "IfRandom" }}</p>
+<a href="https://{{ .ClientHost }}" class="outlier">{{ .ClientHost }}</a>
+{{ end }} \ No newline at end of file
diff --git a/views/pages/blog-catalogue.html b/views/pages/blog-catalogue.html
new file mode 100644
index 0000000..ca8f578
--- /dev/null
+++ b/views/pages/blog-catalogue.html
@@ -0,0 +1,239 @@
+{{ define "body" }}
+<!-- Streamline Icons: https://streamlinehq.com -->
+<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
+ <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 md:flex-row flex-col text-base h-full">
+ <div class="relative flex shrink-0 w-full max-h-[30%] md:min-w-1/10 md:max-w-1/4 md:max-h-full md:h-full md:w-fit shadow-elevation-6">
+ <div class="absolute w-full h-full 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">
+ <div class="flex flex-col bg-paper bg-background-light overflow-y-auto inset-shadow-elevation-6">
+ <fieldset>
+ <legend class="font-bold w-full text-center">{{ l $.Lang "BlogSearch" "OrderByHeader" }}</legend>
+ <div class="md:flex flex-col grid grid-cols-3 grid-rows-2 grid-flow-col">
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "TitleOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-letter-asc"/></svg>
+ </label>
+ </div>
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "TitleOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-letter-desc"/></svg>
+ </label>
+ </div>
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "ActionDateOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-asc"/></svg>
+ </label>
+ </div>
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "ActionDateOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-desc"/></svg>
+ </label>
+ </div>
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "PublicationDateOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-asc"/></svg>
+ </label>
+ </div>
+ <div class="m-1">
+ <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 $.Lang "BlogSearch" "PublicationDateOrdered" }}
+ <svg viewBox="0 0 24 24" class="h-8"><use href="#icon-arrange-number-desc"/></svg>
+ </label>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset class="mt-1">
+ <legend class="font-bold w-full text-center">{{ l $.Lang "BlogSearch" "TagsHeader" }}</legend>
+ <div class="md:flex flex-col 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 $.Lang "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>
+ </fieldset>
+ </div>
+ <hr class="border-t-[0.375rem] border-dotted border-main-hard my-2 mx-auto w-24">
+ <div class="flex flex-row p-0.5 rounded-1 h-12">
+ <button type="button" onclick="defaultSearchParams(); cleanHrefParams();" class="accent-button grow h-full">
+ <svg class="h-full mx-auto" viewBox="0 0 24 24"><use href="#icon-camera-settings-flip"/></svg>
+ </button>
+ <button type="submit" onclick="setHrefParams();" class="accent-button grow h-full">
+ <svg class="h-full mx-auto" viewBox="0 0 24 24"><use href="#icon-search-magnifier"/></svg>
+ </button>
+ </div>
+ </form>
+ </div>
+
+ <div class="relative flex grow h-full">
+ <div class="absolute w-full h-full inset-0 inset-shadow-elevation-6 pointer-events-none z-20"></div>
+ <div hx-get="/api/v1/blog-search" hx-vals='js:{lang: "{{ .Lang }}", tz: clientTimeZone, highlight: "{{ .PreviousBlogPage }}"}' 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>
+ function selectAll() {
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const selectAllCheckbox = tagsContainer.querySelector('#tagsAllCheckbox');
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]:not([id="tagsAllCheckbox"])');
+ checkboxes.forEach(checkbox => {
+ checkbox.checked = selectAllCheckbox.checked;
+ });
+ });
+ }
+
+ function contextAll() {
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const selectAllCheckbox = tagsContainer.querySelector('#tagsAllCheckbox');
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]:not([id="tagsAllCheckbox"])');
+ var areAllChecked = true;
+ checkboxes.forEach(checkbox => {
+ if (!checkbox.checked) areAllChecked = false;
+ });
+ selectAllCheckbox.checked = areAllChecked;
+ });
+ }
+
+ function defaultSearchParams() {
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]');
+ checkboxes.forEach(checkbox => {
+ checkbox.checked = true;
+ });
+ const sortRadio = tagsContainer.querySelector('#sortPublicationDateDesc');
+ sortRadio.checked = true;
+ });
+ }
+
+ function cleanHrefParams() {
+ const url = new URL(window.location.href);
+ url.search = '';
+
+ window.history.pushState({}, '', url.toString());
+ }
+
+ function setHrefParams() {
+ const url = new URL(window.location.href);
+ url.search = '';
+
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]');
+ checkboxes.forEach(checkbox => {
+ if (checkbox.checked)
+ url.searchParams.append('tags[]', checkbox.value);
+ });
+ const sortRadio = tagsContainer.querySelector('input[type="radio"]:checked');
+ url.searchParams.set('sort', sortRadio.value);
+ });
+
+ window.history.pushState({}, '', url.toString());
+ }
+
+ function pickedTagSetHrefParams(tag) {
+ const url = new URL(window.location.href);
+ url.searchParams.delete('tags[]');
+ url.searchParams.set('tags[]', tag);
+
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]');
+ checkboxes.forEach(checkbox => {
+ checkbox.checked = false;
+ });
+ chosenCheckbox = tagsContainer.querySelector(`#tag${tag}Checkbox`);
+ chosenCheckbox.checked = true;
+ });
+
+ window.history.pushState({}, '', url.toString());
+ }
+
+ 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') {
+ contextAll();
+
+ const tagsContainers = document.querySelectorAll('form.tags-list');
+ tagsContainers.forEach(tagsContainer => {
+ const checkboxes = tagsContainer.querySelectorAll('input[type="checkbox"]');
+ anyChecked = false;
+ checkboxes.forEach(checkbox => {
+ anyChecked = checkbox.checked ? true : anyChecked;
+ });
+ if (!anyChecked) {
+ const selectAllCheckbox = tagsContainer.querySelector('#tagsAllCheckbox');
+ selectAllCheckbox.checked = true;
+ selectAll();
+ }
+ });
+ }
+ }, {once: true});
+</script>
+{{ end }}
diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html
new file mode 100644
index 0000000..3d3c623
--- /dev/null
+++ b/views/pages/blog-page.html
@@ -0,0 +1,59 @@
+{{ define "body" }}
+<input class="htmx-exit-trigger" type="hidden" name="codename" value="{{ .Codename }}">
+<div class="relative bg-paper bg-background-light flex flex-col py-4 overflow-y-auto">
+ <div class="flex flex-col sm:flex-row h-[30cqb] sm:h-[15cqb] shadow-elevation-6">
+ <div class="grow shrink-2 flex-1 overflow-y-auto -mt-4 z-1 shadow-elevation-3">
+ <div class="multitone min-h-full" style="--multitone-bg: url({{ printf $.PhotoStorage.Thumbnail560p.BaseUrl .Thumbnail }});">
+ <div class="ml-8 py-4">
+ <h1 class="max-xs:flex flex-row content-center [@media(max-height:32rem)]:block hidden font-gentium text-2xl font-bold italic text-main-hard tracking-[.0125rem] mb-1">
+ <div hx-get="/api/v1/like" hx-target="this" hx-swap="outerHTML" hx-trigger="load"></div>
+ {{ .Title }}
+ </h1>
+ <p class="block grow text-lg font-gentium text-secondary">
+ <b>{{ l $.Lang "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 $.Lang "Metadata" "Action" }}</b>: {{ .ActionDate }}</p>
+ <p class="block grow text-md font-gentium font-thin text-main-hard">{{ .ShortDescription }}</p>
+ </div>
+ </div>
+ </div>
+ <hr class="block sm:hidden border-t-[0.1875rem] bg-paper bg-background-dark border-dotted border-main-hard w-full">
+ {{- if .Medley }}
+ <div class="overflow-y-auto grow-2 shrink-0 flex-1 bg-paper bg-background-dark shadow-elevation-3 sm:-mt-4 z-2">
+ <h2 class="text-2xl font-gentium font-extrabold text-main-hard tracking-[.0125rem] ml-2 mb-2 border-b-[0.25rem] border-dotted w-fit">
+ {{ l .Lang "Medleys" .Medley }}
+ </h2>
+ <div hx-get="/api/v1/blog-search" hx-vals='js:{lang: "{{ .Lang }}", tz: clientTimeZone, medley: "{{ .Medley }}", sort: "medley", hideTags: true, hidePublishedTime: true, highlight: "{{ .Codename }}"}' hx-target="this" hx-swap="innerHTML" hx-trigger="load"
+ class="grow flex flex-col pr-2">
+ Loading...
+ </div>
+ </div>
+ {{- end }}
+ </div>
+ <hr class="block border-t-[0.375rem] w-24 mx-auto my-4 border-dotted border-main-hard">
+ <article class="px-8 flex flex-col">
+ {{ .ParsedMarkdown }}
+ </article>
+{{- if .MapLocationX }}
+ <hr class="border-t-[0.375rem] border-dotted border-main-hard my-2 w-24 mx-auto">
+ <div id="map-outer-container" class="relative p-1 flex-none mx-auto w-[80%] lg:w-[60%] h-[30dvh] md:h-[40dvh]"
+ hx-get="/api/v1/map" hx-vals='{"lang": "{{ .Lang }}", "codename": "{{ .Codename }}", "zoom": 8}' hx-target="this" hx-swap="innerHTML" hx-trigger="load">
+ </div>
+ <hr class="border-t-[0.375rem] border-dotted border-main-hard my-2 w-24 mx-auto">
+
+ <script>
+ var lightbox = GLightbox({
+ selector: '.glightbox',
+ moreLength: 0
+ });
+ </script>
+{{- end }}
+</article>
+{{ end }}
+
+{{ define "header" }}
+<div hx-get="/api/v1/like" hx-target="this" hx-swap="outerHTML" hx-trigger="load"></div>
+{{ end }}
diff --git a/views/pages/global-map.html b/views/pages/global-map.html
new file mode 100644
index 0000000..4d1853f
--- /dev/null
+++ b/views/pages/global-map.html
@@ -0,0 +1,370 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="description" content="{{ l $.Lang "GlobalMap" "Description" }}" />
+ <title>{{ l $.Lang "GlobalMap" "Header" }} // SAYA.UZ</title>
+ <meta property="og:title" content="{{ l $.Lang "GlobalMap" "Header" }}" />
+ <meta
+ property="og:description"
+ content="{{ l $.Lang "GlobalMap" "Description" }}"
+ />
+ <meta
+ property="og:url"
+ content="{{ .CanonicalEndpoint }}/{{ .Lang }}/map"
+ />
+ <meta property="og:type" content="site" />
+ <title>{{ l $.Lang "GlobalMap" "Header" }} // SAYA.UZ</title>
+ <link rel="canonical" href="{{ .CanonicalEndpoint }}/{{ .Lang }}/map" />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/fonts/fonts.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="icon"
+ href="/favicon.ico"
+ type="image/x-icon"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet/1.9.4/leaflet.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.css"
+ />
+ <link
+ rel="stylesheet"
+ href="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css"
+ />
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/htmx/2.0.6/htmx.min.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/leaflet/1.9.4/leaflet.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/protomaps-leaflet/5.0.0/dist/protomaps-leaflet.js"></script>
+ <script src="{{ .StaticStorage.BaseUrl }}/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
+ </head>
+
+ <body
+ data-theme="ram"
+ class="font-m-plus text-main-hard overflow-hidden bg-interlocked-hexagons h-dvh"
+ >
+ <!-- Streamline Icons: https://streamlinehq.com -->
+ <svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
+ <symbol id="icon-back" viewBox="-4 -4 32 32"><g>
+ <path d="M23.9 10.45a12.31 12.31 0 0 0 -1.15 -3.61 9.12 9.12 0 0 0 -2.29 -3A13 13 0 0 0 19 2.88c-0.81 -0.48 -1.73 -1 -2.2 -1.18a0.34 0.34 0 0 0 -0.29 0.62c0.39 0.18 1.09 0.56 1.77 1A14.8 14.8 0 0 1 20 4.38a8.27 8.27 0 0 1 2 2.81 11.57 11.57 0 0 1 1 3.37 9.88 9.88 0 0 1 -4.18 9 11.15 11.15 0 0 1 -9.82 2 20.19 20.19 0 0 1 -2 -0.68A13.23 13.23 0 0 1 5.2 20a8.59 8.59 0 0 1 -3.7 -4.66 8.84 8.84 0 0 1 0.08 -6A12.88 12.88 0 0 1 6 3.31a10.45 10.45 0 0 1 7.24 -1.72 0.3 0.3 0 0 0 0.06 -0.6 11.16 11.16 0 0 0 -7.69 1.69A13.82 13.82 0 0 0 0.71 9a9.81 9.81 0 0 0 -0.23 6.69A9.63 9.63 0 0 0 4.62 21a14.35 14.35 0 0 0 2 1 21.55 21.55 0 0 0 2.09 0.72 12.23 12.23 0 0 0 10.78 -2.27 10.81 10.81 0 0 0 4.41 -10Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ <path d="M18.68 13.8a0.29 0.29 0 0 0 0.36 -0.22 7.5 7.5 0 0 0 -0.4 -4.82 0.6 0.6 0 0 0 -0.44 -0.3 4.51 4.51 0 0 0 -0.95 0c-0.46 0 -3.32 0.39 -5.08 0.58l-0.68 0.07 0 -0.67a18.15 18.15 0 0 0 -0.16 -2.34 1.16 1.16 0 0 0 -0.15 -0.42 0.57 0.57 0 0 0 -0.46 -0.25 2.88 2.88 0 0 0 -1.27 0.41A17.24 17.24 0 0 0 6 8.49a10.89 10.89 0 0 0 -1.68 2 2.28 2.28 0 0 0 -0.41 1.33A5.09 5.09 0 0 0 5.28 14a32.9 32.9 0 0 0 4 3.68 10.06 10.06 0 0 0 1.07 0.5 0.63 0.63 0 0 0 0.55 -0.06 2 2 0 0 0 0.42 -1c0.14 -0.82 0.23 -2.12 0.28 -2.72l0.31 0c1.43 0.11 4.57 0.35 5.94 0.4a5.59 5.59 0 0 0 0.64 0 0.48 0.48 0 0 0 0.29 -0.13 0.34 0.34 0 0 0 -0.36 -0.55c0 -0.08 -0.29 0 -0.54 0 -1.36 -0.08 -4.48 -0.4 -5.9 -0.55l-0.65 -0.07a0.51 0.51 0 0 0 -0.52 0.27 34 34 0 0 1 -0.49 3.45c-0.22 -0.13 -0.49 -0.35 -0.56 -0.4a34.25 34.25 0 0 1 -3.12 -3 13.83 13.83 0 0 1 -1.29 -1.54 1.39 1.39 0 0 1 -0.35 -0.55 1.61 1.61 0 0 1 0.39 -0.84 13 13 0 0 1 2 -2.17A16.1 16.1 0 0 1 9.8 6.91l0.54 -0.3a16.11 16.11 0 0 1 0.15 1.8l0 1.19a0.5 0.5 0 0 0 0.5 0.5c0.23 0 0.71 -0.06 1.32 -0.15 1.72 -0.25 4.5 -0.74 5 -0.74 0.15 0 0.65 0.14 0.79 0a6.76 6.76 0 0 1 0.54 2 6.61 6.61 0 0 1 -0.12 2.23 0.3 0.3 0 0 0 0.16 0.36Zm-8.07 3.46c0 0.07 -0.1 0.06 -0.2 0 0.1 -0.04 0.24 -0.11 0.2 0ZM10.26 6.2l0 0.08v0.08c-0.07 -0.06 -0.13 -0.12 0 -0.16Z" fill="var(--color-main)" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-logo" role="img" viewBox="-20 -20 160 160">
+ <defs>
+ <linearGradient gradientTransform="rotate(150, 0.5, 0.5)" x1="50%" y1="0%" x2="50%" y2="100%" id="gradient">
+ <stop stop-color="var(--color-accent-deep)" stop-opacity="1" offset="0%"></stop><stop stop-color="var(--color-main)" stop-opacity="1" offset="100%"></stop>
+ </linearGradient>
+ </defs>
+ <path d="m106.155 94.45 0.005 -0.01c-6.465 16.215 -26.09 26.16 -47.235 25.525C26.5 119.965 0 92.4 0 59.53S26.38 0.005 58.925 0.005c8.965 0 17.465 2.03 25.075 5.65 0.405 -0.885 1.355 -2.72 2.255 -2.785 1.19 -0.085 1.87 0.685 2.63 1.545 0.77 0.86 2.3 2.145 2.3 2.145s6.965 -2.405 14.775 1.885c7.815 4.29 8.915 5.58 10.45 8.58 0.76 1.505 0.975 4.145 1 6.41a3.98 3.98 0 0 0 -0.35 -0.015c-2.48 0 -4.8 2.275 -4.8 5.4 0 1.315 0.41 2.48 1.075 3.39l-0.05 0.035a7.525 7.525 0 0 0 -0.66 0.05 93.52 93.52 0 0 0 -1.945 -0.71 12.65 12.65 0 0 1 -4.1 -2.36 7.01 7.01 0 0 0 -5.98 -10.56c-1.915 0 -3.65 0.78 -4.91 2.05 -2.36 -1.355 -5.87 -2.41 -12.635 -2.825l-2.035 -0.055c-11.41 0.06 -18.055 1.395 -29.895 6.505 -3.015 1.415 -6.03 3.075 -8.925 5.005 -2.115 1.5 -3.195 3.35 -3.545 5.685a6.63 6.63 0 0 0 6.15 6.865h0.210c6.35 0.3 10.195 9.95 10.315 12.485 0.02 0.25 0.02 0.115 0.015 0.4 -0.16 3.635 -1.85 6.335 -5.44 6.23a6.155 6.155 0 0 1 -4.88 -2.47c-0.315 -0.385 -0.515 -0.86 -0.795 -1.27 -3.33 -5.405 -8.66 -6.80 -13.855 -7.615 -2.19 -0.34 -5.365 -0.61 -6.55 1.25a41.4 41.4 0 0 0 -2.885 15.315c-0.1 25.18 20.205 45.59 45.13 45.59 12.875 0 26.745 -4.76 34.965 -13.5l-0.175 0.15c-8.86 7.365 -23.3 9.705 -30.135 9.705 -21.51 0 -39.09 -16.16 -39.09 -37.89 0 -6.38 1.44 -11.98 4.07 -16.8 2.475 0.915 4.735 2.415 6.4 5.11a1.2 1.2 0 0 0 0.065 0.1050c0.32 0.46 0.555 0.985 0.91 1.42 2.12 2.62 4.405 3.29 6.71 3.4h0.05c2.15 0.065 3.84 -0.6 5.12 -1.71 1.735 -1.5 2.75 -3.95 2.885 -6.91v-0.07c0.01 -0.425 0 -0.265 -0.02 -0.56 -0.12 -1.88 -1.665 -6.59 -4.53 -10.135 -1.33 -1.655 -2.935 -3.035 -4.75 -3.87l0.6 -0.37c3.78 -2.285 11.82 -4.885 22.96 -3.19 5.65 0.865 10.275 2.095 17.415 4.395 8.285 2.67 12.895 6.395 19.27 7.135 0.75 0.085 1.505 0.09 2.25 0.015 2.05 5.645 3.17 11.75 3.17 18.105 0 10.34 -2.95 19.975 -8.055 28.1zm9.735 -61.37s-0.575 1.005 -1.82 1.61c-0.515 0.25 -1.41 -0.375 -2.25 0.5 -1.795 3.63 2.58 6.66 4.615 6.575 2.04 -0.085 3.65 -2.16 3.56 -3.965 -0.085 -2.79 -4.1 -4.72 -4.1 -4.72zm1.17 -7.16c1.275 0 2.31 1.3 2.31 2.9 0 1.6 -1.035 2.9 -2.31 2.9 -1.27 0 -2.3 -1.3 -2.3 -2.9 0 -1.6 1.03 -2.9 2.3 -2.9zm-16.46 -4.755c2.46 0 4.45 2.015 4.45 4.5a4.475 4.475 0 0 1 -4.45 4.49 4.475 4.475 0 0 1 -4.45 -4.495c0 -2.48 1.995 -4.495 4.45 -4.495z" fill="url(#gradient)" stroke-width="5"></path>
+ </symbol>
+ <symbol id="icon-newspaper" viewBox="-4 -4 32 32"><g>
+ <path d="M13.3 5.15c-1.68 -0.31 -9.3 -1.08 -9.61 0.47 -0.58 2.8 -0.8 3.4 -0.8 3.76 0 0.87 1.94 1 2.81 1.14s1.94 0.29 2.92 0.4a11.4 11.4 0 0 0 3.85 -0.28c0.29 0 0.68 0 0.9 -0.34a2.66 2.66 0 0 0 0.15 -1.3c0.34 -2.77 0.4 -3 0.3 -3.34a0.67 0.67 0 0 0 -0.52 -0.51Zm-1 4.36 -1.7 0.28a30.3 30.3 0 0 1 -4.81 -0.23 6.67 6.67 0 0 1 -2 -0.28c0 -0.19 -0.09 0.74 0.29 -2.08 0 0 0.36 -1.37 0.36 -1.45 0.15 0.37 5 -0.24 7.2 0.14q0.55 0.09 1.08 0.21l0 0.46c-0.52 3.63 -0.44 2.72 -0.45 2.95Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M17.54 7a0.34 0.34 0 0 0 0.46 -0.17c0.58 -0.9 -1.81 -1.11 -3.24 -0.87a0.35 0.35 0 0 0 -0.37 0.32c-0.04 0.72 2.45 0.41 3.15 0.72Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M14.44 9.13a5 5 0 0 0 3.08 0.48c0.43 0.14 1.06 -0.56 0.19 -0.86a3.36 3.36 0 0 0 -0.6 -0.09c-0.96 -0.15 -3.11 -0.4 -2.67 0.47Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M7.78 12.72c-4.92 -0.13 -4.67 -0.09 -4.8 0.13a0.28 0.28 0 0 0 0.15 0.42c0.16 0.09 0.06 0.05 4.61 0.52a73.45 73.45 0 0 0 9.5 0 0.34 0.34 0 0 0 0 -0.68c-2.38 0 -3 -0.23 -9.46 -0.39Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M16.68 16.61c-5.44 -0.27 -3.68 -0.55 -8.64 -0.47 -0.89 0 -1.78 0.05 -2.67 0 -0.35 0 -2.17 -0.26 -2.3 -0.23a0.32 0.32 0 0 0 0 0.61c0.1 0 -0.16 0 2.25 0.44a77.28 77.28 0 0 0 7.73 0.39l1.13 0c4.08 0.01 3.37 -0.77 2.5 -0.74Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M24 10.27c-0.13 -3.52 -0.05 -2.5 -0.14 -4.86a0.44 0.44 0 0 0 -0.76 -0.28 2.72 2.72 0 0 1 -2.33 1.25 21.46 21.46 0 0 0 0.56 -2.94 0.88 0.88 0 0 0 -0.22 -0.6c-0.31 -0.3 -3 -0.21 -3.48 -0.2 -3.05 0.09 -5.71 -0.27 -9.06 -0.2 -4.62 0.1 -5.83 -0.73 -5.47 0.2a0.45 0.45 0 0 0 0.3 0.24 33.56 33.56 0 0 0 5.17 0.37c4.41 0.09 4.28 0.53 11.32 0.53l0.17 0c0 1.27 -1 3.8 -1 8.45 0 1.64 0.13 6.24 0.85 7.56a2.26 2.26 0 0 0 0.4 0.51c-3.31 1.08 -15.91 0.5 -17.78 -0.21 -0.32 -0.12 -0.77 -0.16 -0.9 -0.36 -1.17 -1.73 0.06 -9.79 0.28 -11.81a27.82 27.82 0 0 1 0.67 -3.53A7.91 7.91 0 0 0 3 2.69a0.31 0.31 0 0 0 -0.58 0c0.09 -0.1 -0.89 2.79 -1.25 5.18C0.72 10.49 -0.86 18.1 0.61 20.33c0.4 0.61 1 0.63 1.45 0.81a11.09 11.09 0 0 0 3.14 0.51c2.08 0.13 15.3 0.61 16.69 -1.21 2.16 -2.82 2.2 -6.66 2.11 -10.17ZM21.3 20a1 1 0 0 1 -0.8 -0.58c-0.61 -1.2 -0.59 -5.82 -0.53 -7.19A33.39 33.39 0 0 1 20.61 7a3.11 3.11 0 0 0 1.24 -0.07 3.52 3.52 0 0 0 1.09 -0.52C22.61 13 23.52 16.56 21.3 20Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M21.43 8.91c-0.57 -0.41 -0.55 1 -0.68 2.15a19.8 19.8 0 0 0 0.06 4.15 0.34 0.34 0 0 0 0.68 0 20.13 20.13 0 0 0 0.31 -4.15c-0.28 -2.29 -0.19 -2.06 -0.37 -2.15Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-map" viewBox="-4 -4 32 32"><g>
+ <path d="M18.47 13.42a0.31 0.31 0 0 0 0.41 0.11 0.29 0.29 0 0 0 0.11 -0.41C18 11.2 16.38 9.18 15.71 7A5.35 5.35 0 0 1 16 2.86a3.54 3.54 0 0 1 2.4 -1.53 4.18 4.18 0 0 1 2.93 0.18 3.19 3.19 0 0 1 1.16 1.2A3.59 3.59 0 0 1 23 4.34a6.78 6.78 0 0 1 -0.53 2.76 34 34 0 0 1 -2.1 4l-1.11 1.62a0.35 0.35 0 0 0 0.1 0.48 0.34 0.34 0 0 0 0.47 -0.09L21 11.45a33.28 33.28 0 0 0 2.3 -4 7.51 7.51 0 0 0 0.7 -3.14 4.62 4.62 0 0 0 -0.6 -2.14A4.23 4.23 0 0 0 21.86 0.52 5.38 5.38 0 0 0 18.08 0.2 4.66 4.66 0 0 0 15 2.38a6.25 6.25 0 0 0 -0.12 4.94c0.74 2.18 2.44 4.18 3.59 6.1Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M18.36 6.15C21 7 21 4.49 20 3.73c-1.39 -1.32 -3.48 1.84 -1.64 2.42Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M8.79 9a1.43 1.43 0 0 1 -0.37 0.77c-0.31 0.31 -0.89 0.45 -1.26 0.74a1.36 1.36 0 0 0 -0.49 0.85 3.43 3.43 0 0 0 0.21 1.58 8 8 0 0 1 0.55 1.79 1 1 0 0 1 -0.3 0.86 1.51 1.51 0 0 1 -0.65 0.35 1.9 1.9 0 0 1 -0.81 0.08 8.41 8.41 0 0 0 -1.15 -0.14 1.73 1.73 0 0 0 -0.94 0.23 1.93 1.93 0 0 0 -0.67 0.8c-0.15 0.31 -0.28 0.67 -0.44 1s0 1.08 0.51 0.57a2.55 2.55 0 0 0 0.51 -0.86 1.53 1.53 0 0 1 0.51 -0.76 0.87 0.87 0 0 1 0.48 -0.06 6.7 6.7 0 0 1 1 0.21 3.13 3.13 0 0 0 1.25 0 2.54 2.54 0 0 0 1.18 -0.59 2.11 2.11 0 0 0 0.66 -1.77 6.48 6.48 0 0 0 -0.53 -1.77 3.24 3.24 0 0 1 -0.37 -1.37 0.52 0.52 0 0 1 0.24 -0.34A6.52 6.52 0 0 0 9 10.31a2.07 2.07 0 0 0 0.48 -1.25 4.3 4.3 0 0 0 -0.07 -1c-0.26 -0.34 -0.71 -0.22 -0.63 0.07a2.49 2.49 0 0 1 0.01 0.87Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ <path d="m23.83 20.17 -0.44 -2.79 -0.67 -5.76a0.3 0.3 0 0 0 -0.6 0.08l0.54 5.77 0.34 2.77c0 0.17 0.06 0.38 0.08 0.58a0.5 0.5 0 0 1 0 0.18 0.63 0.63 0 0 1 -0.26 0.22c-0.16 0.09 -0.34 0.15 -0.49 0.22 -0.33 0.13 -0.67 0.25 -1 0.36 -0.52 0.16 -1 0.28 -1.58 0.41 -0.84 0.2 -1.7 0.45 -2.57 0.61a7.67 7.67 0 0 1 -1.65 0.14 4.8 4.8 0 0 1 -1.13 -0.21c-0.39 -0.11 -4.47 -1.38 -6 -1.81a8.17 8.17 0 0 0 -2.35 -0.33 10.19 10.19 0 0 0 -2.33 0.32 5.3 5.3 0 0 0 -1.21 0.27l0 -0.21c0 -0.22 0 -0.45 -0.06 -0.67 0 -0.47 -0.28 -2.86 -0.33 -3.26 -0.3 -2.29 -0.7 -4.78 -0.88 -7.09l-0.08 -1.36A9.09 9.09 0 0 1 1 7.34 0.4 0.4 0 0 1 1.14 7a2.44 2.44 0 0 1 1.07 -0.33 12.47 12.47 0 0 1 1.94 0A12.63 12.63 0 0 1 6 6.88a14.23 14.23 0 0 1 1.81 0.49c0.24 0.08 2.74 0.92 3.32 1.09a22.06 22.06 0 0 0 2.3 0.6 0.35 0.35 0 1 0 0.12 -0.68 20.56 20.56 0 0 1 -2.2 -0.61c-1.28 -0.42 -2.6 -0.91 -3.28 -1.15a15.84 15.84 0 0 0 -1.9 -0.55 13.16 13.16 0 0 0 -2 -0.28 12.94 12.94 0 0 0 -2.08 0 3.2 3.2 0 0 0 -1.47 0.44A1.27 1.27 0 0 0 0 7a5.65 5.65 0 0 0 0.19 1.71L0.22 10c0.15 2.33 0.63 4.62 0.9 6.93 0.07 0.57 0.13 1.13 0.16 1.7s0 1.12 0 1.69a7 7 0 0 0 0.07 0.79 3.24 3.24 0 0 0 0.16 0.8 1.51 1.51 0 0 0 0.27 0.42 0.76 0.76 0 0 0 0.63 0.22A11.69 11.69 0 0 0 4 22.06a8.45 8.45 0 0 1 2.06 -0.29 7 7 0 0 1 2 0.28l4.16 1.13c0.62 0.2 1.22 0.43 1.84 0.6a5.67 5.67 0 0 0 1.37 0.21 8 8 0 0 0 1.88 -0.19c0.89 -0.18 1.76 -0.47 2.6 -0.69 0.56 -0.14 1.1 -0.29 1.63 -0.47 0.37 -0.12 0.73 -0.26 1.08 -0.41a4.65 4.65 0 0 0 0.7 -0.36 1.35 1.35 0 0 0 0.45 -0.5 1 1 0 0 0 0.1 -0.47 6.79 6.79 0 0 0 -0.04 -0.73Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M13.27 21.36a3 3 0 0 0 -0.93 -2 8.73 8.73 0 0 1 -0.87 -0.85 0.56 0.56 0 0 1 -0.11 -0.62 1.94 1.94 0 0 1 0.76 -0.83 3 3 0 0 1 1.12 -0.51 8.59 8.59 0 0 0 2.07 -0.43 1.88 1.88 0 0 0 1 -1.23l0.12 -0.7a0.3 0.3 0 0 0 -0.29 -0.32 0.29 0.29 0 0 0 -0.31 0.29l-0.15 0.5a1.21 1.21 0 0 1 -0.71 0.71 7.5 7.5 0 0 1 -1.89 0.14 4 4 0 0 0 -1.62 0.59 3 3 0 0 0 -1.19 1.35 1.56 1.56 0 0 0 0.12 1.5 6.3 6.3 0 0 0 1.26 1.15 2.41 2.41 0 0 1 0.8 1.19 0.92 0.92 0 0 1 0 0.52c0 0.33 0.6 0.64 0.75 0.14a1.84 1.84 0 0 0 0.07 -0.59Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-palette" viewBox="-4 -4 32 32"><g>
+ <path d="M10 19.26a0.32 0.32 0 0 0 0 0.59 5.85 5.85 0 0 0 1.62 0.42 1 1 0 0 0 0.93 -0.34 5.08 5.08 0 0 0 0.63 -1.35c0.33 -1 0.46 -2.23 0.71 -3.15 0.09 -0.34 0.2 -0.67 0.32 -1 0.28 -0.79 0.61 -1.56 0.88 -2.36 0.14 -0.4 0.27 -0.81 0.39 -1.22 0.27 -0.94 0.5 -1.9 0.78 -2.84 0.2 -0.69 0.43 -1.39 0.62 -2.1a12.59 12.59 0 0 0 0.32 -1.48 8.09 8.09 0 0 0 0.16 -1 0.83 0.83 0 0 0 -0.19 -0.58 1.68 1.68 0 0 0 -0.64 -0.41 7.51 7.51 0 0 0 -1.33 -0.37l-4.3 -0.78c-0.4 -0.1 -0.73 0.1 -0.95 0.57 -0.33 0.7 -0.42 2.14 -0.77 2.79a0.3 0.3 0 0 0 0.11 0.39 0.28 0.28 0 0 0 0.42 -0.04 18.6 18.6 0 0 0 0.77 -2.47 1.87 1.87 0 0 1 0.19 -0.4s0 -0.07 0.08 -0.06L15 3a4.45 4.45 0 0 1 1.41 0.53 5.74 5.74 0 0 1 -0.24 0.71 12.78 12.78 0 0 1 -0.32 1.36c-0.2 0.7 -0.43 1.4 -0.63 2.09l-1.1 4c-0.24 0.81 -0.54 1.58 -0.79 2.38 -0.11 0.35 -0.21 0.7 -0.3 1.07 -0.21 0.92 -0.3 2.11 -0.58 3.15a4.64 4.64 0 0 1 -0.45 1.23s-0.08 0 -0.13 0a1.89 1.89 0 0 1 -0.57 0 6.94 6.94 0 0 1 -1 -0.28 0.33 0.33 0 0 0 -0.24 0 4 4 0 0 0 0.83 -0.27 1.74 1.74 0 0 0 0.68 -0.57 0.83 0.83 0 0 0 0.14 -0.54 5.77 5.77 0 0 0 -0.17 -0.79l-0.59 -2.83c-0.22 -1.19 -0.48 -2.38 -0.76 -3.56 -0.43 -1.77 -0.91 -3.53 -1.37 -5.27A24.28 24.28 0 0 0 8 2.73 5.29 5.29 0 0 0 6.85 1a0.74 0.74 0 0 0 -0.54 -0.17 3.48 3.48 0 0 0 -0.67 0.17l-2.21 0.66A10.36 10.36 0 0 0 0.91 2.77 1.91 1.91 0 0 0 0 4a2.51 2.51 0 0 0 0.08 1c0.14 0.61 0.44 1.28 0.58 1.73L2.17 12l2.27 8a0.27 0.27 0 0 0 0.35 0.2 0.29 0.29 0 0 0 0.2 -0.35l-2 -8.1 -1.37 -5.36c-0.1 -0.38 -0.32 -0.94 -0.46 -1.47a1.93 1.93 0 0 1 -0.1 -0.79c0 -0.27 0.38 -0.45 0.74 -0.65a9.89 9.89 0 0 1 2 -0.78L6 2l0.24 0a4.41 4.41 0 0 1 0.7 1.2 21 21 0 0 1 0.8 2.55c0.49 1.72 1 3.46 1.46 5.21 0.31 1.16 0.6 2.33 0.84 3.49l0.66 2.86 0.18 0.71a1 1 0 0 1 -0.39 0.32 3.81 3.81 0 0 1 -0.91 0.32l-3.64 0.93a0.33 0.33 0 0 0 -0.24 0.39 0.32 0.32 0 0 0 0.39 0.25l3.67 -0.86a2 2 0 0 0 0.24 -0.11Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M23.73 9.93a7.66 7.66 0 0 0 -0.8 -0.88 13.75 13.75 0 0 0 -1.45 -1.31c-0.77 -0.63 -1.61 -1.25 -2.23 -1.75a0.58 0.58 0 0 0 -0.68 0.11c-0.37 0.29 -1.05 1 -1.5 1.41l-0.18 0.19 -0.08 0 -0.07 0a0.25 0.25 0 0 0 -0.17 0.1 0.27 0.27 0 0 0 0 0.4c0.07 0.07 0.32 0.12 0.62 -0.1s1.09 -1 1.55 -1.34l0.26 -0.1c0.57 0.5 1.3 1.11 2 1.71a15.9 15.9 0 0 1 1.3 1.3c0.15 0.17 1.1 0.88 0.77 1a1.06 1.06 0 0 1 -0.23 0.41c-0.15 0.2 -0.34 0.39 -0.47 0.54s-0.49 0.51 -0.74 0.76c-0.61 0.6 -1.25 1.17 -1.86 1.77 -1.47 1.51 -2.86 3.12 -4.32 4.65 -0.62 0.65 -1.24 1.29 -1.9 1.9 -0.33 0.3 -0.65 0.6 -1 0.88s-0.45 0.37 -0.68 0.54 -0.46 0.2 -0.42 0.33a1.38 1.38 0 0 1 -0.74 -0.32 7.64 7.64 0 0 1 -1.13 -1.17 0.33 0.33 0 0 0 -0.51 0.41 8.44 8.44 0 0 0 1.21 1.32 2 2 0 0 0 1.27 0.51 0.62 0.62 0 0 0 0.31 -0.1c0.15 -0.09 0.36 -0.28 0.45 -0.34 0.26 -0.18 0.51 -0.36 0.75 -0.55s0.7 -0.57 1.05 -0.86c0.7 -0.6 1.37 -1.22 2 -1.87 1.46 -1.48 2.89 -3.1 4.37 -4.58 0.6 -0.61 1.24 -1.17 1.84 -1.78 0.27 -0.27 0.53 -0.54 0.78 -0.83a5.83 5.83 0 0 0 0.71 -1 1.66 1.66 0 0 0 0.19 -0.65 1.3 1.3 0 0 0 -0.27 -0.71Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m16.85 7.71 -0.09 0h0.05Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M14.33 8.68a5.87 5.87 0 0 0 0.29 -0.75 11.92 11.92 0 0 0 0.62 -1.7 3.66 3.66 0 0 0 0.08 -1.38 0.61 0.61 0 0 0 -0.38 -0.43 4.9 4.9 0 0 0 -0.51 -0.12L12.84 4l-1.31 -0.29 -0.36 0a0.45 0.45 0 0 0 -0.47 0.28l-0.33 1.81a0.28 0.28 0 0 0 0.22 0.34 0.29 0.29 0 0 0 0.34 -0.22l0.41 -1.42 1.22 0.42 1.58 0.43h0.1a3.68 3.68 0 0 1 -0.09 0.63 12.53 12.53 0 0 1 -0.49 1.59s0 0.17 0 0.32c-0.18 -0.07 -0.43 -0.09 -0.51 -0.12 -0.37 -0.13 -0.74 -0.25 -1.12 -0.36l-1.13 -0.29a0.32 0.32 0 0 0 -0.4 0.22 0.32 0.32 0 0 0 0.22 0.4c0.36 0.12 0.72 0.24 1.07 0.38l1 0.43c0.13 0.06 0.47 0.29 0.71 0.38A0.86 0.86 0 0 0 14 9a0.57 0.57 0 0 0 0.33 -0.32Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M12.42 12.21s-0.07 0.14 -0.12 0.27l-0.71 -0.21a0.33 0.33 0 0 0 -0.4 0.24 0.32 0.32 0 0 0 0.24 0.39c0.27 0.1 0.57 0.31 0.86 0.44l0.31 0.1a0.55 0.55 0 0 0 0.49 -0.34c0.07 -0.15 0.23 -0.55 0.25 -0.59a11.17 11.17 0 0 0 0.49 -1.3 2.71 2.71 0 0 0 0.09 -1.11 0.59 0.59 0 0 0 -0.34 -0.44 4.71 4.71 0 0 0 -0.66 -0.13l-2 -0.19a0.28 0.28 0 0 0 -0.32 0.25 0.29 0.29 0 0 0 0.24 0.32l1.89 0.57 0.15 0c0 0.14 -0.06 0.29 -0.09 0.44 -0.12 0.47 -0.27 0.93 -0.37 1.29Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m18.71 12.05 -0.09 0.15a2.08 2.08 0 0 0 -0.19 -0.23l-1.57 -1.45a0.33 0.33 0 0 0 -0.46 0.46l1.41 1.67a5.31 5.31 0 0 0 0.38 0.46 0.67 0.67 0 0 0 0.35 0.2 0.6 0.6 0 0 0 0.43 -0.09 5.42 5.42 0 0 0 0.43 -0.34c0.22 -0.18 0.43 -0.36 0.64 -0.56s0.38 -0.4 0.57 -0.61c0 0 0.31 -0.37 0.39 -0.51a0.57 0.57 0 0 0 -0.05 -0.72c-0.44 -0.36 -0.86 -0.72 -1.27 -1.1s-0.54 -0.51 -0.81 -0.78a0.29 0.29 0 0 0 -0.4 0 0.3 0.3 0 0 0 0 0.41c0.28 0.4 0.57 0.77 0.88 1.15s0.42 0.51 0.64 0.76l-0.15 0.1Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M15.08 15.8a0.33 0.33 0 0 0 0.41 0.52c2.89 -1.7 2.2 -1.19 2.45 -1.42a0.59 0.59 0 0 0 0.19 -0.34 0.57 0.57 0 0 0 -0.13 -0.46 6.23 6.23 0 0 0 -0.56 -0.6A16.32 16.32 0 0 0 16 12.36a0.3 0.3 0 0 0 -0.41 0 0.29 0.29 0 0 0 0 0.41l1.21 1.54 -0.27 0.21Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M4.42 15.19a0.43 0.43 0 0 0 0.34 0.32 1.3 1.3 0 0 0 0.44 0c0.26 0 0.54 -0.14 0.75 -0.18 0.43 -0.11 0.88 -0.17 1.32 -0.27a5.69 5.69 0 0 0 0.59 -0.16 7.54 7.54 0 0 0 0.81 -0.27 0.66 0.66 0 0 0 0.33 -0.52 2.87 2.87 0 0 0 0 -0.76c-0.1 -0.49 -0.54 -1.9 -0.67 -2.31a4.6 4.6 0 0 0 -0.23 -0.63 0.57 0.57 0 0 0 -0.26 -0.26 1 1 0 0 0 -0.56 0 6.66 6.66 0 0 0 -0.8 0.28c-2.84 1.09 -2.89 0.66 -2.81 1.08l0.65 3.09s0.05 0.4 0.1 0.59Zm2.26 -3.95c0.13 0 0.33 -0.11 0.53 -0.16l0.07 0a3 3 0 0 0 0.12 0.3c0.09 0.33 0.46 1.65 0.55 2.05a2.79 2.79 0 0 1 0.07 0.38 3.67 3.67 0 0 1 -0.45 0.06l-1.85 0.54 -0.61 0.2c-0.05 -0.11 -0.12 -0.22 -0.12 -0.24l-0.67 -2.43Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M2.88 8.84a0.44 0.44 0 0 0 0.34 0.33 1.15 1.15 0 0 0 0.45 0A6.18 6.18 0 0 0 4.41 9c0.44 -0.1 0.88 -0.16 1.32 -0.26 0.2 -0.05 0.4 -0.1 0.6 -0.17 0 0 0.6 -0.17 0.81 -0.27a0.62 0.62 0 0 0 0.36 -0.52A2.88 2.88 0 0 0 7.44 7c-0.11 -0.48 -0.55 -1.9 -0.68 -2.3a6.1 6.1 0 0 0 -0.22 -0.63 0.57 0.57 0 0 0 -0.27 -0.27 1 1 0 0 0 -0.56 0 5.82 5.82 0 0 0 -0.79 0.29C2.08 5.14 2 4.71 2.1 5.14l0.65 3.09s0.08 0.46 0.13 0.61Zm2.26 -3.95 0.53 -0.15 0.07 0c0 0.12 0.11 0.25 0.12 0.29 0.09 0.33 0.46 1.65 0.55 2.05a2.66 2.66 0 0 1 0.07 0.39c-0.19 0 -0.42 0 -0.45 0.06L4.19 8l-0.62 0.2c0 -0.11 -0.12 -0.22 -0.12 -0.23l-0.67 -2.39Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-account" viewBox="-4 -4 32 32"><g>
+ <path d="M18.33 20a0.35 0.35 0 0 0 0.35 -0.34 10.26 10.26 0 0 0 -0.22 -2.9 8.42 8.42 0 0 0 -0.36 -1.21 7.92 7.92 0 0 0 -0.54 -1.14 6 6 0 0 0 -1.92 -2 4.54 4.54 0 0 0 1.53 -3.5 7.58 7.58 0 0 0 -0.23 -2.56 4.49 4.49 0 0 0 -0.88 -1.53 0.34 0.34 0 0 0 -0.49 0 0.35 0.35 0 0 0 -0.05 0.49 3.53 3.53 0 0 1 0.77 1.67 7.89 7.89 0 0 1 0 1.95 3.63 3.63 0 0 1 -2.71 3.47A5.37 5.37 0 0 1 9 11.54a2.77 2.77 0 0 1 -0.92 -1.41 4.19 4.19 0 0 1 -0.19 -1.8 5.55 5.55 0 0 1 0.86 -2.46 3.65 3.65 0 0 1 2 -1.5 7.27 7.27 0 0 1 1.94 -0.31 4.75 4.75 0 0 1 1.89 0.35 0.3 0.3 0 0 0 0.25 -0.55 5.19 5.19 0 0 0 -2.13 -0.51 8.53 8.53 0 0 0 -2.16 0.23A4.58 4.58 0 0 0 8 5.3a6.6 6.6 0 0 0 -1.18 2.86A5.17 5.17 0 0 0 7 10.48a3.85 3.85 0 0 0 1.34 2l0.22 0.14a6.23 6.23 0 0 0 -2.34 1.88 6 6 0 0 0 -0.94 1.8 7.45 7.45 0 0 0 -0.33 2 12.07 12.07 0 0 0 -0.08 1.48 1.82 1.82 0 0 0 0.17 0.76 0.32 0.32 0 0 0 0.42 0.13 0.31 0.31 0 0 0 0.13 -0.42 1.25 1.25 0 0 1 0 -0.64c0.07 -0.45 0.22 -0.93 0.28 -1.2a8.28 8.28 0 0 1 0.5 -1.69 7.87 7.87 0 0 1 0.78 -1.53A6.48 6.48 0 0 1 9.4 13.1a6.41 6.41 0 0 0 4.53 0.29 5.19 5.19 0 0 0 1.21 -0.58 6.56 6.56 0 0 1 1.59 2.5c0.24 0.55 0.46 1.12 0.65 1.69a11.51 11.51 0 0 1 0.62 2.67 0.35 0.35 0 0 0 0.33 0.33Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M0.24 6.28a0.5 0.5 0 0 0 0 0.14 0.29 0.29 0 0 0 0.31 0.18c0.38 -0.06 0.26 -0.41 0.27 -0.82a29.28 29.28 0 0 1 0.3 -3.08 4.73 4.73 0 0 1 0.24 -1.14 0.48 0.48 0 0 1 0.3 -0.28 8.85 8.85 0 0 1 1.25 -0.16A7.63 7.63 0 0 1 3.86 1l2.36 0a0.35 0.35 0 0 0 0.35 -0.33 0.35 0.35 0 0 0 -0.35 -0.35C5.43 0.28 4.66 0.13 3.87 0.08A6.36 6.36 0 0 0 2.8 0.07a7.65 7.65 0 0 0 -1.49 0.1 1.53 1.53 0 0 0 -1 0.92A4.77 4.77 0 0 0 0 2.6a22.83 22.83 0 0 0 0.18 3.21 3.73 3.73 0 0 0 0.06 0.47Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="m6.29 23 -2.37 0a7.47 7.47 0 0 1 -0.92 -0.12 9 9 0 0 1 -1.26 -0.16 0.46 0.46 0 0 1 -0.29 -0.29 4.46 4.46 0 0 1 -0.25 -1.13 28.94 28.94 0 0 1 -0.26 -3.08 2.37 2.37 0 0 0 0 -0.64c0 -0.09 -0.51 -0.33 -0.6 0.14l-0.06 0.47a21.56 21.56 0 0 0 -0.2 3.21 4.77 4.77 0 0 0 0.28 1.51 1.52 1.52 0 0 0 1 0.92 7.66 7.66 0 0 0 1.49 0.11 7.79 7.79 0 0 0 1.08 0c0.79 -0.06 1.56 -0.2 2.35 -0.24a0.35 0.35 0 0 0 0 -0.7Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M17.71 1c0.79 0.05 1.58 0 2.37 0a7.47 7.47 0 0 1 0.94 0.09 9 9 0 0 1 1.26 0.16 0.47 0.47 0 0 1 0.29 0.28 4.56 4.56 0 0 1 0.25 1.14 32.83 32.83 0 0 1 0.28 3.72c0 0.09 0.51 0.32 0.6 -0.14l0.06 -0.47a21.7 21.7 0 0 0 0.16 -3.22 4.7 4.7 0 0 0 -0.28 -1.5 1.53 1.53 0 0 0 -1 -0.93 8.59 8.59 0 0 0 -1.49 -0.1 9.73 9.73 0 0 0 -1.08 0c-0.79 0.06 -1.56 0.2 -2.35 0.25a0.34 0.34 0 0 0 -0.34 0.34 0.34 0.34 0 0 0 0.33 0.38Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M23.82 18.17c0 -0.42 -0.05 -0.84 -0.4 -0.78s-0.26 0.35 -0.27 0.81a28.84 28.84 0 0 1 -0.27 3.08 4.63 4.63 0 0 1 -0.24 1.14 0.46 0.46 0 0 1 -0.3 0.28 7.6 7.6 0 0 1 -1.25 0.16 7.63 7.63 0 0 1 -0.95 0.09l-2.36 0a0.35 0.35 0 1 0 0 0.69c0.79 0.05 1.56 0.19 2.35 0.25a9.53 9.53 0 0 0 1.07 0 8.52 8.52 0 0 0 1.49 -0.1 1.55 1.55 0 0 0 1 -0.93 4.7 4.7 0 0 0 0.28 -1.5 23 23 0 0 0 -0.15 -3.19Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ </svg>
+
+ <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);
+ }
+
+ const savedTheme = localStorage.getItem("theme") || "lilac";
+ switchTheme(savedTheme);
+ </script>
+
+ <script>
+ const clientTimeZone =
+ Intl.DateTimeFormat().resolvedOptions().timeZone;
+
+ function convertRemToPixels(rem) {
+ return (
+ rem *
+ parseFloat(
+ getComputedStyle(document.documentElement).fontSize,
+ )
+ );
+ }
+ </script>
+
+ <nav
+ id="sidebar"
+ aria-label="Main navigation"
+ class="fixed flex flex-row w-full h-24 md:flex-col md:w-24 md:h-auto bg-paper bg-background shadow-elevation-6 z-1001 shrink-0 md:rounded-br-md"
+ >
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ href="./"
+ id="sidebar-back-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-back"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ href="/{{ .Lang }}"
+ id="sidebar-home-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-logo"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ href="/{{ .Lang }}/blog"
+ id="sidebar-blog-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-newspaper"/></svg>
+ </a>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button active"
+ href="/{{ .Lang }}/map"
+ id="sidebar-map-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-map"/></svg>
+ </a>
+ <div
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ onclick="toggleThemeWheel()"
+ id="sidebar-theme-button"
+ draggable="false"
+ >
+ <svg class="sidebar-theme-button-content" viewBox="0 0 24 24"><use href="#icon-palette"/></svg>
+ </div>
+ <a
+ class="w-18 h-18 rounded-xl m-3 accent-button"
+ href="/{{ .Lang }}/user"
+ id="sidebar-user-button"
+ draggable="false"
+ >
+ <svg viewBox="0 0 24 24"><use href="#icon-account"/></svg>
+ </a>
+ <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>
+ </nav>
+
+ <div id="map-outer-container" class="bg-paper bg-background-dark flex z-10 w-full h-full"
+ hx-get="/api/v1/map" hx-vals='{"lang": "{{ .Lang }}", "codename": "{{ .Codename }}", "zoom": 4, "zoomPosition": "topright"}' hx-target="this" hx-swap="innerHTML" hx-trigger="load">
+ </div>
+
+ <script>
+ const themeWheel = document.getElementById("theme-wheel");
+ const themeButton = document.getElementById("sidebar-theme-button");
+ const themeIcons = document.querySelectorAll(".theme-icon");
+
+ themeIcons.forEach((icon) => {
+ if (icon.getAttribute("data-theme") == savedTheme) {
+ icon.classList.add("active");
+ }
+ });
+
+ function calculateVmax(percent) {
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
+
+ const largerDimension = Math.max(viewportWidth, viewportHeight);
+
+ const vmaxValue = (largerDimension / 100) * percent;
+
+ return vmaxValue;
+ }
+
+ function positionThemeIcons() {
+ const sliceAngle = 360 / themeIcons.length;
+ const themeWheelRadius = convertRemToPixels(6);
+
+ themeIcons.forEach((icon, index) => {
+ const startAngle = index * sliceAngle;
+ const endAngle = (index + 1) * sliceAngle;
+
+ const clipPath = createSliceClipPath(
+ startAngle,
+ endAngle,
+ themeWheelRadius,
+ );
+ icon.style.clipPath = clipPath;
+ });
+ }
+
+ function createSliceClipPath(startAngle, endAngle, radius) {
+ const centerX = radius;
+ const centerY = radius;
+
+ let points = `${centerX}px ${centerY}px`;
+
+ const segments = Math.max(
+ 2,
+ Math.ceil(Math.abs(endAngle - startAngle) / 5),
+ );
+ const angleStep = (endAngle - startAngle) / segments;
+
+ 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`;
+ }
+
+ points += `, ${centerX}px ${centerY}px`;
+
+ return `polygon(${points})`;
+ }
+
+ function positionThemeWheel() {
+ const buttonRect = themeButton.getBoundingClientRect();
+ const buttonCenterX = buttonRect.left + buttonRect.width / 2;
+ const buttonCenterY = buttonRect.top + buttonRect.height / 2;
+ const themeWheelRadius = convertRemToPixels(6);
+
+ const margin = 0;
+
+ let wheelX = buttonCenterX - themeWheelRadius;
+ let wheelY = buttonCenterY - themeWheelRadius;
+
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
+
+ if (wheelX < margin) {
+ wheelX = margin;
+ } else if (
+ wheelX + themeWheelRadius * 2 >
+ viewportWidth - margin
+ ) {
+ wheelX = viewportWidth - themeWheelRadius * 2 - margin;
+ }
+
+ if (wheelY < margin) {
+ wheelY = margin;
+ } else if (
+ wheelY + themeWheelRadius * 2 >
+ viewportHeight - margin
+ ) {
+ wheelY = viewportHeight - themeWheelRadius * 2 - margin;
+ }
+
+ themeWheel.style.left = wheelX + "px";
+ themeWheel.style.top = wheelY + "px";
+ }
+
+ function hideThemeWheel() {
+ themeWheel.classList.remove("active");
+ }
+
+ function showThemeWheel() {
+ positionThemeWheel();
+ positionThemeIcons();
+ themeWheel.classList.add("active");
+ }
+
+ function toggleThemeWheel() {
+ if (themeWheel.classList.contains("active")) {
+ hideThemeWheel();
+ } else {
+ showThemeWheel();
+ }
+ }
+
+ 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");
+ });
+ });
+
+ themeWheel.addEventListener("mouseleave", hideThemeWheel);
+
+ document.addEventListener("click", (e) => {
+ if (
+ !themeWheel.contains(e.target) &&
+ e.target !== themeButton &&
+ !e.target.classList.contains("sidebar-theme-button-content")
+ ) {
+ hideThemeWheel();
+ }
+ });
+ </script>
+ </body>
+</html>
diff --git a/views/pages/home-page.html b/views/pages/home-page.html
new file mode 100644
index 0000000..d494a08
--- /dev/null
+++ b/views/pages/home-page.html
@@ -0,0 +1,144 @@
+{{ define "body" }}
+<!-- Streamline Icons: https://streamlinehq.com -->
+<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
+ <symbol id="icon-discord" viewBox="0 0 24 24"><g>
+ <path d="M23.8 8.8A10.45 10.45 0 0 0 20 3 13 13 0 0 0 13.59 0.4c-0.14 0 -6 -1 -9.79 2.77C1.67 5.32 0.56 8.65 0.15 11.77A15.3 15.3 0 0 0 0 14.71a8.77 8.77 0 0 0 3.46 6.44 13.74 13.74 0 0 0 4 2 13.55 13.55 0 0 0 1.91 0.52 5.32 5.32 0 0 0 1.41 0.11 16.63 16.63 0 0 0 6.12 -1.57A12.19 12.19 0 0 0 21.75 18a14.6 14.6 0 0 0 1.87 -4.4 10.74 10.74 0 0 0 0.18 -4.8Zm-1.19 4.56a13.31 13.31 0 0 1 -1.77 4.05 11 11 0 0 1 -4.43 3.73 15.5 15.5 0 0 1 -5.71 1.47 4.07 4.07 0 0 1 -1.13 -0.09 13.63 13.63 0 0 1 -1.76 -0.47 13.06 13.06 0 0 1 -3.68 -1.75 7.87 7.87 0 0 1 -2.5 -3.08A7.75 7.75 0 0 1 1 14.63a14.11 14.11 0 0 1 0 -2.75c0.32 -3 1.29 -6.15 3.27 -8.23 0.1 -0.11 2.84 -3.36 9.2 -2.5a12.09 12.09 0 0 1 5.95 2.53A9.47 9.47 0 0 1 22.86 9a9.56 9.56 0 0 1 -0.25 4.36Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M20.27 11.06c-0.33 -0.59 -0.74 -1.14 -1.08 -1.69a16.78 16.78 0 0 0 -1.4 -2 6 6 0 0 0 -1.27 -1.17A6.34 6.34 0 0 0 14 5.36a31.12 31.12 0 0 0 -3.83 -0.08 12.94 12.94 0 0 0 -3 0.18c-1.41 0.35 -0.76 0.32 -2 2.72 -0.57 0.89 -1.02 1.82 -1.49 2.72a11.42 11.42 0 0 0 -0.77 1.39 1.65 1.65 0 0 0 -0.1 0.82 2.77 2.77 0 0 0 0.45 1.15 8.92 8.92 0 0 0 1.08 1.27l1.09 1.29a3.51 3.51 0 0 0 0.29 0.37 0.47 0.47 0 0 0 0.42 0.15 2 2 0 0 0 1.16 -0.62 12.55 12.55 0 0 0 1.49 -2c0.06 -0.08 0.36 -0.36 0.37 -0.52l0.93 0.11 2.91 0c1.31 0.09 0.41 -0.77 1.77 1.78a9.19 9.19 0 0 0 0.52 0.85 5.71 5.71 0 0 0 0.53 0.81 0.67 0.67 0 0 0 0.39 0.19 1.49 1.49 0 0 0 0.74 -0.11 5 5 0 0 0 1 -0.67 11.91 11.91 0 0 0 1.52 -1.42 13 13 0 0 0 1.28 -1.64 1.47 1.47 0 0 0 0.25 -0.77 3.09 3.09 0 0 0 -0.16 -0.94 6.06 6.06 0 0 0 -0.57 -1.33Zm-0.38 2.43A12.53 12.53 0 0 1 18.7 15a11.92 11.92 0 0 1 -1.4 1.28 5 5 0 0 1 -0.57 0.42l-0.14 0.08a2.55 2.55 0 0 0 -0.38 -0.48 6.07 6.07 0 0 1 -0.45 -0.74c-0.35 -0.64 -0.64 -1.32 -1 -1.95a0.73 0.73 0 0 0 -0.48 -0.31 11.39 11.39 0 0 0 -1.22 -0.09h-2.95c-0.21 0 -0.69 -0.1 -1 -0.1a1.13 1.13 0 0 0 -0.45 0.08 0.88 0.88 0 0 0 -0.34 0.29c-0.14 0.19 -0.28 0.53 -0.35 0.63a19.39 19.39 0 0 1 -1.11 1.72 1.93 1.93 0 0 1 -0.59 0.53l-0.11 -0.09L5 14.93a10 10 0 0 1 -1 -1.12 1.94 1.94 0 0 1 -0.41 -0.81 1.11 1.11 0 0 1 0.11 -0.64c0.17 -0.4 0.45 -0.79 0.62 -1.14 0.45 -0.91 0.87 -1.84 1.33 -2.75 1.29 -2.53 1.18 -2.29 2 -2.41a14.57 14.57 0 0 1 2.46 0 28 28 0 0 1 3.71 0.16A5.33 5.33 0 0 1 16 7a5.08 5.08 0 0 1 1 1 16.3 16.3 0 0 1 1.27 1.93c0.33 0.55 0.72 1.11 1 1.69a5.1 5.1 0 0 1 0.48 1.1 2.36 2.36 0 0 1 0.1 0.53 0.43 0.43 0 0 1 0.04 0.24Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M7.15 8.26a1.44 1.44 0 0 0 -0.51 0.6 1.56 1.56 0 0 0 0.14 1.48A1.49 1.49 0 0 0 8.2 11a1.77 1.77 0 0 0 1.38 -1.42c0.27 -1.69 -1.45 -1.94 -2.43 -1.32Zm1.53 1.11a0.71 0.71 0 0 1 -0.6 0.53 0.44 0.44 0 0 1 -0.41 -0.2 0.65 0.65 0 0 1 -0.19 -0.54 0.68 0.68 0 0 1 0.21 -0.37c0.75 -0.55 1.17 0.02 0.99 0.58Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M15 8a1.38 1.38 0 0 0 -0.77 -0.21 2.68 2.68 0 0 0 -1 0.25 3.12 3.12 0 0 0 -0.72 1 1.65 1.65 0 0 0 0.55 1.53 1.6 1.6 0 0 0 1.69 0.38 1.71 1.71 0 0 0 0.89 -1.47A1.65 1.65 0 0 0 15 8Zm-0.37 1.4a0.62 0.62 0 0 1 -0.3 0.53 0.36 0.36 0 0 1 -0.27 0 1.28 1.28 0 0 1 -0.4 -0.25c-0.15 -0.14 -0.3 -0.29 -0.28 -0.47a0.45 0.45 0 0 1 0.17 -0.34 2.73 2.73 0 0 1 0.53 -0.29 0.57 0.57 0 0 1 0.39 0.14 0.74 0.74 0 0 1 0.2 0.69Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-telegram" viewBox="0 0 24 24"><g>
+ <path d="M23.8 9.74a10.54 10.54 0 0 0 -3.1 -5.5c-1.25 -1.19 -7.2 -6 -13.52 -3.12a12 12 0 0 0 -4.56 18.49 12.24 12.24 0 0 0 2.66 2.53 9.1 9.1 0 0 0 3.43 1.45c3.79 0.74 7.9 -0.75 10.9 -3.38s5.03 -6.67 4.19 -10.47Zm-4.87 9.68c-2.78 2.38 -6.54 3.78 -10 3.09a8.18 8.18 0 0 1 -3 -1.27 11.8 11.8 0 0 1 -2.44 -2.3 11 11 0 0 1 -2.25 -9.53 11.25 11.25 0 0 1 6.24 -7.66C8.17 1.42 12.94 -0.79 19 3.84a10 10 0 0 1 3.91 6.08c0.74 3.49 -1.1 7.08 -3.98 9.5Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M17.5 6.52a8 8 0 0 0 -2.14 0.35l-0.78 0.13c-1.67 0.31 -3.36 0.63 -5 1 -1.11 0.28 -2.21 0.59 -3.29 1a5.12 5.12 0 0 0 -0.65 0.25 4.6 4.6 0 0 0 -0.64 0.34l-0.61 0.4 -0.39 0.34a0.93 0.93 0 0 0 -0.24 1.09C4 12 5 12.34 5.49 12.48l0.53 0.17 0.15 0 0 0.81 0 1 0.08 0.74 0.06 0.53A8.91 8.91 0 0 0 6.53 17a1.4 1.4 0 0 0 0.42 0.71H7a0.3 0.3 0 0 0 0.34 0.22A13.32 13.32 0 0 0 9 17.8a5.35 5.35 0 0 0 0.69 -0.17c0.23 -0.07 0.45 -0.15 0.67 -0.24 0.49 -0.19 0.94 -0.41 1.4 -0.63l0.58 0.56 0.66 0.47 0.52 0.23a1.08 1.08 0 0 0 1 -0.19 4.55 4.55 0 0 0 0.92 -1.51l1.4 -2.92c0.38 -0.76 0.78 -1.51 1.15 -2.28 0.25 -0.52 0.48 -1 0.68 -1.59A3.92 3.92 0 0 0 19 8.2a1.73 1.73 0 0 0 -0.31 -1.08 1.51 1.51 0 0 0 -1.19 -0.6ZM6.88 13.44l-0.07 -0.58c0.46 0 0.49 -0.43 5.26 -1.84l0.62 -0.16A16.71 16.71 0 0 1 11.34 12c-0.74 0.57 -1.51 1.12 -2.26 1.69l-0.46 0.52 -0.69 1.49s-0.22 0.44 -0.4 0.82c-0.07 -0.36 -0.1 -0.74 -0.14 -0.91l-0.12 -0.54 -0.19 -0.7Zm3.14 3c-0.23 0.05 -0.46 0.1 -0.68 0.17l-0.66 0.21 -0.27 0.12c0.07 -0.25 0.26 -0.76 0.31 -0.93 0.12 -0.36 0.35 -1.18 0.48 -1.5a0.3 0.3 0 0 0 0 -0.23s0.07 0 0.11 0l1.81 2c-0.35 -0.02 -0.72 0.04 -1.12 0.13Zm7.83 -8.08a3.2 3.2 0 0 1 -0.22 0.82c-0.14 0.39 -0.3 0.77 -0.46 1.14 -0.4 0.9 -0.83 1.79 -1.24 2.68l-1.31 2.95a6 6 0 0 1 -0.55 1.15 0.34 0.34 0 0 1 -0.36 0.16l-0.35 -0.14 -0.57 -0.38 -1 -0.91 -1.86 -1.93c0.78 -0.49 1.56 -1 2.32 -1.48 0.4 -0.27 0.8 -0.55 1.17 -0.85 0.2 -0.17 0.41 -0.34 0.59 -0.52a2.16 2.16 0 0 0 0.36 -0.51 2.52 2.52 0 0 0 0.14 -0.56 0.54 0.54 0 0 0 -0.51 -0.55 1.06 1.06 0 0 0 -0.24 0 3.54 3.54 0 0 0 -0.47 0.12l-1.51 0.45c-0.58 0.19 -1.14 0.38 -1.69 0.6 -1.27 0.5 -2.49 1.07 -3.78 1.55l-0.09 0 -0.53 -0.18a3.39 3.39 0 0 1 -1.22 -0.65c-0.11 -0.11 -0.11 -0.26 0.06 -0.43l0.3 -0.25 0.52 -0.32 1.16 -0.52c1.08 -0.32 2.17 -0.58 3.26 -0.8 1.66 -0.35 3.33 -0.62 5 -0.89l0.81 -0.16a10 10 0 0 1 1.6 -0.32c0.23 0 0.46 0 0.57 0.14a0.76 0.76 0 0 1 0.1 0.56Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ </g></symbol>
+ <symbol id="icon-email" viewBox="0 0 24 24"><g>
+ <path d="M23.58 5.09a2.73 2.73 0 0 0 -0.71 -1.43 4.24 4.24 0 0 0 -1.62 -0.34 99 99 0 0 0 -11.89 0.07C5.34 3.65 1.7 4.18 0.55 5a1.12 1.12 0 0 0 -0.35 0.68A25.75 25.75 0 0 0 0 9.6a93.2 93.2 0 0 0 0.5 10.09 0.31 0.31 0 1 0 0.61 -0.11c-0.15 -0.95 -0.29 -4 -0.31 -7.11A56 56 0 0 1 1 6.36c1.64 1.1 4.88 3.25 7.53 4.69l1.46 0.72a7.13 7.13 0 0 0 2.53 0.82 3.16 3.16 0 0 0 1.14 -0.42 8.38 8.38 0 0 0 0.79 -0.48l1.44 -1c0.34 -0.25 0.67 -0.49 1 -0.77A44.32 44.32 0 0 0 22.32 5c0 0.11 0.07 0.24 0.1 0.38a24.38 24.38 0 0 1 0.41 4.75 65 65 0 0 1 -0.36 8.17c0 0.22 -0.07 0.45 -0.1 0.58l-0.69 0c-1.79 0.18 -5.6 0.46 -9.48 0.7 -4.39 0.27 -8.86 0.5 -10.56 0.54a0.35 0.35 0 0 0 -0.35 0.35 0.36 0.36 0 0 0 0.36 0.35c2.27 0 9.45 -0.29 14.83 -0.58 2.56 -0.13 4.71 -0.27 5.73 -0.37a2.73 2.73 0 0 0 0.86 -0.19 0.6 0.6 0 0 0 0.24 -0.3 4.17 4.17 0 0 0 0.22 -0.94A65.86 65.86 0 0 0 24 10.1a26 26 0 0 0 -0.42 -5.01Zm-6.33 3.28c-1.23 0.92 -2.48 1.78 -3.44 2.36a4.31 4.31 0 0 1 -1.36 0.67 3.75 3.75 0 0 1 -1.27 -0.4c-0.9 -0.37 -2.06 -0.94 -3.29 -1.59C5.34 8.1 2.52 6.49 1.13 5.68c1.18 -0.69 4.57 -1 8.29 -1.2a106 106 0 0 1 11.74 0h0.62a38.87 38.87 0 0 1 -4.53 3.89Z" fill="var(--color-main)" stroke-width="1"></path>
+ <path d="M17.68 14.41c0.34 0.33 0.69 0.65 1 0.95 1 0.93 2 1.74 2.46 2.19a0.36 0.36 0 0 0 0.5 0 0.35 0.35 0 0 0 0 -0.5c-0.43 -0.51 -1.23 -1.46 -2.18 -2.49q-0.48 -0.51 -1 -1c-0.34 -0.33 -0.69 -0.66 -1 -1s-0.81 -0.68 -1.19 -1c-0.69 -0.47 -1.2 0 -0.71 0.59 0.34 0.37 0.71 0.78 1.12 1.2s0.66 0.73 1 1.06Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ <path d="M4.59 15.35a39.94 39.94 0 0 0 -2.94 3.25 0.35 0.35 0 1 0 0.53 0.46c0.59 -0.6 1.69 -1.51 2.89 -2.58 0.63 -0.57 1.29 -1.17 1.9 -1.79s1.42 -1.52 2 -2.21 -0.14 -1 -0.82 -0.39c-0.52 0.46 -1.08 0.94 -1.67 1.47s-1.28 1.19 -1.89 1.79Z" fill="var(--color-accent-deep)" stroke-width="1"></path>
+ </g></symbol>
+</svg>
+<div class="relative bg-paper bg-background-light font-gentium flex flex-col sm:flex-row w-full h-full overflow-y-auto text-base/loose tracking-wide z-10">
+ <div class="sm: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-[0.25rem] border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ l $.Lang "HomePage" "Hymn1" }}</p>
+ <hr class="w-full border-t-[0.125rem] 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 $.Lang "HomePage" "Hymn2" }}</p>
+ <p class="text-xl/loose sm:text-2xl/loose lg:text-3xl/loose -indent-8 ml-12 p-1">{{ l $.Lang "HomePage" "Hymn3" }}</p>
+ <p class="text-xl/loose sm:text-2xl/loose lg:text-3xl/loose -indent-8 ml-12 p-1">{{ l $.Lang "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-[0.125rem] border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ l $.Lang "HomePage" "DidYouKnowThat" }}</p>
+ <hr class="w-full border-t-[0.125rem] 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="sm: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-[0.125rem] border-solid border-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ l $.Lang "HomePage" "Contacts" }}</p>
+ <hr class="w-full border-t-[0.125rem] border-dotted border-main-hard mb-1">
+ <a href="https://t.me/EarlInisMona">
+ <svg class="w-4 h-4 mr-1 inline" viewBox="0 0 24 24"><use href="#icon-telegram"/></svg>
+ <span class="font-bold">Telegram:</span>
+ <span>@EarlInisMona</span>
+ </a>
+ <a href="https://discord.com/users/356057270951346176">
+ <svg class="w-4 h-4 mr-1 inline" viewBox="0 0 24 24"><use href="#icon-discord"/></svg>
+ <span class="font-bold">Discord:</span>
+ <span>montferrat</span>
+ </a>
+ <a href="mailto:saya.andy@posteo.com">
+ <svg class="w-4 h-4 mr-1 inline" viewBox="0 0 24 24"><use href="#icon-email"/></svg>
+ <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-[0.25rem] 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-[0.125rem] border-solid border-color-background-dark
+ bg-linear-to-r from-background-dark to-background-light">{{ l $.Lang "HomePage" "SidebarDescription" }}</p>
+ <hr class="w-full border-t-[0.125rem] 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;">
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-back"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "BackDescription" }}</p>
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-logo"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "HomePageDescription" }}</p>
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-newspaper"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "BlogSearchDescription" }}</p>
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-map"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "MarkerMapDescription" }}</p>
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-palette"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "ThemeSwitchDescription" }}</p>
+ <svg viewBox="0 0 24 24" class="h-full w-[15cqi] context-center text-main-hard"><use href="#icon-account"/></svg>
+ <p class="p-1 w-[85cqi]">{{ l $.Lang "HomePage" "AccountDescription" }}</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..9576a65
--- /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-[0.125rem] 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-[0.125rem] 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..12ff1f0
--- /dev/null
+++ b/views/pages/unsubscribe-page.html
@@ -0,0 +1,82 @@
+<!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)"
+ />
+ <link
+ rel="icon"
+ href="/favicon.ico"
+ type="image/x-icon"
+ />
+ <title>{{ l $.Lang "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..a94dcb3
--- /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-elevation-6 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 $.Lang "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-elevation-6 focus:outline-none focus:bg-background-light focus:text-main-hard z-22"
+ id="email-input" name="email" type="text" value="{{ .Email }}" placeholder="{{ l $.Lang "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 $.Lang "UserProfile" "SendCodeButton" }}
+ </button>
+ </form>
+ <div id="email-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-elevation-6 py-2 px-4 text-center"></div>
+
+ <hr class="my-2 border-t-[0.25rem] 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 $.Lang "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-elevation-6 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 $.Lang "UserProfile" "VerifyButton" }}
+ </button>
+ </form>
+ <div id="verification-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-elevation-6 py-2 px-4 text-center"></div>
+</div>
+
+<hr class="my-4 border-t-[0.25rem] border-dotted border-main-hard">
+
+<div class="bg-paper bg-background-light flex flex-col inset-shadow-elevation-6 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 $.Lang "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 $.Lang "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 $.Lang "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 $.Lang "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-elevation-6 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-elevation-6 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 $.Lang "UserProfile" "SaveButton" }}
+ </button>
+ </div>
+ </form>
+ <div id="subs-message" class="bg-paper bg-background-dark text-main-soft z-26 w-full inset-shadow-elevation-6 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 $.Lang "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 $.Lang "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
diff --git a/views/partials/blog-page-like-button.html b/views/partials/blog-page-like-button.html
new file mode 100644
index 0000000..50ceae9
--- /dev/null
+++ b/views/partials/blog-page-like-button.html
@@ -0,0 +1,28 @@
+<button hx-put="/api/v1/like" hx-vals='{"like": {{ not .Liked }}}' hx-target="this" hx-swap="outerHTML" hx-trigger="click"
+ class="accent-button rounded-xl relative shrink-0 w-fit aspect-square mr-4 p-2 my-auto{{ if .Liked }} active{{ end }}">
+ {{ if .Liked }}
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="Like-Hand-1--Streamline-Freehand" class="h-10">
+ <desc>
+ Like Hand 1 Streamline Icon: https://streamlinehq.com
+ </desc>
+ <g>
+ <path d="M18.36 11a4.26 4.26 0 0 0 -3 -0.92 22.21 22.21 0 0 0 -3.72 0.43c0 -0.69 0.05 -1.76 0 -2.69a4.77 4.77 0 0 0 -0.31 -1.56 1.73 1.73 0 0 0 -2 -1 2.13 2.13 0 0 0 -1.69 1.29 17.51 17.51 0 0 1 -2.3 4.14c-0.77 1 -1.56 1.83 -2.17 1.89a1.68 1.68 0 0 0 -0.12 -0.31A2 2 0 0 0 2 11.52a4.67 4.67 0 0 0 -1.7 -0.21 0.3 0.3 0 0 0 -0.28 0.32 0.3 0.3 0 0 0 0.32 0.28 3.71 3.71 0 0 1 1.17 0.22 1.31 1.31 0 0 1 0.81 0.55 7.78 7.78 0 0 1 0.17 1.68c0 0.54 0 1.14 0.06 1.78 0 0.88 0.07 1.82 0.1 2.66s0.06 1.82 0 2.35c0 0.17 -0.08 0.34 -0.06 0.39a2.1 2.1 0 0 1 -0.91 0.36 2.74 2.74 0 0 1 -1.21 0 0.34 0.34 0 0 0 -0.22 0.65 3.61 3.61 0 0 0 1.54 0.11 2.85 2.85 0 0 0 1.53 -0.58 1.4 1.4 0 0 0 0.24 -0.72 31.22 31.22 0 0 0 0.14 -4.27c0 -0.82 -0.09 -1.64 -0.17 -2.36s-0.15 -1.15 -0.23 -1.57a5.48 5.48 0 0 0 2.56 -2.06 18 18 0 0 0 2.55 -4.26 1.32 1.32 0 0 1 1 -0.77 0.88 0.88 0 0 1 1 0.51 4.12 4.12 0 0 1 0.18 1.24c0 1.09 -0.08 2.38 0 3a1.39 1.39 0 0 0 0.12 0.57 0.55 0.55 0 0 0 0.51 0.27 4 4 0 0 0 0.52 -0.06 18.17 18.17 0 0 1 4.26 -0.36 2.45 2.45 0 0 1 1.57 0.55c0.85 0.9 1.31 3 1.4 5s-0.18 4.15 -1.05 5 -2.57 1.05 -4.37 1.21a12 12 0 0 1 -4.67 -0.46C8 22.1 6.71 21.39 5.6 21a3.82 3.82 0 0 0 -1.66 -0.27 0.34 0.34 0 0 0 -0.3 0.38 0.34 0.34 0 0 0 0.36 0.29 3.15 3.15 0 0 1 1.34 0.27c1.09 0.41 2.33 1.14 3.2 1.54a14.07 14.07 0 0 0 6 0.58 7.25 7.25 0 0 0 4 -1.28c1 -1 1.55 -3.37 1.46 -5.78S19.34 12 18.36 11Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M0.37 6c0.31 0 0.82 0.13 1.41 0.17H2v0.1c0.06 0.68 0.15 1.25 0.17 1.46a0.34 0.34 0 0 0 0.68 0C2.84 7.54 3 7 3 6.27l0 -0.15c0.64 -0.08 1.16 -0.2 1.25 -0.18a0.34 0.34 0 0 0 0.43 -0.22 0.32 0.32 0 0 0 -0.21 -0.42 7 7 0 0 0 -1.46 -0.24V5c-0.07 -0.67 -0.2 -1.24 -0.24 -1.47a0.31 0.31 0 0 0 -0.31 -0.3 0.29 0.29 0 0 0 -0.29 0.3C2.17 3.78 2 4.34 2 5l-0.2 0a10.33 10.33 0 0 0 -1.43 0.32 0.3 0.3 0 0 0 -0.27 0.33 0.3 0.3 0 0 0 0.27 0.35Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M23.77 10.81a5.83 5.83 0 0 0 -1.25 -0.25c-0.1 -0.39 -0.24 -0.71 -0.29 -0.92a0.3 0.3 0 1 0 -0.6 0c0 0.2 -0.11 0.53 -0.15 0.91a8.85 8.85 0 0 0 -1.2 0.31 0.29 0.29 0 0 0 -0.26 0.33 0.3 0.3 0 0 0 0.32 0.27c0.3 0 0.7 0.13 1.17 0.18h0.07c0.09 0.44 0.22 0.81 0.25 1a0.34 0.34 0 1 0 0.68 0 8.85 8.85 0 0 0 0.14 -1.08c0.47 -0.07 0.84 -0.17 0.93 -0.15a0.34 0.34 0 0 0 0.22 -0.65Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M13.94 4.33a2.57 2.57 0 0 1 1.43 0.88 4.52 4.52 0 0 1 1 1.54 0.57 0.57 0 0 0 0.56 0.37 0.57 0.57 0 0 0 0.53 -0.41 2.81 2.81 0 0 1 1 -1.41 6.9 6.9 0 0 1 1.69 -1 0.49 0.49 0 0 0 0.31 -0.43 0.5 0.5 0 0 0 -0.24 -0.47 8.18 8.18 0 0 1 -2.26 -1.47 2.39 2.39 0 0 1 -0.71 -1.46 0.34 0.34 0 0 0 -0.34 -0.34 0.35 0.35 0 0 0 -0.34 0.35 0.29 0.29 0 0 0 -0.27 0.23 4.41 4.41 0 0 1 -1 1.63 3.53 3.53 0 0 1 -1.48 1 0.47 0.47 0 0 0 -0.32 0.5 0.48 0.48 0 0 0 0.44 0.49Zm2 -1.47a5.53 5.53 0 0 0 0.82 -1.44 3.34 3.34 0 0 0 0.59 1 6.91 6.91 0 0 0 1.53 1.3 5.93 5.93 0 0 0 -1.48 1 6.91 6.91 0 0 0 -0.51 0.57 4.8 4.8 0 0 0 -0.7 -0.85 4 4 0 0 0 -1 -0.74 5.76 5.76 0 0 0 0.71 -0.84Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ </g>
+ </svg>
+ <div class="absolute left-10 -top-2 bg-accent-light rounded-full w-6 h-6 text-main! font-m-plus! font-normal! tracking-normal! not-italic! text-lg!">{{ .LikedCount }}</div>
+ {{ else }}
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="Like-Hand--Streamline-Freehand" class="h-10">
+ <desc>
+ Like Hand Streamline Icon: https://streamlinehq.com
+ </desc>
+ <g>
+ <path d="M24 14.66c-0.1 -2.79 -0.84 -5.58 -2 -6.82a5 5 0 0 0 -3.59 -1.08 27.12 27.12 0 0 0 -4.58 0.54 1.27 1.27 0 0 1 0 -0.2c0 -0.82 0.06 -2.11 0 -3.23a5.56 5.56 0 0 0 -0.4 -1.87A2 2 0 0 0 11.16 0.87a2.51 2.51 0 0 0 -1.94 1.55 20.45 20.45 0 0 1 -2.79 5C5.52 8.64 5 9.45 4.22 9.58c-0.37 0.13 -0.11 0.56 0.22 0.45C5.27 9.81 6 9.12 7 7.85a21.68 21.68 0 0 0 3 -5.14 1.66 1.66 0 0 1 1.3 -1 1.15 1.15 0 0 1 1.28 0.67 4.82 4.82 0 0 1 0.23 1.52c0 1.31 -0.08 2.87 -0.06 3.61a1.57 1.57 0 0 0 0.14 0.63 0.58 0.58 0 0 0 0.53 0.28 5 5 0 0 0 0.58 -0.06 22.31 22.31 0 0 1 5.15 -0.43 3 3 0 0 1 2 0.7c1.05 1.1 1.61 3.6 1.72 6.08s-0.23 5.07 -1.3 6.11c-0.91 0.88 -3.09 1.3 -5.29 1.43a14.43 14.43 0 0 1 -5.66 -0.57c-1.07 -0.47 -2.61 -1.33 -3.95 -1.8a4.56 4.56 0 0 0 -2 -0.33 0.34 0.34 0 0 0 -0.29 0.38 0.34 0.34 0 0 0 0.38 0.3 3.7 3.7 0 0 1 1.64 0.32c1.32 0.49 2.82 1.37 3.86 1.85 1.4 0.65 4.49 0.93 7.24 0.68 2 -0.19 3.87 -0.71 4.74 -1.52 1.26 -1.17 1.85 -4.02 1.76 -6.9Z" fill="var(--color-main)" fill-rule="evenodd" stroke-width="1"></path>
+ <path d="M3.53 9.34a2.22 2.22 0 0 0 -1.24 -0.88 5.37 5.37 0 0 0 -2 -0.26 0.3 0.3 0 0 0 -0.29 0.31 0.3 0.3 0 0 0 0.32 0.29 4.36 4.36 0 0 1 1.44 0.25 1.74 1.74 0 0 1 1 0.69A9.16 9.16 0 0 1 3 11.8c0 0.64 0.06 1.38 0.09 2.14 0 1.07 0.08 2.2 0.11 3.22s0.06 2.19 0 2.84c0 0.23 -0.12 0.45 -0.07 0.51A2.7 2.7 0 0 1 2 21a3.34 3.34 0 0 1 -1.49 0 0.34 0.34 0 0 0 -0.22 0.65 4.22 4.22 0 0 0 1.82 0.13 3.37 3.37 0 0 0 1.79 -0.69 1.82 1.82 0 0 0 0.26 -0.82 37.13 37.13 0 0 0 0.14 -5.13c0 -1 -0.1 -2 -0.19 -2.83a12.48 12.48 0 0 0 -0.58 -2.97Z" fill="var(--color-accent-deep)" fill-rule="evenodd" stroke-width="1"></path>
+ </g>
+ </svg>
+ <div class="absolute left-10 -top-2 bg-accent-deep rounded-full w-6 h-6 text-background! font-m-plus! font-normal! tracking-normal! not-italic! text-lg!">{{ .LikedCount }}</div>
+ {{ end }}
+</button>
diff --git a/views/partials/catalogue-blog-card-tags.html b/views/partials/catalogue-blog-card-tags.html
new file mode 100644
index 0000000..374314a
--- /dev/null
+++ b/views/partials/catalogue-blog-card-tags.html
@@ -0,0 +1 @@
+{{ range $i, $tag := .Tags }}{{ if ne $i 0 }}, {{ end }}<a hx-trigger="click" hx-get="/api/v1/blog-search" hx-target=".blog-cards" hx-swap="innerHTML" hx-trigger="load" hx-include=".tags-list" class="hx-anchor cursor-pointer" onclick="pickedTagSetHrefParams({{ $tag }})">{{ $tag }}</a>{{ end }} \ No newline at end of file
diff --git a/views/partials/catalogue-blog-cards.html b/views/partials/catalogue-blog-cards.html
new file mode 100644
index 0000000..6466262
--- /dev/null
+++ b/views/partials/catalogue-blog-cards.html
@@ -0,0 +1,39 @@
+{{- range .BlogPages }}
+<hr class="first-of-type:hidden border-t-[0.375rem] my-1 w-24 mx-auto border-dotted border-main-hard">
+<div {{ if .ToHighlight }}id="blog-page-highlighted"{{ end }} class="w-full flex flex-row items-stretch mask-t-from-[calc(100%-0.5rem)] mask-t-to-100% mask-b-from-[calc(100%-0.5rem)] mask-b-to-100% {{ if .ToHighlight }}bg-accent-light bg-paper{{ end }}">
+ <div class="relative min-h-24 flex flex-col w-32 overflow-hidden shrink-0 mask-r-from-[calc(100%-1rem)] mask-r-to-100%">
+ <img onclick="return changeUrl('{{ .ArticleLink }}');" class="h-full min-h-24 w-full cursor-pointer select-none object-cover block absolute" src="{{ printf $.PhotoStorage.Thumbnail320p.BaseUrl .Thumbnail }}">
+ <div class="w-full h-6 flex flex-row mt-auto relative">
+ <div class="flex-1/2 flex flex-row justify-center select-none bg-linear-180 {{ if .Liked }}from-accent-deep/40 to-accent-deep/80 text-background-dark{{ else }}from-accent-light/40 to-accent-light/80 text-main-hard{{ end }}">
+ <svg viewBox="0 0 24 24"><use href="#icon-like"/></svg>
+ <span>{{ .LikeCount }}</span>
+ </div>
+ <div class="flex-1/2 flex flex-row justify-center select-none bg-linear-180 {{ if .Viewed }}from-accent-deep/40 to-accent-deep/80 text-background-dark{{ else }}from-accent-light/40 to-accent-light/80 text-main-hard{{ end }}">
+ <svg viewBox="0 0 24 24"><use href="#icon-view"/></svg>
+ <span>{{ .ViewCount }}</span>
+ </div>
+ </div>
+ </div>
+ <div class="grow w-full h-fit flex flex-col justify-center my-auto py-1 px-2">
+ <div class="flex flex-row gap-2 max-w-full">
+ <a href="{{ .ArticleLink }}" onclick="return changeUrl('{{ .ArticleLink }}');" class="grow-2 text-base cursor-pointer font-m-plus">
+ <span class="font-extrabold">{{ .Title }}</span>
+ <span class="italic">[{{ .ActionDate }}]</span>
+ </a>
+ {{- if not $.HidePublishedTime }}
+ <p class="basis-56 grow text-base italic text-secondary text-right">{{ .PublishedTime }}</p>
+ {{- end }}
+ </div>
+ <p class="font-m-plus">{{ .ShortDescription }}</p>
+ {{- if not $.HideTags }}
+ <p class="font-m-plus text-sm">{{ $.L.TagsLabel }} {{ template "catalogue-blog-card-tags.html" . }}</p>
+ {{- end }}
+ </div>
+</div>
+{{- if .ToHighlight }}
+<script>
+ element = document.getElementById("blog-page-highlighted");
+ element.scrollIntoView({ behavior: "smooth", block: "center" });
+</script>
+{{- end }}
+{{- end }}
diff --git a/views/partials/general-page-body.html b/views/partials/general-page-body.html
new file mode 100644
index 0000000..b71a0d1
--- /dev/null
+++ b/views/partials/general-page-body.html
@@ -0,0 +1,2 @@
+<input class="htmx-exit-trigger" type="hidden" name="dummy" value="">
+{{ block "body" . }}{{ end }} \ No newline at end of file
diff --git a/views/partials/general-page-bottom-embeds.html b/views/partials/general-page-bottom-embeds.html
new file mode 100644
index 0000000..4c36b26
--- /dev/null
+++ b/views/partials/general-page-bottom-embeds.html
@@ -0,0 +1 @@
+{{ block "bottom-embeds" . }}{{ end }} \ No newline at end of file
diff --git a/views/partials/general-page-footer.html b/views/partials/general-page-footer.html
new file mode 100644
index 0000000..3f5f9ee
--- /dev/null
+++ b/views/partials/general-page-footer.html
@@ -0,0 +1,23 @@
+{{ block "footer" . }}{{ end }}
+<p
+ class="grow content-center text-base/[1] font-gentium font-thin italic text-right text-secondary mr-1"
+>
+ All the photos on <a href="https://saya.uz/">saya.uz</a> are licensed under
+ <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>
+ by <a href="https://t.me/EarlInisMona">Saya Andy</a> © {{ .PublishedYear }}
+</p>
+<img
+ class="max-w-4 max-h-4 self-center"
+ src="https://mirrors.creativecommons.org/presskit/icons/cc.svg"
+ alt="CC"
+/>
+<img
+ class="max-w-4 max-h-4 self-center"
+ src="https://mirrors.creativecommons.org/presskit/icons/by.svg"
+ alt="BY"
+/>
+<img
+ class="max-w-4 max-h-4 self-center"
+ src="https://mirrors.creativecommons.org/presskit/icons/sa.svg"
+ alt="SA"
+/>
diff --git a/views/partials/general-page-header.html b/views/partials/general-page-header.html
new file mode 100644
index 0000000..a75d32f
--- /dev/null
+++ b/views/partials/general-page-header.html
@@ -0,0 +1,9 @@
+<title>{{ or .PageTitle .Title }}</title>
+<div class="flex flex-row mb-2">
+ {{ block "header" . }}{{ end }}
+ <h1
+ class="text-4xl font-m-plus font-bold italic text-shadow-[0_0.125rem_0.125rem_var(--color-main-soft)] text-left my-auto"
+ >
+ {{ .Title }}
+ </h1>
+</div>
diff --git a/views/partials/general-page-top-embeds.html b/views/partials/general-page-top-embeds.html
new file mode 100644
index 0000000..1407b50
--- /dev/null
+++ b/views/partials/general-page-top-embeds.html
@@ -0,0 +1 @@
+{{ block "top-embeds" . }}{{ end }} \ No newline at end of file
diff --git a/views/partials/global-map-widget.html b/views/partials/global-map-widget.html
new file mode 100644
index 0000000..f50020f
--- /dev/null
+++ b/views/partials/global-map-widget.html
@@ -0,0 +1,109 @@
+<div
+ id="map-container"
+ class="bg-paper bg-background-dark flex z-10 w-full h-full"
+></div>
+
+<script>
+(function() {
+ var map;
+ var markers = L.markerClusterGroup();
+ const THUMB_BASE = "{{ .PhotoStorage.Thumbnail320p.BaseUrl }}";
+
+ 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>
+ `;
+
+ return L.divIcon({
+ html: svgIcon,
+ className: 'custom-svg-marker',
+ iconSize: [32, 32],
+ iconAnchor: [16, 32],
+ popupAnchor: [0, -32]
+ });
+ }
+
+ function initLocationMap() {
+ map = L.map('map-container').setView([{{ .MapLocationLat }}, {{ .MapLocationLong }}], {{ .MapLocationZoom }});
+
+ protomapsL.leafletLayer({
+ url: '{{ .StaticStorage.Map.BaseUrl }}/{{ .StaticStorage.Map.PMTiles }}',
+ maxZoom: 15,
+ flavor: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
+ lang: '{{ .Lang }}'
+ }).addTo(map);
+
+ {{- with .ZoomPosition }}
+ L.control.zoom({
+ position: '{{ . }}'
+ }).addTo(map);
+ {{- end }}
+
+ map.addLayer(markers);
+ }
+
+ 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;
+ }
+
+ return [hash, (20 + newCoef * 80).toFixed(0), (20 + newCoef * 75).toFixed(0)];
+ }
+
+ function mapAddMarker(x, y, relativeErrorMeters = 0, title = "", link = "", thumbnail = "", newCoef = 1, toHighlight = false) {
+ 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);
+ }
+
+ 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>`);
+
+ markers.addLayer(marker);
+
+ if (toHighlight) {
+ markers.zoomToShowLayer(marker, () => marker.openPopup());
+ }
+ }
+
+ initLocationMap();
+ {{- range .MapMarkers }}
+ mapAddMarker({{ .Lat }}, {{ .Long }}, {{ .AccuracyMeters }}, {{ .Title }}, {{ .PageLink }}, {{ .Thumbnail }}, {{ fdiv .Index (len $.MapMarkers) }}, {{ .ToHighlight }});
+ {{- end }}
+
+ function onResize() {
+ setTimeout(() => {
+ if (map) map.invalidateSize();
+ }, 300);
+ }
+ window.addEventListener('resize', onResize);
+ new MutationObserver((muts, obs) => {
+ if (!document.getElementById('map-container')) {
+ window.removeEventListener('resize', onResize);
+ obs.disconnect();
+ }
+ }).observe(document.body, { childList: true, subtree: true });
+})();
+</script>
diff --git a/views/partials/personal-page-status.html b/views/partials/personal-page-status.html
new file mode 100644
index 0000000..41033a9
--- /dev/null
+++ b/views/partials/personal-page-status.html
@@ -0,0 +1,12 @@
+<div id="{{ .StatusId }}" class='z-26 w-full inset-shadow-elevation-6
+ {{if eq .Status "OK"}}bg-green-700 text-green-100
+ {{else if eq .Status "Failed"}}bg-red-700 text-red-100
+ {{else}}bg-paper bg-background-dark text-main-soft{{end}}
+ {{if eq .Message ""}}hidden{{end}}
+ py-2 px-4 text-center'
+ {{- range $_, $val := .DataAttributes }}
+ {{ $val }}
+ {{- end }}
+ >
+ {{ .Message }}
+</div> \ No newline at end of file