FIX: double requests on /baende endpoint

This commit is contained in:
Simon Martens
2026-01-30 11:54:55 +01:00
parent 459c15b409
commit 52fecc0d05
7 changed files with 229 additions and 156 deletions

View File

@@ -5808,18 +5808,16 @@ class od extends HTMLElement {
scroll-to-top scroll-to-top
fixed bottom-12 right-8 z-50 fixed bottom-12 right-8 z-50
hidden hidden
bg-gray-800 text-white w-12 h-12
p-2 bg-slate-700 hover:bg-slate-800 text-white
rounded-md rounded border-2 border-slate-600
shadow-sm transition-all duration-200
flex items-center justify-center
cursor-pointer cursor-pointer
text-2xl
hover:opacity-80
transition-opacity
border-0
" "
aria-label="Scroll to top" aria-label="Scroll to top"
> >
<i class="ri-arrow-up-double-line"></i> <i class="ri-arrow-up-double-line text-2xl"></i>
</button> </button>
`, this._button = this.querySelector(".scroll-to-top"), window.addEventListener("scroll", this.handleScroll), this._button.addEventListener("click", this.scrollToTop); `, this._button = this.querySelector(".scroll-to-top"), window.addEventListener("scroll", this.handleScroll), this._button.addEventListener("click", this.scrollToTop);
} }
@@ -8910,206 +8908,206 @@ class Ec extends HTMLElement {
jt && jt.value, this.hasContext = l || u || f || I || U || p || h; jt && jt.value, this.hasContext = l || u || f || I || U || p || h;
let tt = ""; let tt = "";
n && l ? tt = ` n && l ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Reihe Reihe
</div> </div>
<a href="/reihe/${c}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihe/${c}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
` : n && u ? tt = ` ` : n && u ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Person Person
</div> </div>
<a href="/person/${m}/edit/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/person/${m}/edit/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
` : n && f ? tt = ` ` : n && f ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Almanach Almanach
</div> </div>
<a href="/almanach/${A}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${A}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
<a href="/almanach/${A}/contents/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${A}/contents/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Beiträge bearbeiten</span> <span class="text-gray-900">Beiträge bearbeiten</span>
</a> </a>
<a href="/almanach/${A}/contents/new" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${A}/contents/new" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Beitrag</span> <span class="text-gray-900">Neuer Beitrag</span>
</a> </a>
` : n && I && R ? tt = ` ` : n && I && R ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Beitrag Beitrag
</div> </div>
<a href="/almanach/${R}/contents/${$}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${R}/contents/${$}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
<a href="/almanach/${R}/contents/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${R}/contents/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Beiträge bearbeiten</span> <span class="text-gray-900">Beiträge bearbeiten</span>
</a> </a>
<a href="/almanach/${R}/contents/new" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${R}/contents/new" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Beitrag</span> <span class="text-gray-900">Neuer Beitrag</span>
</a> </a>
` : n && p ? tt = ` ` : n && p ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Reihen Reihen
</div> </div>
<a href="/reihen/new/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/new/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Reihe</span> <span class="text-gray-900">Neue Reihe</span>
</a> </a>
` : n && h ? tt = ` ` : n && h ? tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Personen Personen
</div> </div>
<a href="/personen/new/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/new/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Person</span> <span class="text-gray-900">Neue Person</span>
</a> </a>
` : n && U && (tt = ` ` : n && U && (tt = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Seite Seite
</div> </div>
<a href="/redaktion/seiten/?key=${_}" hx-boost="false" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/seiten/?key=${_}" hx-boost="false" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Seite bearbeiten</span> <span class="text-gray-900">Seite bearbeiten</span>
</a> </a>
`); `);
const _i = n ? ` const _i = n ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Erstellen Erstellen
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/almanach-new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach-new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-book-line text-base text-gray-700 mr-2.5"></i> <i class="ri-book-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Band</span> <span class="text-gray-900">Neuer Band</span>
</a> </a>
<a href="/almanach-new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/almanach-new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/reihen/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-stack-line text-base text-gray-700 mr-2.5"></i> <i class="ri-stack-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Reihe</span> <span class="text-gray-900">Neue Reihe</span>
</a> </a>
<a href="/reihen/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/reihen/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/orte/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/orte/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i> <i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Ort</span> <span class="text-gray-900">Neuer Ort</span>
</a> </a>
<a href="/orte/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/orte/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/personen/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Person</span> <span class="text-gray-900">Neue Person</span>
</a> </a>
<a href="/personen/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/personen/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="border-t border-gray-200 my-1"></div> <div class="border-t border-gray-200 my-1"></div>
` : "", vi = n ? ` ` : "", vi = n ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Listen Listen
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/reihen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-stack-line text-base text-gray-700 mr-2.5"></i> <i class="ri-stack-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Reihen</span> <span class="text-gray-900">Reihen</span>
</a> </a>
<a href="/reihen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/reihen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/baende/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/baende/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-book-line text-base text-gray-700 mr-2.5"></i> <i class="ri-book-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bände</span> <span class="text-gray-900">Bände</span>
</a> </a>
<a href="/baende/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/baende/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/orte/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/orte/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i> <i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Orte</span> <span class="text-gray-900">Orte</span>
</a> </a>
<a href="/orte/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/orte/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/personen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Personen</span> <span class="text-gray-900">Personen</span>
</a> </a>
<a href="/personen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/personen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/abkuerzungen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/abkuerzungen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-text text-base text-gray-700 mr-2.5"></i> <i class="ri-text text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Abkürzungen</span> <span class="text-gray-900">Abkürzungen</span>
</a> </a>
<a href="/abkuerzungen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/abkuerzungen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/redaktion/seiten/" hx-boost="false" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/seiten/" hx-boost="false" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-pages-line text-base text-gray-700 mr-2.5"></i> <i class="ri-pages-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Seiten</span> <span class="text-gray-900">Seiten</span>
</a> </a>
<a href="/redaktion/seiten/" target="_blank" hx-boost="false" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/redaktion/seiten/" target="_blank" hx-boost="false" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="border-t border-gray-200 my-1"></div> <div class="border-t border-gray-200 my-1"></div>
` : "", yi = r ? ` ` : "", yi = r ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Administration Administration
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/redaktion/exports/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/exports/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-download-2-line text-base text-gray-700 mr-2.5"></i> <i class="ri-download-2-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Datenexport</span> <span class="text-gray-900">Datenexport</span>
</a> </a>
<a href="/redaktion/exports/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/redaktion/exports/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/user/management/access/User?redirectTo=${a}" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/management/access/User?redirectTo=${a}" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Nutzer einladen</span> <span class="text-gray-900">Nutzer einladen</span>
</a> </a>
<a href="/user/management/access/User?redirectTo=${a}" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/user/management/access/User?redirectTo=${a}" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/user/management?redirectTo=${a}" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/management?redirectTo=${a}" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-2-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-2-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Benutzerverwaltung</span> <span class="text-gray-900">Benutzerverwaltung</span>
</a> </a>
<a href="/user/management?redirectTo=${a}" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/user/management?redirectTo=${a}" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
@@ -9118,7 +9116,7 @@ class Ec extends HTMLElement {
this.innerHTML = ` this.innerHTML = `
<div class="fixed bottom-12 left-8 z-50"> <div class="fixed bottom-12 left-8 z-50">
<!-- Unified Menu Container --> <!-- Unified Menu Container -->
<div class="fab-menu hidden absolute bottom-16 left-0 w-64 bg-white rounded border border-gray-300 shadow transition-all duration-100 ease-out"> <div class="fab-menu hidden absolute bottom-16 left-0 w-64 max-h-[85vh] overflow-y-auto bg-white rounded border border-gray-300 shadow transition-all duration-100 ease-out">
<!-- Contextual actions (always at top when present) --> <!-- Contextual actions (always at top when present) -->
${Me} ${Me}
${Ai} ${Ai}
@@ -9128,15 +9126,15 @@ class Ec extends HTMLElement {
${_i} ${_i}
${vi} ${vi}
${yi} ${yi}
<div class="px-4 py-2"> <div class="px-3 py-1.5">
<div class="font-semibold text-gray-900 text-sm">${t}</div> <div class="font-semibold text-gray-900 text-sm">${t}</div>
<div class="text-xs text-gray-600 truncate">${e}</div> <div class="text-xs text-gray-600 truncate">${e}</div>
</div> </div>
<a href="/user/${i}/edit?redirectTo=${encodeURIComponent(window.location.href)}" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/${i}/edit?redirectTo=${encodeURIComponent(window.location.href)}" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-user-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-user-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Profil bearbeiten</span> <span class="text-gray-900">Profil bearbeiten</span>
</a> </a>
<a href="/logout?redirectTo=${a}" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/logout?redirectTo=${a}" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-logout-box-line text-base text-gray-700 mr-2.5 mb-1"></i> <i class="ri-logout-box-line text-base text-gray-700 mr-2.5 mb-1"></i>
<span class="text-gray-900">Logout</span> <span class="text-gray-900">Logout</span>
</a> </a>
@@ -9158,13 +9156,17 @@ class Ec extends HTMLElement {
t.stopPropagation(), this.nextState(); t.stopPropagation(), this.nextState();
} }
handleClickAway(t) { handleClickAway(t) {
this.contains(t.target) || this.setState("closed"); this.contains(t.target) || (this.hasContext ? this.setState("half") : this.setState("closed"));
} }
nextState() { nextState() {
this.state === "closed" ? this.setState(this.hasContext ? "half" : "full") : this.state === "half" ? this.setState("full") : this.setState("closed"); if (this.hasContext) {
this.setState(this.state === "half" ? "full" : "half");
return;
}
this.state === "closed" ? this.setState("full") : this.setState("closed");
} }
setState(t) { setState(t) {
if (this.state = t, t === "closed") if (this.hasContext && t === "closed" && (t = "half"), this.state = t, t === "closed")
this._menu.style.opacity = "0", this._menu.style.transform = "translateY(8px)", this._fullContent.style.maxHeight = "0", this._fullContent.style.opacity = "0", setTimeout(() => { this._menu.style.opacity = "0", this._menu.style.transform = "translateY(8px)", this._fullContent.style.maxHeight = "0", this._fullContent.style.opacity = "0", setTimeout(() => {
this.state === "closed" && this._menu.classList.add("hidden"); this.state === "closed" && this._menu.classList.add("hidden");
}, 200), this._icon.classList.remove("ri-arrow-up-s-line", "ri-close-line"), this._icon.classList.add("ri-menu-line"), this._button.style.backgroundColor = "", this._button.style.borderColor = "", this._button.classList.remove("shadow-md"), this._button.classList.add("shadow-sm"); }, 200), this._icon.classList.remove("ri-arrow-up-s-line", "ri-close-line"), this._icon.classList.add("ri-menu-line"), this._button.style.backgroundColor = "", this._button.style.borderColor = "", this._button.classList.remove("shadow-md"), this._button.classList.add("shadow-sm");

File diff suppressed because one or more lines are too long

View File

@@ -91,7 +91,7 @@
const query = params.toString(); const query = params.toString();
return query ? `/baende/?${query}` : '/baende/'; return query ? `/baende/?${query}` : '/baende/';
}, },
applyFilter(overrides = {}, indicator = 'body') { applyFilter(overrides = {}, indicator = 'body', sourceEl = null) {
Object.entries(overrides).forEach(([key, value]) => { Object.entries(overrides).forEach(([key, value]) => {
this[key] = value; this[key] = value;
}); });
@@ -102,6 +102,7 @@
target: '#baenderesults', target: '#baenderesults',
swap: 'outerHTML', swap: 'outerHTML',
indicator, indicator,
source: sourceEl || (indicator && document.querySelector(indicator)) || undefined,
}); });
}, },
clearFilters() { clearFilters() {
@@ -116,7 +117,7 @@
if (d !== current) d.open = false; if (d !== current) d.open = false;
}); });
}, },
changeSort(field) { changeSort(field, event = null) {
if (this.sortField === field) { if (this.sortField === field) {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc'; this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else { } else {
@@ -142,7 +143,7 @@
htmx.ajax('GET', `/baende/results/?${queryString}`, { htmx.ajax('GET', `/baende/results/?${queryString}`, {
target: '#baenderesults', target: '#baenderesults',
swap: 'outerHTML', swap: 'outerHTML',
indicator: 'body' source: event?.currentTarget || undefined,
}); });
}, },
updateUrl() { updateUrl() {
@@ -199,7 +200,7 @@ class="container-normal font-sans mt-10">
<div class="mt-2"> <div class="mt-2">
<div class="border-b px-3 border-zinc-300"> <div class="border-b px-3 border-zinc-300">
<!-- Row 1: Filters --> <!-- Row 1: Filters -->
<div class="flex flex-wrap items-end justify-center min-h-14 gap-x-2 gap-y-3 pb-3"> <div class="flex flex-wrap items-end justify-center min-h-14 gap-x-2 gap-y-3 pb-3" hx-boost="false">
<!-- Alphabet navigation toggle --> <!-- Alphabet navigation toggle -->
<div class="relative"> <div class="relative">
<details class="font-sans text-base list-none" data-role="alphabet-toggle" @toggle="alphabetOpen = $el.open; if ($el.open) { closeOtherDropdowns($el); }"> <details class="font-sans text-base list-none" data-role="alphabet-toggle" @toggle="alphabetOpen = $el.open; if ($el.open) { closeOtherDropdowns($el); }">
@@ -215,18 +216,25 @@ class="container-normal font-sans mt-10">
<div class="p-2 w-[26rem]"> <div class="p-2 w-[26rem]">
<a :href="buildPageUrl({ letter: '', offset: 0 })" <a :href="buildPageUrl({ letter: '', offset: 0 })"
hx-indicator="#baende-alphabet-spinner" hx-indicator="#baende-alphabet-spinner"
@click.prevent="alphabetOpen = false; applyFilter({ selectedLetter: '' }, '#baende-alphabet-spinner')" @click.prevent="alphabetOpen = false; $el.closest('details').open = false; applyFilter({ selectedLetter: '' }, '#baende-alphabet-spinner', $el)"
x-show="selectedLetter" x-show="selectedLetter"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
<span>Alle</span> <span>Alle</span>
</a> </a>
<div class="grid grid-cols-13 gap-1 text-sm text-gray-700"> <div class="grid grid-cols-13 gap-1 text-sm text-gray-700" x-effect="
const active = selectedLetter || '';
$el.querySelectorAll('[data-letter]').forEach((el) => {
const isActive = el.dataset.letter === active;
el.classList.toggle('bg-stone-200', isActive);
el.classList.toggle('font-bold', isActive);
});
">
{{- range $_, $ch := $model.letters -}} {{- range $_, $ch := $model.letters -}}
<a :href="buildPageUrl({ letter: '{{ $ch }}', offset: 0 })" <a :href="buildPageUrl({ letter: '{{ $ch }}', offset: 0 })"
hx-indicator="#baende-alphabet-spinner" hx-indicator="#baende-alphabet-spinner"
@click.prevent="alphabetOpen = false; applyFilter({ selectedLetter: '{{ $ch }}' }, '#baende-alphabet-spinner')" @click.prevent="alphabetOpen = false; $el.closest('details').open = false; applyFilter({ selectedLetter: '{{ $ch }}' }, '#baende-alphabet-spinner', $el)"
:class="selectedLetter === '{{ $ch }}' ? 'bg-stone-200 font-bold' : ''" data-letter="{{ $ch }}"
class="text-center py-1 px-2 rounded hover:bg-gray-100 no-underline transition-colors"> class="text-center py-1 px-2 rounded hover:bg-gray-100 no-underline transition-colors">
{{ $ch }} {{ $ch }}
</a> </a>
@@ -253,7 +261,7 @@ class="container-normal font-sans mt-10">
<div class="max-h-64 overflow-auto flex flex-col gap-1 text-sm text-gray-700 border border-stone-100 rounded-sm" data-role="filter-list"> <div class="max-h-64 overflow-auto flex flex-col gap-1 text-sm text-gray-700 border border-stone-100 rounded-sm" data-role="filter-list">
<a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ status: '', offset: 0 })" <a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ status: '', offset: 0 })"
hx-indicator="#baende-status-spinner" hx-indicator="#baende-status-spinner"
@click.prevent="open = false; applyFilter({ status: '' }, '#baende-status-spinner')" @click.prevent="open = false; $el.closest('details').open = false; applyFilter({ status: '' }, '#baende-status-spinner', $el)"
x-show="status" x-show="status"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
@@ -262,7 +270,7 @@ class="container-normal font-sans mt-10">
{{- range $_, $s := $model.filter_statuses -}} {{- range $_, $s := $model.filter_statuses -}}
<a data-role="filter-item" data-label="{{ $s.label }}" :href="buildPageUrl({ status: '{{ $s.value }}', offset: 0 })" <a data-role="filter-item" data-label="{{ $s.label }}" :href="buildPageUrl({ status: '{{ $s.value }}', offset: 0 })"
hx-indicator="#baende-status-spinner" hx-indicator="#baende-status-spinner"
@click.prevent="open = false; applyFilter({ status: '{{ $s.value }}' }, '#baende-status-spinner')" @click.prevent="open = false; $el.closest('details').open = false; applyFilter({ status: '{{ $s.value }}' }, '#baende-status-spinner', $el)"
:class="status === '{{ $s.value }}' ? 'bg-stone-100 font-semibold' : ''" :class="status === '{{ $s.value }}' ? 'bg-stone-100 font-semibold' : ''"
class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors"> class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors">
{{ $s.label }} {{ $s.label }}
@@ -286,14 +294,21 @@ class="container-normal font-sans mt-10">
<div class="p-3"> <div class="p-3">
<a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ person: '', offset: 0 })" <a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ person: '', offset: 0 })"
hx-indicator="#baende-person-spinner" hx-indicator="#baende-person-spinner"
@click.prevent="open = false; applyFilter({ person: '' }, '#baende-person-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ person: '' }, '#baende-person-spinner', $el);
"
x-show="person" x-show="person"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
<span>Alle</span> <span>Alle</span>
</a> </a>
<div class="relative"> <div class="relative">
<input data-role="filter-search" type="search" placeholder="Personen filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" /> <input data-role="filter-search" type="search" autocomplete="off" placeholder="Personen filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" />
<span id="baende-person-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900"> <span id="baende-person-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900">
<i class="ri-loader-4-line spinning" aria-hidden="true"></i> <i class="ri-loader-4-line spinning" aria-hidden="true"></i>
</span> </span>
@@ -302,7 +317,14 @@ class="container-normal font-sans mt-10">
{{- range $_, $a := $model.filter_agents -}} {{- range $_, $a := $model.filter_agents -}}
<a data-role="filter-item" data-label="{{ $a.Name }}" :href="buildPageUrl({ person: '{{ $a.Id }}', offset: 0 })" <a data-role="filter-item" data-label="{{ $a.Name }}" :href="buildPageUrl({ person: '{{ $a.Id }}', offset: 0 })"
hx-indicator="#baende-person-spinner" hx-indicator="#baende-person-spinner"
@click.prevent="open = false; applyFilter({ person: '{{ $a.Id }}' }, '#baende-person-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ person: '{{ $a.Id }}' }, '#baende-person-spinner', $el);
"
:class="person === '{{ $a.Id }}' ? 'bg-stone-100 font-semibold' : ''" :class="person === '{{ $a.Id }}' ? 'bg-stone-100 font-semibold' : ''"
class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors"> class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors">
<span class="filter-list-searchable mr-1">{{ $a.Name }}</span> <span class="filter-list-searchable mr-1">{{ $a.Name }}</span>
@@ -331,14 +353,21 @@ class="container-normal font-sans mt-10">
<div class="p-3"> <div class="p-3">
<a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ user: '', offset: 0 })" <a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ user: '', offset: 0 })"
hx-indicator="#baende-user-spinner" hx-indicator="#baende-user-spinner"
@click.prevent="open = false; applyFilter({ user: '' }, '#baende-user-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ user: '' }, '#baende-user-spinner', $el);
"
x-show="user" x-show="user"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
<span>Alle</span> <span>Alle</span>
</a> </a>
<div class="relative"> <div class="relative">
<input data-role="filter-search" type="search" placeholder="Benutzer filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" /> <input data-role="filter-search" type="search" autocomplete="off" placeholder="Benutzer filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" />
<span id="baende-user-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900"> <span id="baende-user-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900">
<i class="ri-loader-4-line spinning" aria-hidden="true"></i> <i class="ri-loader-4-line spinning" aria-hidden="true"></i>
</span> </span>
@@ -347,7 +376,14 @@ class="container-normal font-sans mt-10">
{{- range $_, $u := $model.filter_users -}} {{- range $_, $u := $model.filter_users -}}
<a data-role="filter-item" data-label="{{ $u.Name }}" :href="buildPageUrl({ user: '{{ $u.Id }}', offset: 0 })" <a data-role="filter-item" data-label="{{ $u.Name }}" :href="buildPageUrl({ user: '{{ $u.Id }}', offset: 0 })"
hx-indicator="#baende-user-spinner" hx-indicator="#baende-user-spinner"
@click.prevent="open = false; applyFilter({ user: '{{ $u.Id }}' }, '#baende-user-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ user: '{{ $u.Id }}' }, '#baende-user-spinner', $el);
"
:class="user === '{{ $u.Id }}' ? 'bg-stone-100 font-semibold' : ''" :class="user === '{{ $u.Id }}' ? 'bg-stone-100 font-semibold' : ''"
class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors"> class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors">
<span class="filter-list-searchable mr-1">{{ $u.Name }}</span> <span class="filter-list-searchable mr-1">{{ $u.Name }}</span>
@@ -371,14 +407,21 @@ class="container-normal font-sans mt-10">
<div class="p-3"> <div class="p-3">
<a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ year: '', offset: 0 })" <a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ year: '', offset: 0 })"
hx-indicator="#baende-year-spinner" hx-indicator="#baende-year-spinner"
@click.prevent="open = false; applyFilter({ year: '' }, '#baende-year-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ year: '' }, '#baende-year-spinner', $el);
"
x-show="year" x-show="year"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
<span>Alle</span> <span>Alle</span>
</a> </a>
<div class="relative"> <div class="relative">
<input data-role="filter-search" type="search" placeholder="Jahre filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" /> <input data-role="filter-search" type="search" autocomplete="off" placeholder="Jahre filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" />
<span id="baende-year-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900"> <span id="baende-year-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900">
<i class="ri-loader-4-line spinning" aria-hidden="true"></i> <i class="ri-loader-4-line spinning" aria-hidden="true"></i>
</span> </span>
@@ -389,7 +432,14 @@ class="container-normal font-sans mt-10">
{{- if eq $y 0 -}}{{- $label = "ohne Jahr" -}}{{- end -}} {{- if eq $y 0 -}}{{- $label = "ohne Jahr" -}}{{- end -}}
<a data-role="filter-item" data-label="{{ $label }}" :href="buildPageUrl({ year: '{{ $y }}', offset: 0 })" <a data-role="filter-item" data-label="{{ $label }}" :href="buildPageUrl({ year: '{{ $y }}', offset: 0 })"
hx-indicator="#baende-year-spinner" hx-indicator="#baende-year-spinner"
@click.prevent="open = false; applyFilter({ year: '{{ $y }}' }, '#baende-year-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ year: '{{ $y }}' }, '#baende-year-spinner', $el);
"
:class="year === '{{ $y }}' ? 'bg-stone-100 font-semibold' : ''" :class="year === '{{ $y }}' ? 'bg-stone-100 font-semibold' : ''"
class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors"> class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors">
{{ $label }} {{ $label }}
@@ -413,14 +463,21 @@ class="container-normal font-sans mt-10">
<div class="p-3"> <div class="p-3">
<a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ place: '', offset: 0 })" <a data-role="filter-item" data-label="Alle" :href="buildPageUrl({ place: '', offset: 0 })"
hx-indicator="#baende-place-spinner" hx-indicator="#baende-place-spinner"
@click.prevent="open = false; applyFilter({ place: '' }, '#baende-place-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ place: '' }, '#baende-place-spinner', $el);
"
x-show="place" x-show="place"
class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors"> class="mb-2 inline-flex w-full items-center justify-center gap-2 rounded bg-orange-100 px-2 py-1 text-sm font-semibold text-orange-800 hover:bg-orange-200 no-underline transition-colors">
<i class="ri-filter-off-line text-base"></i> <i class="ri-filter-off-line text-base"></i>
<span>Alle</span> <span>Alle</span>
</a> </a>
<div class="relative"> <div class="relative">
<input data-role="filter-search" type="search" placeholder="Orte filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" /> <input data-role="filter-search" type="search" autocomplete="off" placeholder="Orte filtern..." class="w-full px-2 py-1 pr-7 border border-stone-200 rounded text-sm" />
<span id="baende-place-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900"> <span id="baende-place-spinner" class="htmx-indicator absolute right-2 top-1/2 -translate-y-1/2 text-slate-900">
<i class="ri-loader-4-line spinning" aria-hidden="true"></i> <i class="ri-loader-4-line spinning" aria-hidden="true"></i>
</span> </span>
@@ -429,7 +486,14 @@ class="container-normal font-sans mt-10">
{{- range $_, $p := $model.filter_places -}} {{- range $_, $p := $model.filter_places -}}
<a data-role="filter-item" data-label="{{ $p.Name }}" :href="buildPageUrl({ place: '{{ $p.Id }}', offset: 0 })" <a data-role="filter-item" data-label="{{ $p.Name }}" :href="buildPageUrl({ place: '{{ $p.Id }}', offset: 0 })"
hx-indicator="#baende-place-spinner" hx-indicator="#baende-place-spinner"
@click.prevent="open = false; applyFilter({ place: '{{ $p.Id }}' }, '#baende-place-spinner')" @click.prevent="
open = false;
const root = $el.closest('details');
const input = root?.querySelector('[data-role=filter-search]');
if (input) { input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); }
root.open = false;
applyFilter({ place: '{{ $p.Id }}' }, '#baende-place-spinner', $el);
"
:class="place === '{{ $p.Id }}' ? 'bg-stone-100 font-semibold' : ''" :class="place === '{{ $p.Id }}' ? 'bg-stone-100 font-semibold' : ''"
class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors"> class="filter-list-row px-2 py-1 rounded-sm hover:bg-stone-100 no-underline transition-colors">
{{ $p.Name }} {{ $p.Name }}

