Zeigt automatisch wenn navigator.onLine === false.
Blendet sich aus sobald Verbindung wiederhergestellt.
reminders.css aus globalem <link> entfernt (wird lazy geladen).
- router.js: route-announcer used bare `path` variable which is not in scope
inside renderPage(); replaced with `route.path`
- dashboard.js: shoppingLists query used `HAVING open_count > 0` without GROUP BY;
SQLite rejects this — replaced with a WHERE subquery
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Birthdays module: CRUD with calendar/reminder auto-sync, photo upload, age notes
- Add DB migration 18 (birthdays table with calendar_event_id, trigger, indexes)
- Add dashboard widgets: birthdays, family participants, budget overview
- Add Settings > General: admins can set a custom app name (reflected in title/sidebar/login)
- Improve service worker: network-first caching for mutable JS/CSS assets
- Add translations for 16 locales (birthday keys)
Fixes applied during integration:
- innerHTML replaced with insertAdjacentHTML/replaceChildren throughout birthdays.js and dashboard.js
- docker-compose.yml personal dev changes reverted
Co-authored-by: Rafael Foster <rafaelgfoster@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- modal/_validateField: set aria-invalid on invalid inputs so screen readers
announce field errors; login.js mirrors this for username/password fields
- color pickers (notes, calendar): wrap swatches in role="radiogroup" with
aria-labelledby, add aria-checked per swatch, localized aria-labels instead
of hex values, roving tabindex with Arrow/Enter/Space keyboard navigation
- nav badges: badge spans get aria-hidden="true"; nav link aria-label updated
to include overdue count (tasks) or pending reminder count (reminders)
- router: remove aria-live from <main> (caused full page re-reads on nav);
add dedicated #route-announcer sr-only region with aria-live=polite +
aria-atomic, announces page label 50ms after render completes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When navigating to a secondary module (Budget, Recipes, Contacts, Settings),
the More button now displays the module's label and icon instead of "More".
This provides clearer navigation feedback to the user.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Implemented new recipes page with UI for managing recipes.
- Added REST API routes for recipes including create, read, update, and delete operations.
- Introduced database schema for recipes and recipe ingredients.
- Updated meals to link with recipes, allowing meals to reference specific recipes.
- Enhanced validation for recipe-related fields in meals.
- Added styles for the recipes page and components.
Root cause: when auth.me() failed during initial navigation, the catch block
called navigate('/login') without clearing _pendingLoginRedirect. The outer
finally then fired a second concurrent navigate('/login'), which held
isNavigating=true while running. If the user submitted the login form (or
iCloud Keychain autofilled credentials) before the second navigation
completed, navigate('/', user) was silently blocked by the isNavigating guard —
login appeared to succeed but the app never advanced to the dashboard.
Fix: clear _pendingLoginRedirect in the catch block so the finally handler
does not spawn the duplicate navigation.
Also adds a GET /api/v1/version endpoint (no auth required) and shows the
version on the login page, so users can verify their PWA has received the
latest cached JS.
Resolves#68
Co-authored-by: Ulas Kalayci <ulas.kalayci@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- pwa.css: body::after now uses var(--glass-bg) matching the nav's glass
background exactly; z-index lowered to z-nav-1 so the nav renders
on top in the overlap area (safe-area padding), removing the visible
color mismatch that appeared as empty space
- router.js: add iOS focusin/focusout handlers that temporarily set
maximum-scale=1 on input focus to prevent WKWebView auto-zoom;
restores original viewport content 150ms after blur so manual
zoom remains available for accessibility
Two causes of ~1s navigation delay fixed:
1. glass.css Section 19 was extending the page-in animation from 0.20s
to 0.30s using spring easing. Reverted to 0.20s in / 0.12s out.
2. During transitions, dozens of backdrop-filter layers (widgets, cards,
inputs, toolbars) were composited simultaneously for both the outgoing
and incoming page, overloading mid-range Android GPUs.
Added html.navigating class: router.js sets it at transition start,
glass.css overrides all app-content backdrop-filters to none while
active, animationend removes it once the in-animation completes.
- Add _pendingLoginRedirect flag in router.js to handle auth:expired
events that fire during active navigation (isNavigating=true).
Previously the navigate('/login') call was silently dropped, leaving
the user stuck on the dashboard with an error toast.
- Bump SHELL_CACHE v33→v34 and PAGES_CACHE v28→v29 to force cache
invalidation on iOS devices still running the pre-CSRF-fix code.
- Add err.status to dashboard error log for easier diagnostics.
Previous fix removed the old CSS when new CSS loaded, but that happened
BEFORE the out-animation completed - causing a flash of unstyled content.
Now the old stylesheet stays until replaceChildren removes the old DOM.
Increase font-size to 16px on mobile for shopping quick-add inputs,
notes search, and contacts search. Desktop breakpoint restores compact
sizes. Move 9 page-specific stylesheets from index.html to on-demand
loading in router.js, reducing initial CSS payload.
- Rename #page-content to #main-content so skip-to-content link
targets the semantic <main> landmark
- Add sr-only priority labels to dashboard task items for screen
readers (WCAG 1.4.1 color-not-only)
- Replace hardcoded hex in greeting gradient with accent tokens
so dark mode themes the banner correctly
- Replace hardcoded gap: 2px with --space-0h token
- Bump version to 0.7.2
Replace all — with - in all source files (JS, CSS, HTML, JSON,
Markdown) for consistency and readability.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all hardcoded German strings in router.js (navItems labels,
aria-labels, skip-link, error/toast messages) with t() calls. Add a
locale-changed event listener that re-renders sidebar and bottom-nav
items on language switch.
Uses visualViewport resize event to detect keyboard state (viewport height
< 75% of window height). Sets body.keyboard-visible class; CSS hides
.fab and .page-fab via visibility:hidden on screens < 1024px.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Configure manifest.json with scope, maskable icons, and categories. Add iOS/Android
meta tags for standalone behavior. Create pwa.css for native touch/scroll handling
and safe area insets. Add oikos-install-prompt Web Component with Chrome install
flow and iOS guidance. Optimize service worker with network-first navigation and
expanded precache (v19). Add dynamic theme-color per route and modal overlay dimming
in standalone mode. Generate placeholder icons via sharp script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Dark Mode: .form-input hatte kein Styling, Browser-Default führte zu
weißem Text auf weißem Hintergrund. Jetzt mit .input zusammengefasst.
2. Essensplan: DATE_RE fehlte im Import (ReferenceError), db.transaction()
wurde doppelt aufgerufen (3 Stellen).
3. Dashboard: Router-Guard verhinderte Re-Render bei Rücknavigation,
Widgets zeigten veraltete Daten.
4. Einkaufsliste: Mengenfeld hatte abweichende Hintergrundfarbe und
überdimensionierte min-height.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Skip-Link "Zum Inhalt springen" als erstes Element im App-Shell
- .sr-only:focus-visible CSS: sichtbar bei Tab-Focus, fixed top-left
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Alle 9 Menüpunkte jetzt auf Mobile erreichbar (2 Seiten)
- Horizontaler Scroll-Snap für seitenweises Swipen
- Dezente Dot-Indikatoren zeigen aktive Seite an
- Automatischer Scroll zur richtigen Seite bei Navigation zu Seite-2-Items
- Service Worker Cache v12
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- connect-sqlite3 durch eigenen BetterSQLiteStore ersetzt (sessions-Tabelle
in der bestehenden DB, keine native Kompilierung nötig)
- db.init() vor require('./auth') gezogen damit BetterSQLiteStore-Konstruktor
db.get() erfolgreich aufrufen kann
- router.js: App-Shell und pageWrapper vor module.render() in DOM einfügen
damit document.getElementById() in Seiten-Modulen funktioniert
- Seiten-Module (meals, notes, contacts, calendar, budget): _container-Referenz
eingeführt, alle document.getElementById() auf _container.querySelector() bzw.
document.querySelector() für body-Elemente umgestellt
- login.js: User-Objekt nach erfolgreichem Login an navigate() übergeben
damit auth.me()-Roundtrip entfällt
- calendar.js: /users → /auth/users korrigiert (404-Fix)
- SW-Cache v8 (erzwingt Reload aller gecachten Seiten-Module)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- router.js: navigateTo() existierte nicht → ReferenceError nach fehlgeschlagenem
auth.me(). Ersetzt durch navigate() + currentPath-Reset damit die Weiterleitung
nicht durch den currentPath-Guard geblockt wird.
- csrf.js: SESSION_SECURE=false wurde nicht berücksichtigt → CSRF-Cookie war über
HTTP nicht für JS lesbar → alle schreibenden API-Calls nach Login scheiterten mit 403.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>