From 616e64f37d384c297064dc81c815a3abb55ebc04 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:06:56 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Accessibility=20and?= =?UTF-8?q?=20Interaction=20improvements=20for=20QuickScan=20and=20Search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added ARIA labels to search inputs, search buttons, and department dropdown. - Improved QuickScan modal keyboard accessibility (role="button", tabindex="0", Enter/Space support). - Added focus-visible indicators to QuickScan trigger and cards. - Implemented loading state with spinner for QuickScan confirmation button. - Wrapped icon-only buttons with aria-hidden icons for screen readers. Co-authored-by: Woschj <81321922+Woschj@users.noreply.github.com> --- .Jules/palette.md | 3 ++ app/static/js/quickscan.js | 17 +++++++++- app/templates/base.html | 7 +++- app/templates/components/quickscan_modal.html | 32 +++++++++++++------ app/templates/shared/list_base.html | 5 +-- 5 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 .Jules/palette.md diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..f2ea895 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,3 @@ +## 2026-02-18 - [Accessibility & Interaction Feedback] +**Learning:** Custom interactive elements (like cards used as buttons) must have proper ARIA roles, tabindex, and keyboard event handlers (Enter/Space) to be accessible. Additionally, async buttons should always provide visual loading states and use a `finally` block in JS to ensure the button is restored if the modal stays open or on error. +**Action:** Always check for `role="button"` and `tabindex="0"` on non-button interactive elements, and implement robust button state management for async calls. diff --git a/app/static/js/quickscan.js b/app/static/js/quickscan.js index 0b0b3f9..6ca91d5 100755 --- a/app/static/js/quickscan.js +++ b/app/static/js/quickscan.js @@ -1074,6 +1074,13 @@ const QuickScan = { return; } + const btn = document.getElementById('quickScanConfirmBtn'); + const originalHTML = btn ? btn.innerHTML : ''; + if (btn) { + btn.disabled = true; + btn.innerHTML = ' Verarbeitung...'; + } + try { // Daten für die API zusammenstellen const requestData = { @@ -1108,11 +1115,19 @@ const QuickScan = { } else { showQuickScanToast('success', data.message); this.reset(); - document.getElementById('quickScanModal').close(); + const modal = document.getElementById('quickScanModal'); + if (modal) modal.close(); } } catch (error) { console.error('Error:', error); showQuickScanToast('error', 'Ein Fehler ist aufgetreten'); + } finally { + if (btn) { + btn.disabled = false; + btn.innerHTML = originalHTML; + // Re-validate button state based on remaining inputs if modal wasn't closed + updateQuickScanButton(); + } } } }; diff --git a/app/templates/base.html b/app/templates/base.html index c376ba7..6b91edc 100755 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -203,6 +203,11 @@ box-shadow: 0 8px 20px rgba(0,0,0,0.2); } + #quickScanTrigger:focus-visible { + outline: 2px solid #4f46e5; + outline-offset: 2px; + } + /* Trennlinie */ .sidebar-divider { width: 85%; @@ -399,7 +404,7 @@

{% if current_user.is_authenticated %}