autosync toggle, configurable sync interval, 30-day session
- header Sync button now has a paired autosync toggle to its right — reads as one button with no inner seam (outer border only). Dot inside pulses once per actual sync (bursts on every backgroundSync / triggerSync / collab pollOnce via a new sync.pulse hook) so the user can see polls happen. Dot + data-autosync attribute persist the enabled state in localStorage; paused state stops both the CalDAV/relay background timer and the collab poll via a broadcast autosync.changed hook. - hover polish: Sync regains a full accent border (the missing inner edge re-appears only on its hover); the toggle fills with solid accent as hover treatment so the pair never shows a half-outline. - sync interval moved out of hardcode into a settings field under Settings → Relay: number input, 5s..3600s, default 15s (was 45s on caldav / 30s on collab). Changes broadcast via sync.interval.changed and restart both timers without reload. - session cookie lifetime raised to 30 days with matching gc_maxlifetime and SameSite=Lax (was 0 / Strict — some users got kicked to login on every reload when gc cleaned up the /tmp/sess file or a cross-link return blocked the cookie). - search button's kbd element was pushing the button ~3px taller than Sync; leading-none + tighter padding puts them on the same height. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6cd00f9660
commit
b7f450e41f
6 files changed
+222
-12
No files matched your search
+30
-6
@@ -17,10 +17,20 @@ if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
|
||||
}
|
||||
|
||||
// ── Session ──
|
||||
//
|
||||
// 30-day persistence: single-user local-first app, no reason to log the
|
||||
// user out every 24 minutes (PHP's gc_maxlifetime default). Cookie +
|
||||
// server-side GC are set to the same duration so the session survives
|
||||
// reboots AND page reloads, up to a month of inactivity.
|
||||
$sessionLifetime = 60 * 60 * 24 * 30; // 30 days
|
||||
ini_set('session.gc_maxlifetime', (string)$sessionLifetime);
|
||||
ini_set('session.cookie_lifetime', (string)$sessionLifetime);
|
||||
session_set_cookie_params([
|
||||
'lifetime' => $sessionLifetime,
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
|
||||
'samesite' => 'Strict',
|
||||
'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
|
||||
'samesite' => 'Lax', // Strict was blocking some cross-link returns; Lax still blocks CSRF
|
||||
]);
|
||||
session_start();
|
||||
|
||||
@@ -1301,11 +1311,16 @@ if (str_starts_with($route, '/api/')) {
|
||||
<span class="text-[10px] text-t-dim font-pixel ml-1" data-app-version>v<?= APP_VERSION ?></span>
|
||||
<button id="search-btn" class="flex items-center gap-2 px-2.5 py-1.5 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors ml-3">
|
||||
<i class="ph ph-magnifying-glass text-sm"></i><span class="font-pixel text-[10px]">Search</span>
|
||||
<kbd class="text-[9px] text-t-dim border border-t-border rounded px-1 py-0.5 ml-1 font-pixel">ctrl+k</kbd>
|
||||
</button>
|
||||
<button id="header-sync" class="flex items-center gap-2 px-2.5 py-1.5 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" data-tip="sync now">
|
||||
<i class="ph ph-arrows-clockwise text-sm" id="header-sync-icon"></i><span class="font-pixel text-[10px]">Sync</span>
|
||||
<kbd class="text-[9px] text-t-dim border border-t-border rounded px-1 ml-1 font-pixel leading-none" style="padding:1px 4px;">ctrl+k</kbd>
|
||||
</button>
|
||||
<div class="header-sync-group flex items-center">
|
||||
<button id="header-sync" class="flex items-center gap-2 px-2.5 py-1.5 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" data-tip="sync now">
|
||||
<i class="ph ph-arrows-clockwise text-sm" id="header-sync-icon"></i><span class="font-pixel text-[10px]">Sync</span>
|
||||
</button>
|
||||
<button id="header-autosync" class="flex items-center justify-center px-2 py-1.5 text-xs border border-t-border transition-colors" data-tip="auto-sync">
|
||||
<span id="header-autosync-dot" class="header-autosync-dot"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button id="calendar-btn" class="flex items-center gap-2 px-2.5 py-1.5 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors">
|
||||
@@ -1815,6 +1830,15 @@ if (str_starts_with($route, '/api/')) {
|
||||
<button id="relay-test" class="flex items-center gap-1.5 px-3 py-1.5 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors"><i class="ph ph-plugs-connected text-sm"></i><span class="font-pixel text-[10px]">Test</span></button>
|
||||
</div>
|
||||
<div id="relay-status" class="hidden mt-1 px-3 py-2 text-[10px] font-mono break-words border border-t-border bg-t-bg"></div>
|
||||
<div class="border-t border-t-border pt-4 mt-4">
|
||||
<div class="font-pixel text-[9px] uppercase tracking-wider text-t-dim mb-2"><i class="ph ph-timer text-xs"></i> sync frequency</div>
|
||||
<p class="text-[10px] text-t-dim leading-relaxed mb-2">How often the background sync polls the relay + CalDAV for new messages, collab updates and sync events. Lower = snappier, higher = less network traffic.</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="text-xs text-t-muted flex-1" for="setting-sync-interval">Poll every</label>
|
||||
<input id="setting-sync-interval" type="number" min="5" max="3600" step="1" class="bg-t-bg border border-t-border text-t-bright text-xs font-mono px-2 py-1 rounded-sm focus:border-t-accent focus:outline-none" style="width:72px;text-align:right;">
|
||||
<span class="text-xs text-t-dim">sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settings-panel-behavior" class="hidden space-y-5">
|
||||
<div>
|
||||
|
||||
Reference in new issue
Block a user