Revamped headings for person view

This commit is contained in:
Simon Martens
2025-09-21 22:25:51 +02:00
parent b8665b6468
commit cabc896ae8
6 changed files with 534 additions and 454 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -26,8 +26,9 @@
{{ else }} {{ else }}
<div class="max-w-full mx-auto px-8 py-8"> <div class="max-w-full mx-auto px-8 py-8">
<div class="mb-10"> <div class="mb-10 2xl:mb-0">
<div class="bg-white px-6 py-4 rounded mb-6"> <!-- Main header - hidden on 2xl+ screens when scrollspy is visible -->
<div class="bg-white px-6 py-4 rounded mb-6 2xl:hidden">
{{ if eq .model.Search "autoren" }} {{ if eq .model.Search "autoren" }}
<h1 class="text-4xl font-bold text-gray-900 mb-2">Autor:innen</h1> <h1 class="text-4xl font-bold text-gray-900 mb-2">Autor:innen</h1>
<p class="text-gray-700 text-lg">Personen, die Beiträge in der Zeitung verfasst haben</p> <p class="text-gray-700 text-lg">Personen, die Beiträge in der Zeitung verfasst haben</p>
@@ -42,6 +43,7 @@
<input type="checkbox" <input type="checkbox"
class="form-checkbox h-5 w-5 text-red-600 focus:ring-red-500 focus:border-red-500 checked:bg-red-600 checked:border-red-600 rounded" class="form-checkbox h-5 w-5 text-red-600 focus:ring-red-500 focus:border-red-500 checked:bg-red-600 checked:border-red-600 rounded"
{{ if eq .model.Search "autoren" }}checked{{ end }} {{ if eq .model.Search "autoren" }}checked{{ end }}
autocomplete="off"
hx-get="{{ if eq .model.Search "autoren" }}/akteure/a{{ else }}/akteure/autoren{{ end }}" hx-get="{{ if eq .model.Search "autoren" }}/akteure/a{{ else }}/akteure/autoren{{ end }}"
hx-target="body" hx-target="body"
hx-push-url="true"> hx-push-url="true">

View File

@@ -1,6 +1,7 @@
<div class="max-w-full mx-auto px-8 py-8"> <div class="max-w-full mx-auto px-8 py-8">
<div class="mb-10"> <div class="mb-10 2xl:mb-0">
<div class="bg-white px-6 py-4 rounded mb-6"> <!-- Main header - hidden on 2xl+ screens when scrollspy is visible -->
<div class="bg-white px-6 py-4 rounded mb-6 2xl:hidden">
<h1 class="text-4xl font-bold text-gray-900 mb-2">Autor:innen</h1> <h1 class="text-4xl font-bold text-gray-900 mb-2">Autor:innen</h1>
<p class="text-gray-700 text-lg">Personen, die Beiträge in der Zeitung verfasst haben</p> <p class="text-gray-700 text-lg">Personen, die Beiträge in der Zeitung verfasst haben</p>
@@ -10,6 +11,7 @@
<input type="checkbox" <input type="checkbox"
class="form-checkbox h-5 w-5 text-red-600 focus:ring-red-500 focus:border-red-500 checked:bg-red-600 checked:border-red-600 rounded" class="form-checkbox h-5 w-5 text-red-600 focus:ring-red-500 focus:border-red-500 checked:bg-red-600 checked:border-red-600 rounded"
checked checked
autocomplete="off"
hx-get="/akteure/a" hx-get="/akteure/a"
hx-target="body" hx-target="body"
hx-push-url="true"> hx-push-url="true">

View File

@@ -4,7 +4,47 @@
{{- $sorted := .Sorted -}} {{- $sorted := .Sorted -}}
<div class="hidden 2xl:block w-96 flex-shrink-0"> <div class="hidden 2xl:block w-96 flex-shrink-0">
<div class="sticky top-0 max-h-screen bg-white rounded py-4 flex flex-col "> <div class="sticky top-0 max-h-screen bg-white rounded py-4 flex flex-col">
<!-- Compact header for 2xl+ screens -->
<div class="px-3 pb-4 border-b border-gray-200 mb-4">
{{ if eq .Search "autoren" }}
<h2 class="text-2xl font-bold font-serif text-gray-900 mb-1">Autor:innen</h2>
<p class="text-base text-gray-600 mb-3">Personen, die Beiträge in der Zeitung verfasst haben</p>
{{ else }}
<h2 class="text-2xl font-bold font-serif text-gray-900 mb-1">Personen & Körperschaften</h2>
<p class="text-base text-gray-600 mb-3">Verzeichnis aller in der Zeitung erwähnten Personen und Institutionen</p>
{{ end }}
<!-- Compact checkbox with scroll to top button -->
<div class="flex items-center justify-between">
<label class="inline-flex items-center">
<input type="checkbox"
class="form-checkbox h-5 w-5 text-red-600 focus:ring-red-500 focus:border-red-500 checked:bg-red-600 checked:border-red-600 rounded"
{{ if eq .Search "autoren" }}checked{{ end }}
autocomplete="off"
hx-get="{{ if eq .Search "autoren" }}/akteure/a{{ else }}/akteure/autoren{{ end }}"
hx-target="body"
hx-push-url="true">
<span class="ml-2 text-base text-gray-700">Nur Autor:innen anzeigen</span>
</label>
<!-- Scroll to top button -->
<button id="sidebar-scroll-to-top"
onclick="window.scrollTo({top: 0, behavior: 'smooth'})"
class="opacity-0 transition-opacity duration-300 {{ if eq .Search "autoren" }}w-8 h-8{{ else }}w-12 h-8 pr-1{{ end }} bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-800 rounded-full flex items-center justify-center cursor-pointer"
title="Nach oben scrollen">
{{ if eq .Search "autoren" }}
<i class="ri-arrow-up-line text-lg font-bold"></i>
{{ else }}
<div class="flex items-center gap-1">
<i class="ri-arrow-up-line text-sm font-bold"></i>
<span class="text-xs font-bold">A-Z</span>
</div>
{{ end }}
</button>
</div>
</div>
<nav class="flex-1 overflow-y-auto overscroll-contain relative" id="scrollspy-nav"> <nav class="flex-1 overflow-y-auto overscroll-contain relative" id="scrollspy-nav">
<!-- Sliding red background element --> <!-- Sliding red background element -->
<div id="scrollspy-slider" class="absolute bg-red-100 rounded-sm transition-all duration-300 ease-out opacity-0 z-0" style="width: calc(100% - 1.5rem); height: 0; top: 0; left: 0.75rem;"></div> <div id="scrollspy-slider" class="absolute bg-red-100 rounded-sm transition-all duration-300 ease-out opacity-0 z-0" style="width: calc(100% - 1.5rem); height: 0; top: 0; left: 0.75rem;"></div>

