fix(ux): microinteraction fixes - swipe hint, locale loading, haptics, weather toast, FAB backdrop

- tasks.js: add maybeShowSwipeHint (long loop, max 3x) - matches shopping.js pattern
- tasks.js: vibrate(15) on task status toggle
- oikos-locale-picker: show disabled/loading state for both reload and setLocale paths
- dashboard: show success toast after weather refresh (all 4 locales)
- dashboard: add semi-transparent FAB backdrop to signal open mode
This commit is contained in:
Ulas
2026-04-05 13:23:16 +02:00
parent 796fe38913
commit 1722e70e7f
8 changed files with 54 additions and 4 deletions
+26
View File
@@ -656,6 +656,7 @@ function renderTaskList(container) {
stagger(listEl.querySelectorAll('.swipe-row, .kanban-card'));
updateOverdueBadge();
wireSwipeGestures(container);
maybeShowSwipeHint(container);
}
function renderFilters(container) {
@@ -728,6 +729,9 @@ const SWIPE_THRESHOLD = 80; // px - Mindestweg für Aktion
const SWIPE_MAX_VERT = 12; // px - vertikaler Bewegungs-Toleranzbereich (darunter: kein Scroll-Abbruch)
const SWIPE_LOCK_VERT = 30; // px - ab diesem Weg gilt es als Scroll (Swipe abgebrochen)
const SWIPE_HINT_KEY = 'oikos:swipeHintSeen';
const SWIPE_HINT_MAX = 3;
function wireSwipeGestures(container) {
const listEl = container.querySelector('#task-list');
if (!listEl) return;
@@ -850,6 +854,27 @@ function wireSwipeGestures(container) {
});
}
// --------------------------------------------------------
// Swipe-Affordance Hint (Long Loop)
// Zeigt den Nudge-Hinweis maximal 3x (gespeichert in localStorage).
// --------------------------------------------------------
function maybeShowSwipeHint(container) {
if (window.innerWidth >= 1024) return; // Desktop: Swipe nicht relevant
const count = parseInt(localStorage.getItem(SWIPE_HINT_KEY) ?? '0', 10);
if (count >= SWIPE_HINT_MAX) return;
const firstRow = container.querySelector('.swipe-row');
if (!firstRow) return;
firstRow.classList.add('swipe-row--hint');
firstRow.addEventListener('animationend', () => {
firstRow.classList.remove('swipe-row--hint');
}, { once: true });
localStorage.setItem(SWIPE_HINT_KEY, String(count + 1));
}
// --------------------------------------------------------
// Event-Verdrahtung
// --------------------------------------------------------
@@ -921,6 +946,7 @@ function wireTaskList(container) {
if (action === 'toggle-status') {
const status = target.dataset.status;
vibrate(15);
target.classList.toggle('task-status-btn--done', status !== 'done');
target.closest('.task-card')?.classList.toggle('task-card--done', status !== 'done');
try {