summaryrefslogtreecommitdiff
path: root/views
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'views')
-rw-r--r--views/index.html2
-rw-r--r--views/layouts/general-page.html190
-rw-r--r--views/pages/blog-catalogue.html116
-rw-r--r--views/pages/blog-page.html128
-rw-r--r--views/pages/global-map.html54
-rw-r--r--views/pages/home-page.html121
-rw-r--r--views/partials/blog-page-like-button.html6
-rw-r--r--views/partials/catalogue-blog-cards.html11
-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.html7
-rw-r--r--views/partials/general-page-header.html8
-rw-r--r--views/partials/general-page-top-embeds.html1
13 files changed, 494 insertions, 153 deletions
diff --git a/views/index.html b/views/index.html
index 2b8c937..b52df94 100644
--- a/views/index.html
+++ b/views/index.html
@@ -106,7 +106,7 @@
<p class="font-patua mx-auto text-[2.5vmax] mt-[0.8vmin] mb-[0.8vmin]">saya.today</p>
<div class="menu-inner-body grow bg-background-light flex flex-adaptive mx-auto opacity-100">
{{- range .AvailableLanguages }}
- <img onclick="location.href='/{{ .Name }}/blog';" class="object-scale-down cursor-pointer flex-1 rounded-[20%] language-icon mx-auto my-auto relative" src="{{ .Flag }}" alt="{{ .Alt }}">
+ <img onclick="location.href='/{{ .Name }}';" class="object-scale-down cursor-pointer flex-1 rounded-[20%] language-icon mx-auto my-auto relative" src="{{ .Flag }}" alt="{{ .Alt }}">
{{- end }}
</div>
<p class="font-spectral mx-auto text-[1.5vmax] text-secondary mt-[0.8vmin] mb-[0.8vmin]">Choose your language</p>
diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html
index 5918956..60608f4 100644
--- a/views/layouts/general-page.html
+++ b/views/layouts/general-page.html
@@ -3,18 +3,136 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>SAYA TODAY // {{ .Title }}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800&family=Patua+One&display=swap" rel="stylesheet">
- {{ block "header" . }}{{ end }}
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lightgallery.min.css">
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lg-zoom.min.css">
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lg-thumbnail.min.css">
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css">
<link href="/output.css" rel="stylesheet">
</head>
-<body data-theme="ram" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-row ar-lt-0.8:flex-col">
+<body data-theme="ram" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-row ar-lt-1.1:flex-col">
<script>
+ function changeUrl(path, toAppend = false) {
+ const urlParams = new URLSearchParams(window.location.search);
+ const newPathname = location.pathname.endsWith('/') ? location.pathname.slice(0, -1) : location.pathname;
+ const newPath = toAppend ? `${newPathname}${path}` : `${path}`;
+ history.pushState({}, '', `${newPath}${urlParams.entries.length == 0 ? '' : '?' + urlParams.toString()}`);
+ window.dispatchEvent(new Event('popstate'));
+ };
+ </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 calculateVmin(percent) {
+ const viewportWidth = window.innerWidth;
+ const viewportHeight = window.innerHeight;
+
+ const smallerDimension = Math.min(viewportWidth, viewportHeight);
+
+ const vminValue = (smallerDimension / 100) * percent;
+
+ return vminValue;
+ }
+
+ function switchThemeDecor(theme) {
+ document.querySelectorAll('.theme-decor').forEach((e) => {
+ e.remove();
+ });
+
+ if (theme == "" || typeof theme == "undefined") {
+ theme = document.body.getAttribute('data-theme');
+ }
+
+ vmin = calculateVmin(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 x = Math.floor(rand() * clWidth);
+ const y = Math.floor(rand() * clHeight * 0.8);
+ const rot = rand() * 90;
+ const animDuration = (rand() * 10) + 3;
+ const sz = Math.floor(rand() * 8) + 12;
+ 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 = `https://f003.backblazeb2.com/file/sayana-static/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 - 20*vmin);
+ y = Math.floor(rand() * clHeight - 20*vmin);
+ 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) < 30*vmin) {
+ 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;
+ }
+ }
+
function switchTheme(theme) {
if (theme == "" || typeof theme == "undefined") {
const currentTheme = document.body.getAttribute('data-theme');
@@ -27,25 +145,31 @@
}
localStorage.setItem('theme', theme);
document.body.setAttribute('data-theme', theme);
+ switchThemeDecor(theme);
}
const savedTheme = localStorage.getItem('theme') || 'ram';
switchTheme(savedTheme);
</script>
+ <div id="general-page-top-embeds" class="flex"
+ hx-get="/api/v1/general-page/top-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" hx-trigger="load" hx-target="this" hx-swap="innerHTML">
+ </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 id="sidebar" class="bg-sidebar flex sticky flex-col ar-gt-0.8:items-center shadow-2xl z-20 w-[5vw] ar-lt-0.8:w-[90vw] ar-lt-0.4:w-[100vw] h-screen ar-lt-0.8:h-[8vh] ar-lt-0.8:ml-[5vw] ar-lt-0.4:ml-0">
- <div class="logo-custom ar-lt-0.8:hidden text-sidebar font-patua font-extrabold text-center relative z-20">
+ <div id="sidebar" class="bg-sidebar flex sticky flex-col ar-gt-1.1:items-center shadow-2xl z-20 w-[5vw] ar-lt-1.1:w-[90vw] ar-lt-0.4:w-[100vw] h-screen ar-lt-1.1:h-[8vh] ar-lt-1.1:ml-[5vw] ar-lt-0.4:ml-0">
+ <div class="logo-custom ar-lt-1.1:hidden text-sidebar font-patua font-extrabold text-center relative z-20">
saya.today
</div>
- <div class="text-[3vw] ar-lt-0.8:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-0.8:flex-row gap-0 relative z-20">
- <i onclick="location.href='/';" class="fas fa-home w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/blog';" class="fas fa-search w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <div class="text-[3vw] ar-lt-1.1:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-1.1:flex-row gap-0 relative z-20">
+ <i onclick="changeUrl('/{{ .Lang }}');" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="changeUrl('/{{ .Lang }}/blog');" class="fas fa-search w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
</div>
<div class="theme-wheel" id="theme-wheel">
<div class="theme-icon" data-theme="olive"></div>
@@ -55,29 +179,26 @@
</div>
</div>
- <div class="bg-background-dark flex z-10 ar-lt-0.8:w-[90vw] ar-lt-0.4:w-[100vw] h-screen ar-lt-0.8:ml-[5vw] ar-lt-0.4:ml-0">
+ <div class="bg-background-dark flex z-10 ar-lt-1.1:w-[90vw] ar-lt-0.4:w-[100vw] h-screen ar-lt-1.1:ml-[5vw] ar-lt-0.4:ml-0">
<div class="pl-[0.5vw] bg-background-dark border-r-[0.4vmin] border-dashed border-main-dark"></div>
- <div class="ar-gt-0.8:min-w-fit ar-gt-0.8:max-w-[100vh] flex flex-col bg-background-dark relative pt-[1.6vmin] ml-[1.6vmin] pr-[1.6vmin]">
- <div {{ if .PublishedDate }} hx-get="/api/v1/tz" hx-vals='js:{timestamp: "{{ .PublishedDate }}", tz: clientTimeZone}' hx-target="#published-date" hx-swap="innerHTML" hx-trigger="load" {{ end }}
- class="flex flex-row mb-[0.4vmin]">
- <i onclick="location.pathname += location.pathname.endsWith('/') ? '../' : '/../';" class="fas fa-circle-left hover:bg-main-dark hover:bg-opacity-10 cursor-pointer transition-colors duration-300 rounded-md text-[2vmax] mt-auto mb-auto px-[0.8vmin]"></i>
- <p class="text-[2vmax] font-spectral italic font-extrabold select-none mt-auto pl-[0.8vmin] pr-[1.2vmin]">//</p>
- <p class="text-[2vmax] font-spectral italic text-left mt-auto">{{ .Title }}</p>
- <p id="published-date" class="grow text-[1.5vmax] font-spectral text-secondary text-right mt-auto">{{ .PublishedDate }}</p>
+ <div class="ar-gt-1.1:w-[100vh] flex flex-col bg-background-dark relative pt-[1.6vmin] ml-[1.6vmin] pr-[1.6vmin]">
+ <div id="general-page-header" class="flex flex-col"
+ hx-get="/api/v1/general-page/header{{ if .QueryString }}?{{ .QueryString }}{{ end }}" hx-trigger="load" hx-target="this" hx-swap="innerHTML">
</div>
+ <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="border-t-4 border-dotted border-main-dark mb-[0.8vmin]">
- {{ block "body" . }}{{ end }}
+ <div id="general-page-body" class="flex flex-col max-h-[calc(100%-7vmax)] ar-lt-1.1:max-h-[calc(100%-25vh)] grow"
+ hx-get="/api/v1/general-page/body{{ if .QueryString }}?{{ .QueryString }}{{ end }}" hx-trigger="load" hx-target="this" hx-swap="innerHTML">
+ </div>
+ <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"></div>
- <div class="flex flex-row mt-[0.8vmin] mb-[0.4vmin]">
- <p class="grow text-[0.8vmax]/[0.9] font-spectral italic text-right text-secondary mr-2">
- All the photos on <a href="https://saya.today/">saya.today</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 src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" alt="" style="max-width:1.2vh; max-height:1.2vh;">
- <img src="https://mirrors.creativecommons.org/presskit/icons/by.svg" alt="" style="max-width:1.2vh; max-height:1.2vh;">
- <img src="https://mirrors.creativecommons.org/presskit/icons/sa.svg" alt="" style="max-width:1.2vh; max-height:1.2vh;">
+ <div id="general-page-footer" class="flex flex-row mt-[0.8vmin] mb-[0.4vmin]"
+ hx-get="/api/v1/general-page/footer{{ if .QueryString }}?{{ .QueryString }}{{ end }}" hx-trigger="load" hx-target="this" hx-swap="innerHTML">
</div>
+ <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>
<hr class="border-t-4 border-dotted border-main-dark mb-[0.8vmin]">
</div>
@@ -86,6 +207,15 @@
</div>
<script src="https://f003.backblazeb2.com/file/sayana-static/libs/htmx/2.0.6/htmx.min.js"></script>
+ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/lightgallery.min.js"></script>
+ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-zoom.min.js"></script>
+ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-thumbnail.min.js"></script>
+ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.js"></script>
+
+ <div id="general-page-bottom-embeds" class="flex"
+ hx-get="/api/v1/general-page/bottom-embeds{{ if .QueryString }}?{{ .QueryString }}{{ end }}" hx-trigger="load" hx-target="this" hx-swap="innerHTML">
+ </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');
@@ -198,7 +328,13 @@
});
</script>
- {{ block "footer" . }}{{ end }}
+ <script>
+ let decorResizeTimeout;
+ window.addEventListener('resize', function() {
+ clearTimeout(decorResizeTimeout);
+ decorResizeTimeout = setTimeout(switchThemeDecor, 300);
+ });
+ </script>
</body>
</html>
diff --git a/views/pages/blog-catalogue.html b/views/pages/blog-catalogue.html
index 9fa8ea7..eccafd6 100644
--- a/views/pages/blog-catalogue.html
+++ b/views/pages/blog-catalogue.html
@@ -1,44 +1,47 @@
{{ define "body" }}
-<div class="flex flex-row ar-lt-0.8:flex-col max-h-[calc(100%-7vmax)] ar-lt-0.8:max-h-[calc(100%-25vh)] flex-1 text-[1vmax]">
+<div class="flex flex-row ar-lt-1.1:flex-col text-[1vmax] h-[100%]">
<form hx-get="/api/v1/blog-search" hx-vals='{"lang": "{{ .Lang }}"}' hx-target=".blog-cards" hx-swap="innerHTML"
- class="tags-list ar-gt-0.8:min-w-[10vh] ar-gt-0.8:max-w-[20vh] ar-gt-0.8:w-fit ar-lt-0.8:w-[100%] flex shrink-0 flex-col overflow-y-auto ar-gt-0.8:mr-[1.2vmin]">
- <fieldset>
- <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.TagsHeader }}</legend>
- <div class="flex flex-col ar-lt-0.8:grid grid-cols-5 grid-flow-row-dense">
- <div class="m-[0.4vmin]">
- <label class="font-bold"><input type="checkbox" id="tagsAllCheckbox" onclick="selectAll();"> {{ .L.BlogSearch.ChooseAllTags }}</label>
+ class="tags-list ar-gt-1.1:min-w-[10vh] ar-gt-1.1:max-w-[20vh] ar-gt-1.1:w-fit ar-lt-1.1:w-[100%] ar-lt-1.1:max-h-[25%] flex shrink-0 flex-col ar-gt-1.1:mr-[1.2vmin]">
+ <div class="flex flex-col overflow-y-auto">
+ <fieldset>
+ <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.TagsHeader }}</legend>
+ <div class="flex flex-col ar-lt-1.1:grid grid-cols-5 grid-flow-row-dense">
+ <div class="m-[0.4vmin]">
+ <label class="font-bold"><input type="checkbox" id="tagsAllCheckbox" onclick="selectAll();"> {{ .L.BlogSearch.ChooseAllTags }}</label>
+ </div>
+ {{- range .Tags }}
+ <div class="m-[0.4vmin]">
+ <label><input type="checkbox" id="tag{{ .Name }}Checkbox" name="tags[]" value="{{ .Name }}" onclick="contextAll();" {{ if contains $.QueryTags .Name }}checked{{ end }}> {{ .Name }} <span class="text-secondary italic">{{ .Count }}</span></label>
+ </div>
+ {{- end }}
</div>
- {{- range .Tags }}
- <div class="m-[0.4vmin]">
- <label><input type="checkbox" id="tag{{ .Name }}Checkbox" name="tags[]" value="{{ .Name }}" onclick="contextAll();" {{ if contains $.QueryTags .Name }}checked{{ end }}> {{ .Name }} <span class="text-secondary italic">{{ .Count }}</span></label>
+ </fieldset>
+ <fieldset class="mt-[0.8vmin]">
+ <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.OrderByHeader }}</legend>
+ <div class="flex flex-col ar-lt-1.1:grid grid-cols-3 grid-rows-2 grid-flow-col">
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortTitleAsc" name="sort" value="titleAsc" {{ if eq .QuerySort "titleAsc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-a-z"></i></label>
+ </div>
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortTitleDesc" name="sort" value="titleDesc" {{ if eq .QuerySort "titleDesc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-z-a"></i></label>
+ </div>
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortActionDateAsc" name="sort" value="actionDateAsc" {{ if eq .QuerySort "actionDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
+ </div>
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortActionDateDesc" name="sort" value="actionDateDesc" {{ if eq .QuerySort "actionDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
+ </div>
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortPublicationDateAsc" name="sort" value="publicationDateAsc" {{ if eq .QuerySort "publicationDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
+ </div>
+ <div class="m-[0.4vmin]">
+ <label><input type="radio" id="sortPublicationDateDesc" name="sort" value="publicationDateDesc" {{ if eq .QuerySort "publicationDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
+ </div>
</div>
- {{- end }}
- </div>
- </fieldset>
- <fieldset class="mt-[0.8vmin]">
- <legend class="font-bold w-[100%] text-center">{{ .L.BlogSearch.OrderByHeader }}</legend>
- <div class="flex flex-col ar-lt-0.8:grid grid-cols-3 grid-rows-2 grid-flow-col">
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortTitleAsc" name="sort" value="titleAsc" {{ if eq .QuerySort "titleAsc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-a-z"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortTitleDesc" name="sort" value="titleDesc" {{ if eq .QuerySort "titleDesc" }}checked{{ end }}> {{ .L.BlogSearch.TitleOrdered }} <i class="fas fa-arrow-down-z-a"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortActionDateAsc" name="sort" value="actionDateAsc" {{ if eq .QuerySort "actionDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortActionDateDesc" name="sort" value="actionDateDesc" {{ if eq .QuerySort "actionDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.ActionDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortPublicationDateAsc" name="sort" value="publicationDateAsc" {{ if eq .QuerySort "publicationDateAsc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-1-9"></i></label>
- </div>
- <div class="m-[0.4vmin]">
- <label><input type="radio" id="sortPublicationDateDesc" name="sort" value="publicationDateDesc" {{ if eq .QuerySort "publicationDateDesc" }}checked{{ end }}> {{ .L.BlogSearch.PublicationDateOrdered }} <i class="fas fa-arrow-down-9-1"></i></label>
- </div>
- </div>
- </fieldset>
- <div class="flex flex-row bg-background-light my-[2vmin] p-[0.4vmin] rounded-[0.4vmin] justify-items-center">
+ </fieldset>
+ </div>
+ <hr class="border-t-[0.2vmax] border-dotted border-main-dark my-[0.4vmin]">
+ <div class="flex flex-row grow bg-background-light my-[2vmin] p-[0.4vmin] rounded-[0.4vmin] justify-items-center">
<i onclick="defaultSearchParams(); cleanHrefParams();" class="fas fa-rotate-left flex-1 text-center text-[1.5vmax] hover:bg-background-dark cursor-pointer transition-colors duration-300"></i>
<div class="w-[0.5vmin] bg-background-dark grow-0"></div>
<button class="flex-1" type="submit">
@@ -54,9 +57,7 @@
Loading...
</div>
</div>
-{{ end }}
-{{ define "footer" }}
<script>
function selectAll() {
const tagsContainers = document.querySelectorAll('form.tags-list');
@@ -97,6 +98,7 @@
function cleanHrefParams() {
const url = new URL(window.location.href);
url.search = '';
+
window.history.pushState({}, '', url.toString());
}
@@ -136,23 +138,27 @@
window.history.pushState({}, '', url.toString());
}
- document.addEventListener('DOMContentLoaded', contextAll);
-</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') {
+ contextAll();
-<script>
- 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();
+ 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
index 755744d..863b417 100644
--- a/views/pages/blog-page.html
+++ b/views/pages/blog-page.html
@@ -1,76 +1,96 @@
-{{ define "header" }}
-<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lightgallery.min.css">
-<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-zoom.min.css">
-<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-thumbnail.min.css">
-{{- if .MapLocationX }}
-<link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css">
-{{- end }}
+{{ define "top-embeds" }}
+<script>
+ let galleryMap = new Map();
+ let map;
-<style>
- .map-container .leaflet-container {
- width: 100% !important;
- height: 100% !important;
- }
-</style>
+ window.addEventListener('popout', (e) => {
+ map.remove();
+ galleryMap.forEach((_, g, m) => {
+ g.destroy();
+ });
+ galleryMap.clear();
+ map = null;
+ galleryMap = null;
+ }, {once: true});
+</script>
{{ end }}
{{ define "body" }}
-<div class="bg-background-light flex flex-col grow overflow-y-auto inset-shadow p-[2.4vmin] max-h-[calc(100%-7vmax)] ar-lt-0.8:max-h-[calc(100%-25vh)]">
+<div class="bg-background-light flex flex-col inset-shadow p-[2.4vmin] overflow-y-auto">
{{ .ParsedMarkdown }}
{{- if .MapLocationX }}
<hr class="border-t-4 border-dotted border-main-dark mt-[0.8vmin] mb-[0.8vmin] w-[80%] ml-auto mr-auto">
- <div id="map-container" class="relative p-[0.8vmin] flex-none ml-auto mr-auto w-[60%] ar-lt-0.8:w-[80%] h-[40vh] ar-lt-0.8:h-[30vh]"></div>
+ <div id="map-container" class="relative p-[0.8vmin] flex-none ml-auto mr-auto w-[60%] ar-lt-1.1:w-[80%] h-[40vh] ar-lt-1.1:h-[30vh]"></div>
<hr class="border-t-4 border-dotted border-main-dark mt-[0.8vmin] mb-[0.8vmin] w-[80%] ml-auto mr-auto">
+
+ <script>
+ function initLocationMap(id, x, y, relativeErrorMeters = 0) {
+ map = L.map(id).setView([x, y], 8);
+
+ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ maxZoom: 18,
+ attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
+ }).addTo(map);
+
+ if (relativeErrorMeters != 0) {
+ var circle = L.circle([x, y], {
+ color: '#8a9d8a',
+ fillColor: '#8a9d8a',
+ fillOpacity: 0.15,
+ radius: relativeErrorMeters
+ }).addTo(map);
+ }
+
+ var marker = L.marker([x, y], {
+ title: '{{ .Title }}',
+ }).addTo(map)
+ .bindPopup('<span><b>{{ .Title }}</b><br><a href="https://www.openstreetmap.org/#map=13/{{ .MapLocationX }}/{{ .MapLocationY }}">{{ .MapLocationX }}, {{ .MapLocationY }}</a></span>')
+ .openPopup();
+ }
+
+ document.addEventListener('htmx:afterRequest', (e) => {
+ if (e.detail.target.id == 'general-page-body') {
+ initLocationMap(
+ 'map-container',
+ {{ .MapLocationX }},
+ {{ .MapLocationY }},
+ {{ .MapLocationAreaMeters }}
+ );
+ }
+ }, {once: true});
+ </script>
{{- end }}
</div>
{{ end }}
{{ define "footer" }}
-<script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/lightgallery.min.js"></script>
-<script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-zoom.min.js"></script>
-<script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-thumbnail.min.js"></script>
-{{- if .MapLocationX }}
-<script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.js"></script>
+<div hx-get="/api/v1/like" hx-target="this" hx-swap="outerHTML" hx-trigger="load"></div>
+{{ end }}
+{{ define "bottom-embeds" }}
<script>
- var map;
-
- function initLocationMap(id, x, y, relativeErrorMeters = 0) {
- map = L.map(id).setView([x, y], 8);
+ let galleryResizeTimeout;
- L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 18,
- attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
- }).addTo(map);
-
- if (relativeErrorMeters != 0) {
- var circle = L.circle([x, y], {
- color: '#8a9d8a',
- fillColor: '#8a9d8a',
- fillOpacity: 0.15,
- radius: relativeErrorMeters
- }).addTo(map);
- }
-
- var marker = L.marker([x, y], {
- title: '{{ .Title }}',
- }).addTo(map)
- .bindPopup('<span><b>{{ .Title }}</b><br><a href="https://www.openstreetmap.org/#map=13/{{ .MapLocationX }}/{{ .MapLocationY }}">{{ .MapLocationX }}, {{ .MapLocationY }}</a></span>')
- .openPopup();
+ function resizeCb() {
+ clearTimeout(galleryResizeTimeout);
+ galleryResizeTimeout = setTimeout(() => {
+ if (map !== undefined) {
+ map.invalidateSize();
+ }
+ var oldGalleryMap = new Map(galleryMap);
+ oldGalleryMap.forEach((createFunc, g, map) => {
+ galleryMap.delete(g);
+ g.destroy();
+ createFunc();
+ });
+ }, 300);
}
- document.addEventListener('DOMContentLoaded', () => {initLocationMap(
- 'map-container',
- {{ .MapLocationX }},
- {{ .MapLocationY }},
- {{ .MapLocationAreaMeters }}
- )});
+ window.addEventListener('resize', resizeCb);
- window.addEventListener('resize', function() {
- setTimeout(() => {
- map.invalidateSize();
- }, 100);
+ document.addEventListener('popout', (e) => {
+ window.removeEventListener('resize', resizeCb);
+ galleryResizeTimeout = null;
});
</script>
-{{- end }}
{{ end }} \ No newline at end of file
diff --git a/views/pages/global-map.html b/views/pages/global-map.html
index cbb6c7d..a844e06 100644
--- a/views/pages/global-map.html
+++ b/views/pages/global-map.html
@@ -11,9 +11,11 @@
{{ block "header" . }}{{ end }}
<link href="/output.css" rel="stylesheet">
<link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css">
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/MarkerCluster.css">
+ <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css">
</head>
-<body data-theme="ram" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-row ar-lt-0.8:flex-col">
+<body data-theme="ram" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-row ar-lt-1.1:flex-col">
<script>
function switchTheme(theme) {
@@ -38,15 +40,15 @@
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
</script>
- <div id="sidebar" class="bg-sidebar flex sticky flex-col ar-gt-0.8:items-center shadow-2xl z-20 w-[5vw] ar-lt-0.8:w-screen h-screen ar-lt-0.8:h-[8vh]">
- <div class="logo-custom ar-lt-0.8:hidden text-sidebar font-patua font-extrabold text-center relative z-20">
+ <div id="sidebar" class="bg-sidebar flex sticky flex-col ar-gt-1.1:items-center shadow-2xl z-20 w-[5vw] ar-lt-1.1:w-screen h-screen ar-lt-1.1:h-[8vh]">
+ <div class="logo-custom ar-lt-1.1:hidden text-sidebar font-patua font-extrabold text-center relative z-20">
saya.today
</div>
- <div class="text-[3vw] ar-lt-0.8:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-0.8:flex-row gap-0 relative z-20">
- <i onclick="location.href='/';" class="fas fa-home w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/blog';" class="fas fa-search w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
- <i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-0.8:w-[8vh] h-[5vw] ar-lt-0.8:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <div class="text-[3vw] ar-lt-1.1:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-1.1:flex-row gap-0 relative z-20">
+ <i onclick="location.href='/{{ .Lang }}';" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="location.href='/{{ .Lang }}/blog';" class="fas fa-search w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
</div>
<div class="theme-wheel" id="theme-wheel">
<div class="theme-icon" data-theme="olive"></div>
@@ -56,10 +58,11 @@
</div>
</div>
- <div id="map-container" class="bg-background-dark flex z-10 w-[95vw] ar-lt-0.8:w-screen h-screen ar-lt-0.8:h-[92vh]"></div>
+ <div id="map-container" class="bg-background-dark flex z-10 w-[95vw] ar-lt-1.1:w-screen h-screen ar-lt-1.1:h-[92vh]"></div>
<script src="https://f003.backblazeb2.com/file/sayana-static/libs/htmx/2.0.6/htmx.min.js"></script>
<script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.js"></script>
+ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
<script>
const themeWheel = document.getElementById('theme-wheel');
@@ -174,6 +177,27 @@
<script>
var map;
+ var markers = L.markerClusterGroup();
+
+ function createCustomIcon(color, borderColor = "var(--main-light-color)") {
+ const svgIcon = `
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M12 1C7.5 1 4 4.5 4 9c0 6.5 8 14 8 14s8-7.5 8-14c0-4.5-3.5-8-8-8zm0 11c-1.5 0-3-1.5-3-3s1.5-3 3-3 3 1.5 3 3-1.5 3-3 3z"
+ fill="${color}"
+ stroke="${borderColor}"
+ stroke-width="1"
+ stroke-linejoin="round"/>
+ </svg>
+ `;
+
+ 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 }}], 4);
@@ -182,6 +206,8 @@
maxZoom: 18,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
+
+ map.addLayer(markers);
}
function stringToColor(str) {
@@ -212,13 +238,15 @@
}
var marker = L.marker([x, y], {
+ icon: createCustomIcon(titleColor),
title: title,
- }).addTo(map)
- .bindPopup(`
+ }).bindPopup(`
<div class="flex flex-row justify-center justify-items-center">
- <img onclick="location.href='${link}';" class="cursor-pointer object-cover rounded-[10%] select-none w-[3vmax] h-[3vmax] mr-[0.5vmax]" src="https://f003.backblazeb2.com/file/sayana-photos/thumbnails/${thumbnail}.webp">
+ <img onclick="location.href='${link}';" class="cursor-pointer object-cover rounded-[10%] select-none w-[3vmax] h-[3vmax] mr-[0.5vmax]" src="https://f003.backblazeb2.com/file/sayana-photos/webp-320p/${thumbnail}.webp">
<span><b><a href="${link}">${title}</a></b><br><a href="https://www.openstreetmap.org/#map=13/${x}/${y}">${x}, ${y}</a></span>
</div>`);
+
+ markers.addLayer(marker);
}
document.addEventListener('DOMContentLoaded', () => {
@@ -235,7 +263,5 @@
});
</script>
- {{ block "footer" . }}{{ end }}
-
</body>
</html>
diff --git a/views/pages/home-page.html b/views/pages/home-page.html
new file mode 100644
index 0000000..6fd716b
--- /dev/null
+++ b/views/pages/home-page.html
@@ -0,0 +1,121 @@
+{{ define "body" }}
+<div class="bg-background-light flex flex-row ar-lt-0.6:flex-col w-full h-full inset-shadow overflow-y-auto text-[1vmax]/[2] tracking-[0.04vmin]">
+ <div class="ar-gt-0.6:flex-3/5 justify-center content-start p-[5%]">
+ <div class="flex flex-col justify-start items-start bg-background-dark mb-[2vmax]">
+ <p class="text-[3vmax]/[2] tracking-[0.2vmin] uppercase w-full font-spectral italic text-left
+ border-l-[0.4vmax] border-solid border-(--background-dark-color)
+ bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.Hymn1 }}</p>
+ <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
+ <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn2 }}</p>
+ <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn3 }}</p>
+ <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn4 }}</p>
+ </div>
+
+ <div class="flex flex-col justify-center items-center">
+ <p class="text-[2vmax] w-full font-spectral italic text-left
+ border-l-[0.4vmax] border-solid border-(--background-dark-color)
+ bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.DidYouKnowThat }}</p>
+ <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
+ <ul class="w-full text-left list-[circle]">
+ <li class="ml-[2vmax] mb-[0.8vmin]">{{ index .FunFacts 0 }}</li>
+ <li class="ml-[2vmax] mb-[0.8vmin]">{{ index .FunFacts 1 }}</li>
+ <li class="ml-[2vmax]">{{ index .FunFacts 2 }}</li>
+ </ul>
+ </div>
+ </div>
+
+ <div class="ar-gt-0.6:flex-2/5 justify-center content-start p-[5%]">
+ <div class="flex flex-col justify-center items-start mb-[2vmax]">
+ <p class="text-[2vmax] w-full font-spectral italic text-left
+ border-l-[0.4vmax] border-solid border-(--background-dark-color)
+ bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.Contacts }}</p>
+ <a href="https://t.me/EarlInisMona">
+ <i class="fa-brands fa-telegram w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
+ <span class="font-bold">Telegram:</span>
+ <span>@EarlInisMona</span>
+ </a>
+ <a href="https://discord.com/users/356057270951346176">
+ <i class="fa-brands fa-discord w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
+ <span class="font-bold">Discord:</span>
+ <span>montferrat</span>
+ </a>
+ <a href="mailto:saya.andy@posteo.com">
+ <i class="fas fa-envelope w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
+ <span class="font-bold">E-mail:</span>
+ <span>saya.andy@posteo.com</span>
+ </a>
+ </div>
+
+ <div class="flex relative aspect-square justify-center content-center mb-[2vmax]">
+ {{- 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="https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/{{ .GifName }}"
+ class="home-page-gif z-49 -rotate-12 max-w-[70%] max-h-[70%] border-[1vmin] border-(--background-dark-color) 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-[2vmax] w-full font-spectral italic text-left
+ border-l-[0.4vmax] border-solid border-(--background-dark-color)
+ bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.SidebarDescription }}</p>
+ <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
+ <div class="w-full grid grid-cols-[1fr_4fr] content-center items-center
+ [&>*:nth-child(4n+2)]:bg-(--background-medium-color) [&>*:nth-child(4n+3)]:bg-(--background-medium-color)" style="container-type: inline-size;">
+ <i class="fas fa-home w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
+ <p class="p-[0.4vmax]">{{ .L.HomePage.HomePageDescription }}</p>
+ <i class="fas fa-search w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
+ <p class="p-[0.4vmax]">{{ .L.HomePage.BlogSearchDescription }}</p>
+ <i class="fas fa-map w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
+ <p class="p-[0.4vmax]">{{ .L.HomePage.MarkerMapDescription }}</p>
+ <i class="fas fa-swatchbook w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
+ <p class="p-[0.4vmax]">{{ .L.HomePage.ThemeSwitchDescription }}</p>
+ </div>
+ </div>
+ </div>
+</div>
+{{ end }}
diff --git a/views/partials/blog-page-like-button.html b/views/partials/blog-page-like-button.html
new file mode 100644
index 0000000..a16e8c0
--- /dev/null
+++ b/views/partials/blog-page-like-button.html
@@ -0,0 +1,6 @@
+<button
+ hx-put="/api/v1/like" hx-vals='{"like": {{ not .Liked }}}' hx-target="this" hx-swap="outerHTML" hx-trigger="click"
+ class="text-[0.8vmax]/[0.9] font-spectral text-left px-[0.4vmax] py-[0.2vmax] {{ if .Liked }}bg-main-light hover:bg-main-medium text-background-dark border-inset{{ else }}bg-main-dark hover:bg-main-medium text-background-light border-outset{{ end }} cursor-pointer border-[0.2vmax] border-background-dark">
+ <i class="fas fa-thumbs-up w-[0.8vmax] h-[0.8vmax]"></i>
+ <span class="italic ml-[0.2vmax] text-background-light">({{ .LikedCount }})</span>
+</button> \ No newline at end of file
diff --git a/views/partials/catalogue-blog-cards.html b/views/partials/catalogue-blog-cards.html
index 406ef9b..37b3f57 100644
--- a/views/partials/catalogue-blog-cards.html
+++ b/views/partials/catalogue-blog-cards.html
@@ -1,10 +1,10 @@
{{- range .BlogPages }}
<hr class="first-of-type:hidden border-t-[0.3vh] my-[0.8vmin] border-dotted border-main-dark w-[80%] mx-auto">
<div class="m-[0.4vmin] flex flex-row justify-center justify-items-center">
- <img onclick="location.href='{{ .ArticleLink }}';" class="cursor-pointer object-cover rounded-[10%] select-none w-[10vmin] h-[10vmin] aspect-square my-[0.4vmin] mr-[0.8vmin]" src="https://f003.backblazeb2.com/file/sayana-photos/thumbnails/{{ .Thumbnail }}.webp">
+ <img onclick="changeUrl('{{ .ArticleLink }}');" class="cursor-pointer object-cover rounded-[10%] select-none w-[10vmin] h-[10vmin] aspect-square my-[0.4vmin] mr-[0.8vmin]" src="https://f003.backblazeb2.com/file/sayana-photos/webp-320p/{{ .Thumbnail }}.webp">
<div class="grow my-[0.4vmin] mx-[0.8vmin] flex flex-col justify-center">
<div class="flex flex-row gap-[5%] max-w-[100%]">
- <a href="{{ .ArticleLink }}" class="flex-9/12 grow-0 block text-[1vmax] cursor-pointer">
+ <a onclick="changeUrl('{{ .ArticleLink }}');" class="flex-9/12 grow-0 block text-[1vmax] cursor-pointer">
<span class="font-extrabold">{{ .Title }}</span>
<span class="font-extrabold select-none text-secondary">//</span>
<span class="italic text-secondary">{{ .ActionDate }}</span>
@@ -12,6 +12,13 @@
<p class="flex-3/12 grow-0 text-[1vmax] italic text-secondary text-right">{{ .PublishedTime }}</p>
</div>
<p class="text-[1vmax] text-main-dark">{{ .ShortDescription }}</p>
+ <p class="text-[1vmax] text-secondary italic">
+ <i class="fas fa-thumbs-up w-[1vmax] h-[1vmax]"></i>
+ <span>{{ .LikeCount }}</span>
+ <span class="font-extrabold select-none">//</span>
+ <i class="fas fa-eye w-[1vmax] h-[1vmax]"></i>
+ <span>{{ .ViewCount }}</span>
+ </p>
<p class="text-[1vmax] text-secondary">{{ $.L.TagsLabel }} {{ template "catalogue-blog-card-tags.html" . }}</p>
</div>
</div>
diff --git a/views/partials/general-page-body.html b/views/partials/general-page-body.html
new file mode 100644
index 0000000..4686ea1
--- /dev/null
+++ b/views/partials/general-page-body.html
@@ -0,0 +1,2 @@
+<title>SAYA TODAY // {{ .Title }}</title>
+{{ 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..af6aec9
--- /dev/null
+++ b/views/partials/general-page-footer.html
@@ -0,0 +1,7 @@
+{{ block "footer" . }}{{ end }}
+<p class="grow content-center text-[1vmax]/[1] font-spectral italic text-right text-secondary mr-2">
+ All the photos on <a href="https://saya.today/">saya.today</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-[1vmax] max-h-[1vmax] self-center" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" alt="CC">
+<img class="max-w-[1vmax] max-h-[1vmax] self-center" src="https://mirrors.creativecommons.org/presskit/icons/by.svg" alt="BY">
+<img class="max-w-[1vmax] max-h-[1vmax] self-center" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg" alt="SA"> \ No newline at end of file
diff --git a/views/partials/general-page-header.html b/views/partials/general-page-header.html
new file mode 100644
index 0000000..6cb87b7
--- /dev/null
+++ b/views/partials/general-page-header.html
@@ -0,0 +1,8 @@
+<div {{ if .PublishedDate }} hx-get="/api/v1/tz" hx-vals='js:{timestamp: "{{ .PublishedDate }}", tz: clientTimeZone}' hx-target="#published-date" hx-swap="innerHTML" hx-trigger="load" {{ end }}
+ class="flex flex-row mb-[0.4vmin]">
+ <i onclick="changeUrl('/../', true);" class="fas fa-circle-left hover:bg-main-dark hover:bg-opacity-10 cursor-pointer transition-colors duration-300 rounded-md text-[2vmax] mt-auto mb-auto px-[0.8vmin]"></i>
+ <p class="text-[2.5vmin] font-spectral italic font-extrabold select-none mt-auto pl-[0.8vmin] pr-[1.2vmin]">//</p>
+ <p class="text-[2.5vmin] font-spectral italic text-left mt-auto">{{ .Title }}</p>
+ <p id="published-date" class="grow text-[1.75vmin] font-spectral text-secondary text-right mt-auto">{{ .PublishedDate }}</p>
+</div>
+{{ block "header" . }}{{ end }}
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