Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
## 2026-02-15 - [Keyboard Handlers for Custom Buttons]
**Learning:** When turning a `div` or other non-button element into a button using `role="button"` and `tabindex="0"`, simply adding a click handler is insufficient. An `onkeydown` handler for "Enter" and " " (Space) is required, and `event.preventDefault()` must be called for the Space key to prevent the page from scrolling.
**Action:** Use `onkeydown="if(event.key==='Enter' || event.key===' ') { event.preventDefault(); this.click(); }"` for all custom interactive elements.

## 2026-02-20 - [Search Bar Usability and Accessibility]
**Learning:** Adding a "Clear Search" button significantly improves usability in list-heavy applications. To implement this correctly: 1. Use `relative` positioning on the input container. 2. Ensure the clear button has a descriptive `aria-label`. 3. In JavaScript, manually dispatch an `input` event after clearing the value so that existing listeners (like live-filtering) are triggered. 4. Return focus to the input field after clearing for better keyboard flow.
**Action:** Always include a clear button for search inputs in list views and ensure it triggers an `input` event.
5 changes: 4 additions & 1 deletion app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,10 @@ <h1 class="text-xl font-bold text-slate-900 truncate">
</a>
{% if current_user.is_authenticated %}
<div class="dropdown dropdown-end">
<button type="button" tabindex="0" class="btn btn-ghost btn-sm text-slate-600 hover:bg-slate-100">
<button type="button"
tabindex="0"
class="btn btn-ghost btn-sm text-slate-600 hover:bg-slate-100"
aria-label="{{ departments_ctx.current or departments.current or 'Abteilung wählen' }}">
<i class="fas fa-building mr-2"></i>
<span class="hidden sm:inline">{{ departments_ctx.current or departments.current or 'Abteilung wählen' }}</span>
</button>
Expand Down
33 changes: 27 additions & 6 deletions app/templates/shared/list_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@
<!-- Suchleiste und Aktionen -->
<div class="flex flex-col md:flex-row gap-4 items-center">
<div class="form-control flex-1">
<div class="input-group">
<input type="text"
placeholder="Suchen..."
class="input input-bordered w-full"
id="searchInput">
<button class="btn btn-square">
<div class="join w-full">
<div class="relative flex-1">
<input type="text"
placeholder="Suchen..."
class="input input-bordered w-full join-item pr-10"
id="searchInput"
aria-label="Suchen">
<button id="clearSearch"
class="absolute right-0 top-0 h-full px-3 text-slate-400 hover:text-slate-600 hidden z-10"
aria-label="Suche löschen"
type="button">
<i class="fas fa-times-circle"></i>
</button>
</div>
<button class="btn btn-square join-item" aria-label="Suchen">
<i class="fas fa-search"></i>
</button>
</div>
Expand Down Expand Up @@ -76,14 +85,26 @@ <h3 class="card-title text-lg">
// Basis-Suchfunktion
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('searchInput');
const clearSearch = document.getElementById('clearSearch');
if (searchInput) {
searchInput.addEventListener('input', function(e) {
const searchTerm = e.target.value.toLowerCase();
if (clearSearch) {
clearSearch.classList.toggle('hidden', searchTerm === '');
}
document.querySelectorAll('.data-row').forEach(row => {
const searchableContent = row.textContent.toLowerCase();
row.style.display = searchableContent.includes(searchTerm) ? '' : 'none';
});
});

if (clearSearch) {
clearSearch.addEventListener('click', function() {
searchInput.value = '';
searchInput.dispatchEvent(new Event('input'));
searchInput.focus();
});
}
}

// Sortier-Funktionalität
Expand Down
12 changes: 9 additions & 3 deletions app/templates/workers/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
{% endblock %}

{% block filters %}
<select class="select select-bordered w-full max-w-xs focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200" id="departmentFilter">
<select class="select select-bordered w-full max-w-xs focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200" id="departmentFilter" aria-label="Abteilung filtern">
<option value="">Alle Abteilungen</option>
{% for department in departments %}
<option value="{{ department }}">{{ department }}</option>
Expand Down Expand Up @@ -93,10 +93,16 @@
</td>
<td class="text-right">
<div class="btn-group">
<a href="{{ url_for('workers.details', original_barcode=worker.barcode) }}" class="btn btn-sm btn-ghost">
<a href="{{ url_for('workers.details', original_barcode=worker.barcode) }}"
class="btn btn-sm btn-ghost"
aria-label="Mitarbeiter bearbeiten"
title="Mitarbeiter bearbeiten">
<i class="fas fa-edit"></i>
</a>
<button class="btn btn-sm btn-ghost btn-error" onclick="deleteItem('worker', '{{ worker.barcode }}')">
<button class="btn btn-sm btn-ghost btn-error"
onclick="deleteItem('worker', '{{ worker.barcode }}')"
aria-label="Mitarbeiter löschen"
title="Mitarbeiter löschen">
<i class="fas fa-trash"></i>
</button>
</div>
Expand Down