diff --git a/config.php b/config.php index 7830864..eec9a6d 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,7 @@ button:first-child { + border-right: 0 !important; +} +.header-sync-group > button:first-child:hover { + border-right: 1px solid var(--t-accent) !important; +} +.header-sync-group > button + button { + border-left: 0 !important; + align-self: stretch; +} +#header-autosync:hover { + background: var(--t-accent); + border-color: var(--t-accent) !important; + color: var(--t-bg) !important; +} + +/* Autosync toggle button. + Border stays neutral in both states — the dot carries the status + signal (accent + pulse when on, grey when off). Hover styling is + handled by the bg-fill rule further down. */ +#header-autosync { + border-color: var(--t-border); + color: var(--t-muted); +} + +.header-autosync-dot { + display: inline-block; + width: 9px; height: 9px; + border-radius: 50%; + background: var(--t-accent); + transition: background 0.15s, transform 0.2s; +} +#header-autosync[data-autosync="off"] .header-autosync-dot { + background: var(--t-dim); + box-shadow: none; +} +/* Hover: button fills with solid accent (matching the Sync button's + hover border color). Dot switches to the app background color so it + reads as a knockout against the fill. Pulsing keeps tracking real + status — when a sync fires during hover the ring still animates. */ +#header-autosync:hover .header-autosync-dot { + background: var(--t-bg); +} +/* Pulse shadow is accent-colored too, which would be invisible against + the accent fill. Swap it to a bg-toned ring during hover so the + pulse stays visible. */ +#header-autosync:hover .header-autosync-dot.pulsing { + animation: header-autosync-pulse-on-hover 0.9s ease-out 1; +} +@keyframes header-autosync-pulse-on-hover { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--t-bg) 75%, transparent); transform: scale(1); } + 40% { transform: scale(1.4); } + 100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--t-bg) 0%, transparent); transform: scale(1); } +} + +/* Burst pulse on each sync. JS adds `.pulsing` at the start of a sync + and removes it after the animation finishes. Tuned to be visible + against the button background — a generous ring that fades out. */ +.header-autosync-dot.pulsing { + animation: header-autosync-pulse 0.9s ease-out 1; +} +@keyframes header-autosync-pulse { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--t-accent) 75%, transparent); transform: scale(1); } + 40% { transform: scale(1.4); } + 100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--t-accent) 0%, transparent); transform: scale(1); } +} diff --git a/public/index.php b/public/index.php index 14d502d..10fa70e 100644 --- a/public/index.php +++ b/public/index.php @@ -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/')) { v - +
+ + +
+
+
sync frequency
+

How often the background sync polls the relay + CalDAV for new messages, collab updates and sync events. Lower = snappier, higher = less network traffic.

+
+ + + sec +
+