relay UI overhaul, favicon, settings, admin last-seen, fixes

Relay:
  - Inbox/shared/sent split into own view-inbox (nav button + poll).
    Compose is now single-column, centered.
  - Header logo links to compose. Inbox badge stays fresh on all
    views via a quiet loadInbox on every view switch.
  - Mobile menu: full-height sheet below header, larger buttons
    (15px font, 14px padding), full width.
  - Login form wrapped in <form> with name attributes + for/id on
    labels so password managers can autofill.
  - Admin user list shows "last seen <relative time>" per user.
    last_seen_at column on tenants, updated on every authenticated
    request (session + client API).
  - Cache-busting on style.css + app.js via filemtime.
  - View persistence in localStorage (survives reload).
  - Shared-bucket cards show title only (preview line removed).

Favicon:
  - favicon.svg added to project root + copied to public/, relay/,
    website/. Linked via <link rel="icon" type="image/svg+xml"> in
    all three <head> sections.

Settings:
  - New toggle: "Show shopping list items in task collector"
    (default off). collectTasks skips #einkauf/#shopping cards when
    disabled.

Fixes:
  - card-spinner gets display:inline-block so it rotates outside
    flex containers (shopping save spinner).
  - Tim tab test opens the plugin before checking active state.
  - Compose view centered with margin:auto on desktop.

Bumps to 1.9.29.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-17 13:16:23 +02:00
1 parent 8e738ed9d4
commit d50f9fe789
19 files changed
+209 -101

No files matched your search

+1 -1
View File
@@ -14,7 +14,7 @@ if (!defined('RELAY_BOOTSTRAPPED')) { http_response_code(404); exit; }
if ($route === '/api/users' && $method === 'GET') {
if (!$sessionTenant || !$sessionTenant['is_admin']) jsonResponse(['error' => 'admin only'], 403);
$rows = $db->query('SELECT id, username, is_admin, created_at FROM tenants ORDER BY id ASC')->fetchAll();
$rows = $db->query('SELECT id, username, is_admin, created_at, last_seen_at FROM tenants ORDER BY id ASC')->fetchAll();
jsonResponse(['users' => $rows]);
}