From 80087480b54ab200b054689adc78bd1c6c2339ab Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:39:33 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Search=20and=20sortin?= =?UTF-8?q?g=20UX=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements several micro-UX and accessibility improvements: 1. **Clear Search Button:** Added a "Clear Search" button to the search input in `shared/list_base.html`. It appears when text is entered and allows resetting the filter with one click. 2. **Table Sorting Accessibility:** Enhanced table headers in `shared/list_base.html` with keyboard support (`role="button"`, `tabindex="0"`, Enter/Space listeners) and proper ARIA attributes (`aria-label`, `aria-sort`). 3. **Mismatched Tag Fix:** Fixed a known bug in `base.html` where a `
` was incorrectly closed with a ``. The search logic was made robust to handle cases where components might be missing or pre-filled. focus indicators and padding were optimized for better usability. Co-authored-by: Woschj <81321922+Woschj@users.noreply.github.com> --- app/templates/base.html | 2 +- app/templates/shared/list_base.html | 66 +++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/app/templates/base.html b/app/templates/base.html index d35052c..9d24adb 100755 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -243,7 +243,7 @@
- + diff --git a/app/templates/shared/list_base.html b/app/templates/shared/list_base.html index c89a7b4..1a1ea9c 100755 --- a/app/templates/shared/list_base.html +++ b/app/templates/shared/list_base.html @@ -9,13 +9,19 @@
-
+
- +
@@ -78,14 +84,33 @@

// Basis-Suchfunktion document.addEventListener('DOMContentLoaded', function() { const searchInput = document.getElementById('searchInput'); - if (searchInput) { - searchInput.addEventListener('input', function(e) { - const searchTerm = e.target.value.toLowerCase(); + const clearSearch = document.getElementById('clearSearch'); + + if (searchInput) { + const handleSearch = () => { + const searchTerm = searchInput.value; + if (clearSearch) { + clearSearch.classList.toggle('hidden', searchTerm.length === 0); + } + const searchTermLower = searchTerm.toLowerCase(); document.querySelectorAll('.data-row').forEach(row => { const searchableContent = row.textContent.toLowerCase(); - row.style.display = searchableContent.includes(searchTerm) ? '' : 'none'; + row.style.display = searchableContent.includes(searchTermLower) ? '' : 'none'; }); - }); + }; + + searchInput.addEventListener('input', handleSearch); + + if (clearSearch) { + clearSearch.addEventListener('click', function() { + searchInput.value = ''; + handleSearch(); + searchInput.focus(); + }); + } + + // Initialer Check (z.B. bei Browser-Autocomplete oder Zurück-Button) + handleSearch(); } // Sortier-Funktionalität @@ -95,7 +120,11 @@

document.querySelectorAll('th').forEach(th => { if (!th.classList.contains('no-sort')) { const wrapper = document.createElement('div'); - wrapper.className = 'flex items-center gap-2 cursor-pointer select-none'; + wrapper.className = 'flex items-center gap-2 cursor-pointer select-none focus:outline-none focus:ring-2 focus:ring-primary/50 rounded px-1 -mx-1'; + wrapper.setAttribute('role', 'button'); + wrapper.setAttribute('tabindex', '0'); + wrapper.setAttribute('aria-label', `Sortieren nach ${th.textContent.trim()}`); + wrapper.innerHTML = ` ${th.innerHTML} @@ -105,9 +134,17 @@

th.innerHTML = ''; th.appendChild(wrapper); - wrapper.addEventListener('click', () => { + const triggerSort = () => { const column = Array.from(th.parentElement.children).indexOf(th); sortTable(column, th); + }; + + wrapper.addEventListener('click', triggerSort); + wrapper.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + triggerSort(); + } }); } }); @@ -125,11 +162,14 @@

currentSort.direction = 'asc'; } - // Update Sort-Icons - table.querySelectorAll('.sort-icons').forEach(icon => { - icon.innerHTML = ''; + // Update Sort-Icons und ARIA + table.querySelectorAll('th').forEach(header => { + header.removeAttribute('aria-sort'); + const icon = header.querySelector('.sort-icons'); + if (icon) icon.innerHTML = ''; }); + th.setAttribute('aria-sort', currentSort.direction === 'asc' ? 'ascending' : 'descending'); const currentIcon = th.querySelector('.sort-icons'); if (currentSort.direction === 'asc') { currentIcon.innerHTML = '';