View File

@@ -9,7 +9,7 @@
<div class="flex flex-col items-start gap-0.5 leading-tight"> <div class="flex flex-col items-start gap-0.5 leading-tight">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
@click="changeSort('alm')"> @click="changeSort('alm', $event)">
<span class="font-semibold tracking-wide">Alm-Nr</span> <span class="font-semibold tracking-wide">Alm-Nr</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -26,7 +26,7 @@
:aria-sort="sortField === 'title' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'"> :aria-sort="sortField === 'title' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
@click="changeSort('title')"> @click="changeSort('title', $event)">
<span class="font-semibold tracking-wide">Titel</span> <span class="font-semibold tracking-wide">Titel</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -41,7 +41,7 @@
<div class="flex flex-col items-start gap-0.5 h-full justify-end"> <div class="flex flex-col items-start gap-0.5 h-full justify-end">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm leading-tight" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm leading-tight"
@click="changeSort('responsibility')"> @click="changeSort('responsibility', $event)">
<span class="font-semibold tracking-wide">Herausgeber</span> <span class="font-semibold tracking-wide">Herausgeber</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -53,7 +53,7 @@
</button> </button>
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm leading-tight" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm leading-tight"
@click="changeSort('place')"> @click="changeSort('place', $event)">
<span class="font-semibold tracking-wide">Ortsangabe</span> <span class="font-semibold tracking-wide">Ortsangabe</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -69,7 +69,7 @@
:aria-sort="sortField === 'year' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'"> :aria-sort="sortField === 'year' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
@click="changeSort('year')"> @click="changeSort('year', $event)">
<span class="font-semibold tracking-wide">Jahr</span> <span class="font-semibold tracking-wide">Jahr</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -90,7 +90,7 @@
:aria-sort="sortField === 'signatur' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'"> :aria-sort="sortField === 'signatur' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
@click="changeSort('signatur')"> @click="changeSort('signatur', $event)">
<span class="font-semibold tracking-wide">Signaturen</span> <span class="font-semibold tracking-wide">Signaturen</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{
@@ -106,7 +106,7 @@
<div class="flex flex-col items-start gap-0.5 leading-tight"> <div class="flex flex-col items-start gap-0.5 leading-tight">
<button type="button" <button type="button"
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm" class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
@click="changeSort('updated')"> @click="changeSort('updated', $event)">
<span class="font-semibold tracking-wide">Bearbeitet am</span> <span class="font-semibold tracking-wide">Bearbeitet am</span>
<i class="text-xs opacity-70 transition-colors" <i class="text-xs opacity-70 transition-colors"
:class="{ :class="{

View File

@@ -137,86 +137,86 @@ export class FabMenu extends HTMLElement {
let halfOpenContent = ""; let halfOpenContent = "";
if (isAdminOrEditor && hasReihe) { if (isAdminOrEditor && hasReihe) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Reihe Reihe
</div> </div>
<a href="/reihe/${reiheId}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihe/${reiheId}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasPerson) { } else if (isAdminOrEditor && hasPerson) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Person Person
</div> </div>
<a href="/person/${personId}/edit/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/person/${personId}/edit/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasEntry) { } else if (isAdminOrEditor && hasEntry) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Almanach Almanach
</div> </div>
<a href="/almanach/${entryId}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${entryId}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
<a href="/almanach/${entryId}/contents/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${entryId}/contents/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Beiträge bearbeiten</span> <span class="text-gray-900">Beiträge bearbeiten</span>
</a> </a>
<a href="/almanach/${entryId}/contents/new" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${entryId}/contents/new" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Beitrag</span> <span class="text-gray-900">Neuer Beitrag</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasContent && contentEntryId) { } else if (isAdminOrEditor && hasContent && contentEntryId) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Beitrag Beitrag
</div> </div>
<a href="/almanach/${contentEntryId}/contents/${contentId}/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${contentEntryId}/contents/${contentId}/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bearbeiten</span> <span class="text-gray-900">Bearbeiten</span>
</a> </a>
<a href="/almanach/${contentEntryId}/contents/edit" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${contentEntryId}/contents/edit" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-file-list-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Beiträge bearbeiten</span> <span class="text-gray-900">Beiträge bearbeiten</span>
</a> </a>
<a href="/almanach/${contentEntryId}/contents/new" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach/${contentEntryId}/contents/new" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Beitrag</span> <span class="text-gray-900">Neuer Beitrag</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasReihenList) { } else if (isAdminOrEditor && hasReihenList) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Reihen Reihen
</div> </div>
<a href="/reihen/new/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/new/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Reihe</span> <span class="text-gray-900">Neue Reihe</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasPersonenList) { } else if (isAdminOrEditor && hasPersonenList) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Personen Personen
</div> </div>
<a href="/personen/new/" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/new/" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-add-line text-base text-gray-700 mr-2.5"></i> <i class="ri-add-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Person</span> <span class="text-gray-900">Neue Person</span>
</a> </a>
`; `;
} else if (isAdminOrEditor && hasPage) { } else if (isAdminOrEditor && hasPage) {
halfOpenContent = ` halfOpenContent = `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Seite Seite
</div> </div>
<a href="/redaktion/seiten/?key=${pageKey}" hx-boost="false" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/seiten/?key=${pageKey}" hx-boost="false" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-edit-line text-base text-gray-700 mr-2.5"></i> <i class="ri-edit-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Seite bearbeiten</span> <span class="text-gray-900">Seite bearbeiten</span>
</a> </a>
@@ -226,42 +226,42 @@ export class FabMenu extends HTMLElement {
// Build full menu content // Build full menu content
const createSection = isAdminOrEditor const createSection = isAdminOrEditor
? ` ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Erstellen Erstellen
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/almanach-new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/almanach-new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-book-line text-base text-gray-700 mr-2.5"></i> <i class="ri-book-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Band</span> <span class="text-gray-900">Neuer Band</span>
</a> </a>
<a href="/almanach-new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/almanach-new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/reihen/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-stack-line text-base text-gray-700 mr-2.5"></i> <i class="ri-stack-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Reihe</span> <span class="text-gray-900">Neue Reihe</span>
</a> </a>
<a href="/reihen/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/reihen/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/orte/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/orte/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i> <i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neuer Ort</span> <span class="text-gray-900">Neuer Ort</span>
</a> </a>
<a href="/orte/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/orte/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/personen/new/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/new/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Neue Person</span> <span class="text-gray-900">Neue Person</span>
</a> </a>
<a href="/personen/new/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/personen/new/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
@@ -271,60 +271,60 @@ export class FabMenu extends HTMLElement {
const listenSection = isAdminOrEditor const listenSection = isAdminOrEditor
? ` ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Listen Listen
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/reihen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/reihen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-stack-line text-base text-gray-700 mr-2.5"></i> <i class="ri-stack-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Reihen</span> <span class="text-gray-900">Reihen</span>
</a> </a>
<a href="/reihen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/reihen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/baende/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/baende/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-book-line text-base text-gray-700 mr-2.5"></i> <i class="ri-book-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Bände</span> <span class="text-gray-900">Bände</span>
</a> </a>
<a href="/baende/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/baende/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/orte/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/orte/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i> <i class="ri-map-pin-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Orte</span> <span class="text-gray-900">Orte</span>
</a> </a>
<a href="/orte/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/orte/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/personen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/personen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Personen</span> <span class="text-gray-900">Personen</span>
</a> </a>
<a href="/personen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/personen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/abkuerzungen/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/abkuerzungen/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-text text-base text-gray-700 mr-2.5"></i> <i class="ri-text text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Abkürzungen</span> <span class="text-gray-900">Abkürzungen</span>
</a> </a>
<a href="/abkuerzungen/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/abkuerzungen/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/redaktion/seiten/" hx-boost="false" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/seiten/" hx-boost="false" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-pages-line text-base text-gray-700 mr-2.5"></i> <i class="ri-pages-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Seiten</span> <span class="text-gray-900">Seiten</span>
</a> </a>
<a href="/redaktion/seiten/" target="_blank" hx-boost="false" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/redaktion/seiten/" target="_blank" hx-boost="false" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
@@ -334,33 +334,33 @@ export class FabMenu extends HTMLElement {
const adminSection = isAdmin const adminSection = isAdmin
? ` ? `
<div class="px-3 py-1.5 text-xs font-semibold text-gray-500 uppercase tracking-wider"> <div class="px-2.5 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wider">
Administration Administration
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/redaktion/exports/" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/redaktion/exports/" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-download-2-line text-base text-gray-700 mr-2.5"></i> <i class="ri-download-2-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Datenexport</span> <span class="text-gray-900">Datenexport</span>
</a> </a>
<a href="/redaktion/exports/" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/redaktion/exports/" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/user/management/access/User?redirectTo=${redirectPath}" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/management/access/User?redirectTo=${redirectPath}" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Nutzer einladen</span> <span class="text-gray-900">Nutzer einladen</span>
</a> </a>
<a href="/user/management/access/User?redirectTo=${redirectPath}" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/user/management/access/User?redirectTo=${redirectPath}" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
<div class="grid grid-cols-[1fr_auto] group"> <div class="grid grid-cols-[1fr_auto] group">
<a href="/user/management?redirectTo=${redirectPath}" class="flex items-center px-4 py-2 group-hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/management?redirectTo=${redirectPath}" class="flex items-center px-3 py-1.5 group-hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-group-2-line text-base text-gray-700 mr-2.5"></i> <i class="ri-group-2-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Benutzerverwaltung</span> <span class="text-gray-900">Benutzerverwaltung</span>
</a> </a>
<a href="/user/management?redirectTo=${redirectPath}" target="_blank" class="flex items-center justify-center px-3 py-2 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen"> <a href="/user/management?redirectTo=${redirectPath}" target="_blank" class="flex items-center justify-center px-2.5 py-1.5 group-hover:bg-gray-100 text-gray-700 hover:text-slate-900 transition-colors no-underline text-sm" title="In neuem Tab öffnen">
<i class="ri-external-link-line text-base"></i> <i class="ri-external-link-line text-base"></i>
</a> </a>
</div> </div>
@@ -376,7 +376,7 @@ export class FabMenu extends HTMLElement {
this.innerHTML = ` this.innerHTML = `
<div class="fixed bottom-12 left-8 z-50"> <div class="fixed bottom-12 left-8 z-50">
<!-- Unified Menu Container --> <!-- Unified Menu Container -->
<div class="fab-menu hidden absolute bottom-16 left-0 w-64 bg-white rounded border border-gray-300 shadow transition-all duration-100 ease-out"> <div class="fab-menu hidden absolute bottom-16 left-0 w-64 max-h-[85vh] overflow-y-auto bg-white rounded border border-gray-300 shadow transition-all duration-100 ease-out">
<!-- Contextual actions (always at top when present) --> <!-- Contextual actions (always at top when present) -->
${contextualSection} ${contextualSection}
${contextualDivider} ${contextualDivider}
@@ -386,15 +386,15 @@ export class FabMenu extends HTMLElement {
${createSection} ${createSection}
${listenSection} ${listenSection}
${adminSection} ${adminSection}
<div class="px-4 py-2"> <div class="px-3 py-1.5">
<div class="font-semibold text-gray-900 text-sm">${userName}</div> <div class="font-semibold text-gray-900 text-sm">${userName}</div>
<div class="text-xs text-gray-600 truncate">${userEmail}</div> <div class="text-xs text-gray-600 truncate">${userEmail}</div>
</div> </div>
<a href="/user/${userId}/edit?redirectTo=${encodeURIComponent(window.location.href)}" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/user/${userId}/edit?redirectTo=${encodeURIComponent(window.location.href)}" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-user-3-line text-base text-gray-700 mr-2.5"></i> <i class="ri-user-3-line text-base text-gray-700 mr-2.5"></i>
<span class="text-gray-900">Profil bearbeiten</span> <span class="text-gray-900">Profil bearbeiten</span>
</a> </a>
<a href="/logout?redirectTo=${redirectPath}" class="flex items-center px-4 py-2 hover:bg-gray-100 transition-colors no-underline text-sm"> <a href="/logout?redirectTo=${redirectPath}" class="flex items-center px-3 py-1.5 hover:bg-gray-100 transition-colors no-underline text-sm">
<i class="ri-logout-box-line text-base text-gray-700 mr-2.5 mb-1"></i> <i class="ri-logout-box-line text-base text-gray-700 mr-2.5 mb-1"></i>
<span class="text-gray-900">Logout</span> <span class="text-gray-900">Logout</span>
</a> </a>
@@ -436,14 +436,20 @@ export class FabMenu extends HTMLElement {
handleClickAway(e) { handleClickAway(e) {
if (!this.contains(e.target)) { if (!this.contains(e.target)) {
this.setState("closed"); if (this.hasContext) {
this.setState("half");
} else {
this.setState("closed");
}
} }
} }
nextState() { nextState() {
if (this.hasContext) {
this.setState(this.state === "half" ? "full" : "half");
return;
}
if (this.state === "closed") { if (this.state === "closed") {
this.setState(this.hasContext ? "half" : "full");
} else if (this.state === "half") {
this.setState("full"); this.setState("full");
} else { } else {
this.setState("closed"); this.setState("closed");
@@ -451,6 +457,9 @@ export class FabMenu extends HTMLElement {
} }
setState(newState) { setState(newState) {
if (this.hasContext && newState === "closed") {
newState = "half";
}
this.state = newState; this.state = newState;
// Update menu visibility with animations // Update menu visibility with animations

View File

@@ -13,18 +13,16 @@ export class ScrollButton extends HTMLElement {
scroll-to-top scroll-to-top
fixed bottom-12 right-8 z-50 fixed bottom-12 right-8 z-50
hidden hidden
bg-gray-800 text-white w-12 h-12
p-2 bg-slate-700 hover:bg-slate-800 text-white
rounded-md rounded border-2 border-slate-600
shadow-sm transition-all duration-200
flex items-center justify-center
cursor-pointer cursor-pointer
text-2xl
hover:opacity-80
transition-opacity
border-0
" "
aria-label="Scroll to top" aria-label="Scroll to top"
> >
<i class="ri-arrow-up-double-line"></i> <i class="ri-arrow-up-double-line text-2xl"></i>
</button> </button>
`; `;

View File

@@ -663,11 +663,11 @@
} }
.global-notice { .global-notice {
@apply fixed right-6 bottom-6 z-50 hidden; @apply fixed left-24 bottom-12 z-50 hidden;
} }
.global-notice-inner { .global-notice-inner {
@apply flex items-center gap-2 rounded-md border border-slate-200 bg-white/95 px-3 py-2 text-sm font-semibold text-gray-700 shadow-lg backdrop-blur; @apply flex items-center gap-2 rounded-md border-2 border-slate-600 bg-slate-700 px-3 py-2 text-sm font-semibold text-white shadow-md;
} }
.global-notice[data-state="error"] .global-notice-inner { .global-notice[data-state="error"] .global-notice-inner {