View File

@@ -833,6 +833,11 @@ function showSimplePopup(button, message) {
// URL navigation functions // URL navigation functions
function scrollToPageFromURL() { function scrollToPageFromURL() {
// Skip auto-scrolling during HTMX navigation to prevent random jumps
if (window.htmxNavigating) {
return;
}
let pageNumber = ""; let pageNumber = "";
let targetContainer = null; let targetContainer = null;
@@ -1188,9 +1193,29 @@ function initializeScrollspy() {
// Store scroll handler reference for cleanup // Store scroll handler reference for cleanup
window.scrollspyScrollHandler = function () { window.scrollspyScrollHandler = function () {
clearTimeout(window.scrollspyTimeout); clearTimeout(window.scrollspyTimeout);
window.scrollspyTimeout = setTimeout(updateActiveLink, 50); window.scrollspyTimeout = setTimeout(() => {
updateActiveLink();
updateSidebarScrollToTopButton();
}, 50);
}; };
function updateSidebarScrollToTopButton() {
const button = document.getElementById("sidebar-scroll-to-top");
if (!button) return;
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const viewportHeight = window.innerHeight;
const shouldShow = scrollTop > viewportHeight * 0.5; // Show after scrolling 50% of viewport
if (shouldShow) {
button.classList.remove("opacity-0");
button.classList.add("opacity-100");
} else {
button.classList.remove("opacity-100");
button.classList.add("opacity-0");
}
}
// Add scroll listener // Add scroll listener
window.addEventListener("scroll", window.scrollspyScrollHandler); window.addEventListener("scroll", window.scrollspyScrollHandler);
@@ -1228,6 +1253,9 @@ function initializeScrollspy() {
// Initial active link update // Initial active link update
updateActiveLink(); updateActiveLink();
// Initial scroll-to-top button update
updateSidebarScrollToTopButton();
} }
// Cleanup scrollspy functionality // Cleanup scrollspy functionality
@@ -1326,6 +1354,24 @@ function setup() {
// HTMX event handling for newspaper layout, scrollspy, and scroll-to-top button // HTMX event handling for newspaper layout, scrollspy, and scroll-to-top button
document.body.addEventListener("htmx:afterSwap", function (event) { document.body.addEventListener("htmx:afterSwap", function (event) {
// Prevent auto-scrolling during HTMX navigation
window.htmxNavigating = true;
// Scroll to top for normal page navigation (not URL anchors)
const currentUrl = window.location.pathname;
const hasPageAnchor = currentUrl.match(/\/\d+$/); // Ends with page number like /1768/42/166
const isAkteureNavigation = currentUrl.includes('/akteure/') || currentUrl.includes('/autoren');
if (!hasPageAnchor && isAkteureNavigation) {
// Small delay to ensure DOM is ready
setTimeout(() => {
window.scrollTo({
top: 0,
behavior: "instant" // Use instant instead of smooth to avoid conflicts
});
}, 50);
}
setTimeout(() => { setTimeout(() => {
if (document.querySelector(".newspaper-page-container")) { if (document.querySelector(".newspaper-page-container")) {
initializeNewspaperLayout(); initializeNewspaperLayout();
@@ -1338,39 +1384,18 @@ function setup() {
if (scrollToTopButton) { if (scrollToTopButton) {
scrollToTopButton.reassessScrollPosition(); scrollToTopButton.reassessScrollPosition();
} }
// Re-enable auto-scrolling after a delay
setTimeout(() => {
window.htmxNavigating = false;
}, 500);
}, 100); }, 100);
}); });
document.body.addEventListener("htmx:afterSettle", function (event) { // Remove duplicate event handlers to prevent multiple initialization
setTimeout(() => { document.body.addEventListener("htmx:beforeRequest", function (event) {
if (document.querySelector(".newspaper-page-container")) { // Set flag to prevent auto-scrolling during navigation
initializeNewspaperLayout(); window.htmxNavigating = true;
}
if (document.querySelector(".author-section")) {
initializeScrollspy();
}
// Reassess scroll-to-top button visibility after page settle
const scrollToTopButton = document.querySelector("scroll-to-top-button");
if (scrollToTopButton) {
scrollToTopButton.reassessScrollPosition();
}
}, 200);
});
document.body.addEventListener("htmx:load", function (event) {
setTimeout(() => {
if (document.querySelector(".newspaper-page-container")) {
initializeNewspaperLayout();
}
if (document.querySelector(".author-section")) {
initializeScrollspy();
}
// Reassess scroll-to-top button visibility after HTMX load
const scrollToTopButton = document.querySelector("scroll-to-top-button");
if (scrollToTopButton) {
scrollToTopButton.reassessScrollPosition();
}
}, 100);
}); });
} }