a11y: aria-hidden auf allen Icons + aria-label auf icon-only Buttons (Redesign Phase F)

- Alle data-lucide Icons: aria-hidden="true" (dekorativ)
- Icon-only Buttons/Links: title→aria-label (Screenreader-zugänglich)
- Betrifft: modal.js, contacts, meals, budget, calendar, notes, tasks,
  shopping, dashboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ulsklyc
2026-03-26 13:48:23 +01:00
parent 152246185e
commit d5a0e701b0
9 changed files with 80 additions and 80 deletions
+1 -1
View File
@@ -93,7 +93,7 @@ export function openModal({ title, content, onSave, onDelete, size = 'md' } = {}
<div class="modal-panel__header">
<h2 class="modal-panel__title" id="shared-modal-title">${title}</h2>
<button class="modal-panel__close" data-action="close-modal" aria-label="Schließen">
<i data-lucide="x" style="width:18px;height:18px"></i>
<i data-lucide="x" style="width:18px;height:18px" aria-hidden="true"></i>
</button>
</div>
<div class="modal-panel__body">
+10 -10
View File
@@ -86,22 +86,22 @@ export async function render(container, { user }) {
<h1 class="sr-only">Budget</h1>
<div class="budget-nav">
<button class="btn btn--icon" id="budget-prev" aria-label="Vorheriger Monat">
<i data-lucide="chevron-left"></i>
<i data-lucide="chevron-left" aria-hidden="true"></i>
</button>
<button class="budget-nav__today" id="budget-today">Aktuell</button>
<span class="budget-nav__label" id="budget-label"></span>
<button class="btn btn--primary btn--icon" id="budget-add" aria-label="Eintrag hinzufügen">
<i data-lucide="plus"></i>
<i data-lucide="plus" aria-hidden="true"></i>
</button>
<button class="btn btn--icon" id="budget-next" aria-label="Nächster Monat">
<i data-lucide="chevron-right"></i>
<i data-lucide="chevron-right" aria-hidden="true"></i>
</button>
</div>
<div id="budget-body" style="flex:1;display:flex;flex-direction:column;overflow:hidden;">
<div style="padding:2rem;text-align:center;color:var(--color-text-disabled);">Lade…</div>
</div>
<button class="page-fab" id="fab-new-budget" aria-label="Neuer Eintrag">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;
@@ -192,7 +192,7 @@ function renderBody() {
${state.entries.length ? `
<a href="/api/v1/budget/export?month=${state.month}" class="btn btn--secondary"
style="font-size:var(--text-sm);padding:var(--space-1) var(--space-3);">
<i data-lucide="download" style="width:14px;height:14px;margin-right:4px;"></i>CSV
<i data-lucide="download" style="width:14px;height:14px;margin-right:4px;" aria-hidden="true"></i>CSV
</a>` : ''}
</div>
<div class="budget-list" id="budget-list">
@@ -240,7 +240,7 @@ function renderCategoryBars(byCategory) {
function renderEntries() {
if (!state.entries.length) {
return `<div class="budget-empty">
<i data-lucide="receipt" style="width:48px;height:48px;color:var(--color-text-disabled);margin-bottom:var(--space-3);"></i>
<i data-lucide="receipt" style="width:48px;height:48px;color:var(--color-text-disabled);margin-bottom:var(--space-3);" aria-hidden="true"></i>
<div style="font-size:var(--text-base);font-weight:600;">Keine Einträge</div>
<div style="font-size:var(--text-sm);margin-top:var(--space-1);">Noch keine Transaktionen für diesen Monat.</div>
</div>`;
@@ -261,8 +261,8 @@ function renderEntries() {
<div class="budget-entry__meta">${date} · ${escHtml(e.category)}${e.is_recurring ? ' 🔁' : ''}</div>
</div>
<div class="budget-entry__amount ${amtClass}">${sign}${formatAmount(e.amount)}</div>
<button class="budget-entry__delete" data-action="delete" data-id="${e.id}" title="Löschen">
<i data-lucide="trash-2" style="width:14px;height:14px;"></i>
<button class="budget-entry__delete" data-action="delete" data-id="${e.id}" aria-label="Eintrag löschen">
<i data-lucide="trash-2" style="width:14px;height:14px;" aria-hidden="true"></i>
</button>
</div>
`;
@@ -329,8 +329,8 @@ function openBudgetModal({ mode, entry = null }) {
</div>
<div class="modal-panel__footer" style="border:none;padding:0;margin-top:var(--space-4)">
${isEdit ? `<button class="btn btn--danger btn--icon" id="bm-delete" title="Löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;"></i>
${isEdit ? `<button class="btn btn--danger btn--icon" id="bm-delete" aria-label="Eintrag löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>` : '<div></div>'}
<div style="display:flex;gap:var(--space-3)">
<button class="btn btn--secondary" id="bm-cancel">Abbrechen</button>
+8 -8
View File
@@ -161,7 +161,7 @@ export async function render(container, { user }) {
<div class="cal-toolbar" id="cal-toolbar"></div>
<div id="cal-body" style="flex:1;display:flex;flex-direction:column;overflow:hidden;"></div>
<button class="page-fab" id="fab-new-event" aria-label="Neuer Termin">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;
@@ -187,7 +187,7 @@ function renderToolbar() {
<h1 class="sr-only">Kalender</h1>
<div class="cal-toolbar__nav">
<button class="btn btn--icon" id="cal-prev" aria-label="Zurück">
<i data-lucide="chevron-left"></i>
<i data-lucide="chevron-left" aria-hidden="true"></i>
</button>
</div>
<button class="cal-toolbar__today" id="cal-today">Heute</button>
@@ -200,11 +200,11 @@ function renderToolbar() {
</div>
<button class="btn btn--primary btn--icon" id="cal-add" aria-label="Termin hinzufügen"
style="margin-left:auto;">
<i data-lucide="plus"></i>
<i data-lucide="plus" aria-hidden="true"></i>
</button>
<div class="cal-toolbar__nav">
<button class="btn btn--icon" id="cal-next" aria-label="Weiter">
<i data-lucide="chevron-right"></i>
<i data-lucide="chevron-right" aria-hidden="true"></i>
</button>
</div>
`;
@@ -620,7 +620,7 @@ function renderAgendaEvent(ev) {
<div class="agenda-event" data-id="${ev.id}">
<div class="agenda-event__color" style="background-color:${escHtml(ev.color)};"></div>
<div class="agenda-event__body">
<div class="agenda-event__title">${escHtml(ev.title)}${ev.recurrence_rule ? ' <i data-lucide="repeat" style="width:12px;height:12px;display:inline;vertical-align:middle;opacity:0.5"></i>' : ''}</div>
<div class="agenda-event__title">${escHtml(ev.title)}${ev.recurrence_rule ? ' <i data-lucide="repeat" style="width:12px;height:12px;display:inline;vertical-align:middle;opacity:0.5" aria-hidden="true"></i>' : ''}</div>
<div class="agenda-event__meta">
<span>${timeStr}</span>
${ev.location ? `<span>📍 ${escHtml(ev.location)}</span>` : ''}
@@ -663,7 +663,7 @@ function showEventPopup(ev, anchor) {
<div class="event-popup__actions">
<button class="btn btn--secondary" style="flex:1;" id="popup-edit">Bearbeiten</button>
<button class="btn btn--danger" id="popup-delete">
<i data-lucide="trash-2" style="width:16px;height:16px;"></i>
<i data-lucide="trash-2" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>
</div>
`;
@@ -850,8 +850,8 @@ function buildEventModalContent({ mode, event, date }) {
${renderRRuleFields('event', isEdit ? event.recurrence_rule : null)}
<div class="modal-panel__footer" style="border:none;padding:0;margin-top:var(--space-4)">
${isEdit ? `<button class="btn btn--danger btn--icon" id="modal-delete" title="Löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;"></i>
${isEdit ? `<button class="btn btn--danger btn--icon" id="modal-delete" aria-label="Termin löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>` : '<div></div>'}
<div style="display:flex;gap:var(--space-3)">
<button class="btn btn--secondary" id="modal-cancel">Abbrechen</button>
+11 -11
View File
@@ -46,13 +46,13 @@ export async function render(container, { user }) {
<h1 class="sr-only">Kontakte</h1>
<div class="contacts-toolbar">
<div class="contacts-toolbar__search">
<i data-lucide="search" class="contacts-toolbar__search-icon"></i>
<i data-lucide="search" class="contacts-toolbar__search-icon" aria-hidden="true"></i>
<input type="search" class="contacts-toolbar__search-input"
id="contacts-search" placeholder="Name, Telefon oder E-Mail suchen…"
autocomplete="off">
</div>
<button class="btn btn--primary" id="contacts-add-btn">
<i data-lucide="plus" style="width:16px;height:16px;margin-right:4px;"></i>
<i data-lucide="plus" style="width:16px;height:16px;margin-right:4px;" aria-hidden="true"></i>
Neu
</button>
</div>
@@ -64,7 +64,7 @@ export async function render(container, { user }) {
</div>
<div id="contacts-list" class="contacts-list"></div>
<button class="page-fab" id="fab-new-contact" aria-label="Neuer Kontakt">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;
@@ -134,7 +134,7 @@ function renderList() {
if (!contacts.length) {
container.innerHTML = `
<div class="contacts-empty">
<i data-lucide="users" style="width:48px;height:48px;color:var(--color-text-disabled);margin-bottom:var(--space-3);"></i>
<i data-lucide="users" style="width:48px;height:48px;color:var(--color-text-disabled);margin-bottom:var(--space-3);" aria-hidden="true"></i>
<div style="font-size:var(--text-base);font-weight:600;">Keine Kontakte gefunden</div>
</div>
`;
@@ -176,9 +176,9 @@ function renderList() {
}
function renderContactItem(c) {
const phone = c.phone ? `<a href="tel:${escHtml(c.phone)}" class="contact-action-btn contact-action-btn--call" title="Anrufen"><i data-lucide="phone" style="width:16px;height:16px;"></i></a>` : '';
const email = c.email ? `<a href="mailto:${escHtml(c.email)}" class="contact-action-btn contact-action-btn--mail" title="E-Mail"><i data-lucide="mail" style="width:16px;height:16px;"></i></a>` : '';
const maps = c.address ? `<a href="https://maps.google.com/?q=${encodeURIComponent(c.address)}" target="_blank" rel="noopener" class="contact-action-btn contact-action-btn--maps" title="In Maps öffnen"><i data-lucide="map-pin" style="width:16px;height:16px;"></i></a>` : '';
const phone = c.phone ? `<a href="tel:${escHtml(c.phone)}" class="contact-action-btn contact-action-btn--call" aria-label="Anrufen"><i data-lucide="phone" style="width:16px;height:16px;" aria-hidden="true"></i></a>` : '';
const email = c.email ? `<a href="mailto:${escHtml(c.email)}" class="contact-action-btn contact-action-btn--mail" aria-label="E-Mail"><i data-lucide="mail" style="width:16px;height:16px;" aria-hidden="true"></i></a>` : '';
const maps = c.address ? `<a href="https://maps.google.com/?q=${encodeURIComponent(c.address)}" target="_blank" rel="noopener" class="contact-action-btn contact-action-btn--maps" aria-label="In Maps öffnen"><i data-lucide="map-pin" style="width:16px;height:16px;" aria-hidden="true"></i></a>` : '';
const meta = [c.phone, c.email].filter(Boolean).join(' · ');
return `
@@ -190,8 +190,8 @@ function renderContactItem(c) {
</div>
<div class="contact-item__actions">
${phone}${email}${maps}
<button class="contact-action-btn" data-action="delete" data-id="${c.id}" title="Löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;"></i>
<button class="contact-action-btn" data-action="delete" data-id="${c.id}" aria-label="Kontakt löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>
</div>
</div>
@@ -237,8 +237,8 @@ function openContactModal({ mode, contact = null }) {
</div>
<div class="modal-panel__footer" style="border:none;padding:0;margin-top:var(--space-4)">
${isEdit ? `<button class="btn btn--danger btn--icon" id="cm-delete" title="Löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;"></i>
${isEdit ? `<button class="btn btn--danger btn--icon" id="cm-delete" aria-label="Kontakt löschen">
<i data-lucide="trash-2" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>` : '<div></div>'}
<div style="display:flex;gap:var(--space-3);">
<button class="btn btn--secondary" id="cm-cancel">Abbrechen</button>
+6 -6
View File
@@ -118,17 +118,17 @@ function renderGreeting(user, stats = {}) {
const statChips = [];
if (urgentCount > 0)
statChips.push(`<span class="greeting-chip greeting-chip--warn">
<i data-lucide="alert-circle" style="${chipIcon}"></i>
<i data-lucide="alert-circle" style="${chipIcon}" aria-hidden="true"></i>
${urgentCount} dring. Aufgabe${urgentCount > 1 ? 'n' : ''}
</span>`);
if (todayEventCount > 0)
statChips.push(`<span class="greeting-chip">
<i data-lucide="calendar" style="${chipIcon}"></i>
<i data-lucide="calendar" style="${chipIcon}" aria-hidden="true"></i>
${todayEventCount} Termin${todayEventCount > 1 ? 'e' : ''} heute
</span>`);
if (todayMealTitle)
statChips.push(`<span class="greeting-chip">
<i data-lucide="utensils" style="${chipIcon}"></i>
<i data-lucide="utensils" style="${chipIcon}" aria-hidden="true"></i>
Heute: ${todayMealTitle}
</span>`);
@@ -148,7 +148,7 @@ function renderUrgentTasks(tasks) {
return `<div class="widget">
${widgetHeader('check-square', 'Aufgaben', 0, '/tasks')}
<div class="widget__empty">
<i data-lucide="check-circle" class="empty-state__icon" style="color:var(--color-success)"></i>
<i data-lucide="check-circle" class="empty-state__icon" style="color:var(--color-success)" aria-hidden="true"></i>
<div>Alles erledigt</div>
</div>
</div>`;
@@ -181,7 +181,7 @@ function renderUpcomingEvents(events) {
return `<div class="widget">
${widgetHeader('calendar', 'Termine', 0, '/calendar')}
<div class="widget__empty">
<i data-lucide="calendar-check" class="empty-state__icon"></i>
<i data-lucide="calendar-check" class="empty-state__icon" aria-hidden="true"></i>
<div>Keine Termine</div>
</div>
</div>`;
@@ -238,7 +238,7 @@ function renderPinnedNotes(notes) {
return `<div class="widget">
${widgetHeader('pin', 'Pinnwand', 0, '/notes')}
<div class="widget__empty">
<i data-lucide="sticky-note" class="empty-state__icon"></i>
<i data-lucide="sticky-note" class="empty-state__icon" aria-hidden="true"></i>
<div>Keine angepinnten Notizen</div>
</div>
</div>`;
+11 -11
View File
@@ -107,12 +107,12 @@ export async function render(container, { user }) {
<h1 class="sr-only">Essensplan</h1>
<div class="week-nav">
<button class="btn btn--icon" id="week-prev" aria-label="Vorherige Woche">
<i data-lucide="chevron-left"></i>
<i data-lucide="chevron-left" aria-hidden="true"></i>
</button>
<span class="week-nav__label" id="week-label"></span>
<button class="week-nav__today" id="week-today">Heute</button>
<button class="btn btn--icon" id="week-next" aria-label="Nächste Woche">
<i data-lucide="chevron-right"></i>
<i data-lucide="chevron-right" aria-hidden="true"></i>
</button>
</div>
<div class="week-grid" id="week-grid">
@@ -179,7 +179,7 @@ function renderSlot(date, type, mealsForDay) {
data-type="${type.key}"
aria-label="${type.label} hinzufügen"
>
<i data-lucide="plus" style="width:16px;height:16px;"></i>
<i data-lucide="plus" style="width:16px;height:16px;" aria-hidden="true"></i>
</button>
</div>
`;
@@ -206,13 +206,13 @@ function renderSlot(date, type, mealsForDay) {
${canTransfer ? `<button class="meal-card__action-btn meal-card__action-btn--shopping"
data-action="transfer-meal"
data-meal-id="${meal.id}"
title="Zutaten auf Einkaufsliste"
><i data-lucide="shopping-cart" style="width:14px;height:14px;"></i></button>` : ''}
aria-label="Zutaten auf Einkaufsliste"
><i data-lucide="shopping-cart" style="width:14px;height:14px;" aria-hidden="true"></i></button>` : ''}
<button class="meal-card__action-btn"
data-action="delete-meal"
data-meal-id="${meal.id}"
title="Löschen"
><i data-lucide="trash-2" style="width:14px;height:14px;"></i></button>
aria-label="Mahlzeit löschen"
><i data-lucide="trash-2" style="width:14px;height:14px;" aria-hidden="true"></i></button>
</div>
</div>
</div>
@@ -427,7 +427,7 @@ function buildModalContent({ mode, date, mealType, meal }) {
<label class="form-label">Zutaten</label>
<div class="ingredient-list" id="ingredient-list">${ingRows}</div>
<button class="add-ingredient-btn" id="add-ingredient-btn" type="button">
<i data-lucide="plus" style="width:14px;height:14px;"></i>
<i data-lucide="plus" style="width:14px;height:14px;" aria-hidden="true"></i>
Zutat hinzufügen
</button>
</div>
@@ -435,7 +435,7 @@ function buildModalContent({ mode, date, mealType, meal }) {
${isEdit && hasIngOpen ? `
<div class="shopping-transfer">
<div class="shopping-transfer__label">
<i data-lucide="shopping-cart" style="width:14px;height:14px;"></i>
<i data-lucide="shopping-cart" style="width:14px;height:14px;" aria-hidden="true"></i>
Zutaten auf Einkaufsliste übertragen
</div>
<select class="shopping-transfer__select" id="transfer-list-select">${listOpts}</select>
@@ -455,8 +455,8 @@ function ingredientRowHTML(name, qty, id) {
<div class="ingredient-row" data-ing-id="${id ?? ''}">
<input type="text" class="form-input ingredient-row__name" placeholder="Zutat" value="${escHtml(name)}">
<input type="text" class="form-input ingredient-row__qty" placeholder="Menge" value="${escHtml(qty)}">
<button class="ingredient-row__remove" data-action="remove-ingredient" type="button" title="Entfernen">
<i data-lucide="x" style="width:14px;height:14px;"></i>
<button class="ingredient-row__remove" data-action="remove-ingredient" type="button" aria-label="Zutat entfernen">
<i data-lucide="x" style="width:14px;height:14px;" aria-hidden="true"></i>
</button>
</div>
`;
+7 -7
View File
@@ -49,13 +49,13 @@ export async function render(container, { user }) {
<div class="notes-toolbar">
<h1 class="notes-toolbar__title">Pinnwand</h1>
<button class="btn btn--primary" id="notes-add-btn">
<i data-lucide="plus" style="width:16px;height:16px;margin-right:4px;"></i>
<i data-lucide="plus" style="width:16px;height:16px;margin-right:4px;" aria-hidden="true"></i>
Neue Notiz
</button>
</div>
<div id="notes-grid" class="notes-grid"></div>
<button class="page-fab" id="fab-new-note" aria-label="Neue Notiz">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;
@@ -88,7 +88,7 @@ function renderGrid() {
if (!state.notes.length) {
grid.innerHTML = `
<div class="notes-empty">
<i data-lucide="sticky-note" class="notes-empty__icon"></i>
<i data-lucide="sticky-note" class="notes-empty__icon" aria-hidden="true"></i>
<div style="font-size:var(--text-lg);font-weight:600;margin-bottom:var(--space-2);">Noch keine Notizen</div>
<div style="font-size:var(--text-sm);">Klicke auf „Neue Notiz" um loszulegen.</div>
</div>
@@ -130,8 +130,8 @@ function renderNoteCard(note) {
data-id="${note.id}"
style="background-color:${escHtml(note.color)};color:${textColor};">
<button class="note-card__pin" data-action="pin" data-id="${note.id}"
title="${note.pinned ? 'Anpinnen aufheben' : 'Anpinnen'}">
<i data-lucide="${note.pinned ? 'pin-off' : 'pin'}" style="width:12px;height:12px;"></i>
aria-label="${note.pinned ? 'Anpinnen aufheben' : 'Anpinnen'}">
<i data-lucide="${note.pinned ? 'pin-off' : 'pin'}" style="width:12px;height:12px;" aria-hidden="true"></i>
</button>
${note.title ? `<div class="note-card__title">${escHtml(note.title)}</div>` : ''}
<div class="note-card__content">${renderMarkdownLight(note.content)}</div>
@@ -141,8 +141,8 @@ function renderNoteCard(note) {
style="background-color:${escHtml(note.creator_color || '#8E8E93')}">${initials}</span>
<span>${escHtml(note.creator_name || '')}</span>
</div>
<button class="note-card__delete" data-action="delete" data-id="${note.id}" title="Löschen">
<i data-lucide="trash-2" style="width:12px;height:12px;"></i>
<button class="note-card__delete" data-action="delete" data-id="${note.id}" aria-label="Notiz löschen">
<i data-lucide="trash-2" style="width:12px;height:12px;" aria-hidden="true"></i>
</button>
</div>
</div>
+13 -13
View File
@@ -75,7 +75,7 @@ function renderTabs(container) {
bar.innerHTML = `
${tabsHtml}
<button class="list-tab__new" data-action="new-list" aria-label="Neue Liste erstellen">
<i data-lucide="plus" style="width:18px;height:18px"></i>
<i data-lucide="plus" style="width:18px;height:18px" aria-hidden="true"></i>
</button>
`;
if (window.lucide) window.lucide.createIcons();
@@ -88,7 +88,7 @@ function renderListContent(container) {
if (!state.activeList) {
content.innerHTML = `
<div class="no-lists">
<i data-lucide="shopping-cart" style="width:56px;height:56px;color:var(--color-text-disabled)"></i>
<i data-lucide="shopping-cart" style="width:56px;height:56px;color:var(--color-text-disabled)" aria-hidden="true"></i>
<div style="font-size:var(--text-lg);font-weight:var(--font-weight-semibold)">Keine Listen</div>
<div style="font-size:var(--text-sm);color:var(--color-text-secondary)">
Erstelle eine Liste mit dem + Button.
@@ -106,19 +106,19 @@ function renderListContent(container) {
<span class="list-header__name" data-action="rename-list" data-id="${state.activeList.id}"
role="button" tabindex="0" aria-label="Liste umbenennen">
${state.activeList.name}
<i data-lucide="pencil" class="list-header__edit-icon"></i>
<i data-lucide="pencil" class="list-header__edit-icon" aria-hidden="true"></i>
</span>
<div class="list-header__actions">
${checkedCount > 0 ? `
<button class="btn btn--ghost" data-action="clear-checked"
style="font-size:var(--text-sm);color:var(--color-text-secondary)">
<i data-lucide="trash-2" style="width:15px;height:15px"></i>
<i data-lucide="trash-2" style="width:15px;height:15px" aria-hidden="true"></i>
Abgehakt löschen (${checkedCount})
</button>` : ''}
<button class="btn btn--ghost btn--icon" data-action="delete-list"
data-id="${state.activeList.id}" aria-label="Liste löschen"
style="color:var(--color-text-secondary)">
<i data-lucide="trash" style="width:18px;height:18px"></i>
<i data-lucide="trash" style="width:18px;height:18px" aria-hidden="true"></i>
</button>
</div>
</div>
@@ -139,7 +139,7 @@ function renderListContent(container) {
).join('')}
</select>
<button class="quick-add__btn" type="submit" aria-label="Artikel hinzufügen">
<i data-lucide="plus" style="width:20px;height:20px"></i>
<i data-lucide="plus" style="width:20px;height:20px" aria-hidden="true"></i>
</button>
</form>
</div>
@@ -159,7 +159,7 @@ function renderItems() {
if (!state.items.length) {
return `
<div class="shopping-empty">
<i data-lucide="check-circle" class="shopping-empty__icon"></i>
<i data-lucide="check-circle" class="shopping-empty__icon" aria-hidden="true"></i>
<div class="shopping-empty__title">Liste ist leer</div>
<div class="shopping-empty__desc">Füge Artikel mit dem Eingabefeld oben hinzu.</div>
</div>`;
@@ -169,7 +169,7 @@ function renderItems() {
return groups.map(([cat, items]) => `
<div class="item-category">
<div class="item-category__header">
<i data-lucide="${CATEGORY_ICONS[cat] ?? 'tag'}" class="item-category__icon"></i>
<i data-lucide="${CATEGORY_ICONS[cat] ?? 'tag'}" class="item-category__icon" aria-hidden="true"></i>
${cat}
</div>
${items.map(renderItem).join('')}
@@ -183,7 +183,7 @@ function renderItem(item) {
<button class="item-check ${item.is_checked ? 'item-check--checked' : ''}"
data-action="toggle-item" data-id="${item.id}" data-checked="${item.is_checked}"
aria-label="${item.name} ${item.is_checked ? 'als nicht erledigt markieren' : 'abhaken'}">
<i data-lucide="check" class="item-check__icon"></i>
<i data-lucide="check" class="item-check__icon" aria-hidden="true"></i>
</button>
<div class="item-body">
<div class="item-name">${item.name}</div>
@@ -191,7 +191,7 @@ function renderItem(item) {
</div>
<button class="item-delete" data-action="delete-item" data-id="${item.id}"
aria-label="${item.name} löschen">
<i data-lucide="x" style="width:16px;height:16px"></i>
<i data-lucide="x" style="width:16px;height:16px" aria-hidden="true"></i>
</button>
</div>`;
}
@@ -321,7 +321,7 @@ function updateItemsList(container) {
header.insertAdjacentHTML('afterbegin', `
<button class="btn btn--ghost" data-action="clear-checked"
style="font-size:var(--text-sm);color:var(--color-text-secondary)">
<i data-lucide="trash-2" style="width:15px;height:15px"></i>
<i data-lucide="trash-2" style="width:15px;height:15px" aria-hidden="true"></i>
Abgehakt löschen (${checkedCount})
</button>`);
if (window.lucide) window.lucide.createIcons();
@@ -330,7 +330,7 @@ function updateItemsList(container) {
clearBtn.remove();
} else {
clearBtn.innerHTML = `
<i data-lucide="trash-2" style="width:15px;height:15px"></i>
<i data-lucide="trash-2" style="width:15px;height:15px" aria-hidden="true"></i>
Abgehakt löschen (${checkedCount})`;
if (window.lucide) window.lucide.createIcons();
}
@@ -557,7 +557,7 @@ export async function render(container, { user }) {
<div class="list-tabs-bar" id="list-tabs-bar"></div>
<div id="list-content" style="flex:1;display:flex;flex-direction:column;overflow:hidden"></div>
<button class="page-fab" id="fab-new-item" aria-label="Artikel hinzufügen">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;
+13 -13
View File
@@ -99,7 +99,7 @@ function renderDueDate(dateStr) {
const d = formatDueDate(dateStr);
if (!d) return '';
return `<span class="due-date ${d.cls}">
<i data-lucide="clock" style="width:11px;height:11px"></i> ${d.label}
<i data-lucide="clock" style="width:11px;height:11px" aria-hidden="true"></i> ${d.label}
</span>`;
}
@@ -108,11 +108,11 @@ function renderSwipeRow(task, innerHtml) {
return `
<div class="swipe-row" data-swipe-id="${task.id}" data-swipe-status="${task.status}">
<div class="swipe-reveal swipe-reveal--done" aria-hidden="true">
<i data-lucide="${isDone ? 'rotate-ccw' : 'check'}" style="width:22px;height:22px"></i>
<i data-lucide="${isDone ? 'rotate-ccw' : 'check'}" style="width:22px;height:22px" aria-hidden="true"></i>
<span>${isDone ? 'Öffnen' : 'Erledigt'}</span>
</div>
<div class="swipe-reveal swipe-reveal--edit" aria-hidden="true">
<i data-lucide="pencil" style="width:22px;height:22px"></i>
<i data-lucide="pencil" style="width:22px;height:22px" aria-hidden="true"></i>
<span>Bearbeiten</span>
</div>
${innerHtml}
@@ -133,7 +133,7 @@ function renderTaskCard(task, opts = {}) {
<button class="subtask-item__checkbox ${s.status === 'done' ? 'subtask-item__checkbox--done' : ''}"
data-action="toggle-subtask" data-id="${s.id}"
data-status="${s.status}" aria-label="${s.title} als erledigt markieren">
${s.status === 'done' ? '<i data-lucide="check" style="width:10px;height:10px;color:#fff"></i>' : ''}
${s.status === 'done' ? '<i data-lucide="check" style="width:10px;height:10px;color:#fff" aria-hidden="true"></i>' : ''}
</button>
<span class="subtask-item__title">${s.title}</span>
</div>`).join('')
@@ -145,7 +145,7 @@ function renderTaskCard(task, opts = {}) {
<button class="task-status-btn task-status-btn--${task.status}"
data-action="toggle-status" data-id="${task.id}" data-status="${task.status}"
aria-label="${task.title} als erledigt markieren">
<i data-lucide="check" class="task-status-btn__check"></i>
<i data-lucide="check" class="task-status-btn__check" aria-hidden="true"></i>
</button>
<div class="task-card__body">
@@ -155,7 +155,7 @@ function renderTaskCard(task, opts = {}) {
<div class="task-card__meta">
${renderPriorityBadge(task.priority)}
${renderDueDate(task.due_date)}
${task.is_recurring ? '<span class="due-date" title="Wiederkehrend"><i data-lucide="repeat" style="width:12px;height:12px"></i></span>' : ''}
${task.is_recurring ? '<span class="due-date" aria-label="Wiederkehrend"><i data-lucide="repeat" style="width:12px;height:12px" aria-hidden="true"></i></span>' : ''}
${task.category !== 'Sonstiges' ? `<span class="due-date">${task.category}</span>` : ''}
</div>
</div>
@@ -168,7 +168,7 @@ function renderTaskCard(task, opts = {}) {
<button class="btn btn--ghost btn--icon" data-action="edit-task" data-id="${task.id}"
aria-label="Aufgabe bearbeiten" style="min-height:unset;width:36px;height:36px">
<i data-lucide="pencil" style="width:16px;height:16px"></i>
<i data-lucide="pencil" style="width:16px;height:16px" aria-hidden="true"></i>
</button>
</div>
@@ -195,7 +195,7 @@ function renderTaskCard(task, opts = {}) {
function renderTaskGroups(tasks, groupMode) {
if (!tasks.length) {
return `<div class="tasks-empty">
<i data-lucide="check-circle-2" class="tasks-empty__icon"></i>
<i data-lucide="check-circle-2" class="tasks-empty__icon" aria-hidden="true"></i>
<div class="tasks-empty__title">Keine Aufgaben</div>
<div class="tasks-empty__desc">Erstelle eine neue Aufgabe mit dem + Button.</div>
</div>`;
@@ -467,7 +467,7 @@ function renderKanbanCard(task) {
<div class="kanban-card__title">${task.title}</div>
<div class="kanban-card__meta">
${renderPriorityBadge(task.priority)}
${due ? `<span class="due-date ${due.cls}"><i data-lucide="clock" style="width:10px;height:10px"></i> ${due.label}</span>` : ''}
${due ? `<span class="due-date ${due.cls}"><i data-lucide="clock" style="width:10px;height:10px" aria-hidden="true"></i> ${due.label}</span>` : ''}
</div>
${task.assigned_color ? `
<div class="kanban-card__footer">
@@ -915,11 +915,11 @@ export async function render(container, { user }) {
<div class="group-toggle" id="view-toggle">
<button class="group-toggle__btn group-toggle__btn--active" data-view="list"
title="Listenansicht" aria-label="Listenansicht">
<i data-lucide="list" style="width:14px;height:14px;pointer-events:none"></i>
<i data-lucide="list" style="width:14px;height:14px;pointer-events:none" aria-hidden="true"></i>
</button>
<button class="group-toggle__btn" data-view="kanban"
title="Kanban-Ansicht" aria-label="Kanban-Ansicht">
<i data-lucide="columns" style="width:14px;height:14px;pointer-events:none"></i>
<i data-lucide="columns" style="width:14px;height:14px;pointer-events:none" aria-hidden="true"></i>
</button>
</div>
<div class="group-toggle" id="group-mode-toggle">
@@ -927,7 +927,7 @@ export async function render(container, { user }) {
<button class="group-toggle__btn" data-mode="due">Fälligkeit</button>
</div>
<button class="btn btn--primary" id="btn-new-task" style="gap:var(--space-1)">
<i data-lucide="plus" style="width:18px;height:18px"></i> Neu
<i data-lucide="plus" style="width:18px;height:18px" aria-hidden="true"></i> Neu
</button>
</div>
</div>
@@ -943,7 +943,7 @@ export async function render(container, { user }) {
</div>`).join('')}
</div>
<button class="page-fab" id="fab-new-task" aria-label="Neue Aufgabe">
<i data-lucide="plus" style="width:24px;height:24px"></i>
<i data-lucide="plus" style="width:24px;height:24px" aria-hidden="true"></i>
</button>
</div>
`;