User avatar (Google picture), avatar in mobile You tab, /account page

- Capture the Google profile picture (picture claim) into users.avatar_url; an
  Avatar component shows it, falling back to the initial. Used in the desktop
  header and the mobile "You" tab (which now shows the user when signed in).
- Move account/settings to its own route /account (robust + scrolls to top),
  reached by the desktop avatar and the mobile You tab; drop the inline "You"
  sheet. AccountPanel gains a Sign out action; the page links to Saved/History/
  Boundaries via home intent params (?view= / ?open=).
- db: users.avatar_url (schema + idempotent migration). 118 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-03 14:41:43 +00:00
parent bb008cfaa5
commit 15728c3bcb
11 changed files with 168 additions and 87 deletions
@@ -1,7 +1,7 @@
<script>
import { onMount } from 'svelte';
import { getJSON, postJSON, delJSON } from '$lib/api.js';
import { clearLocal } from '$lib/auth.svelte.js';
import { clearLocal, logout as authLogout } from '$lib/auth.svelte.js';
let { onclose } = $props();
let info = $state(null);
@@ -19,6 +19,11 @@
}
});
async function signOut() {
await authLogout();
onclose?.();
}
async function logoutEverywhere() {
busy = 'logout';
try {
@@ -64,6 +69,7 @@
<div class="row"><span class="k">Active sessions</span><span class="v">{info.sessions}</span></div>
<div class="actions">
<button class="btn" onclick={signOut}>Sign out</button>
<a class="btn" href="/api/account/export">Export my data</a>
<button class="btn" onclick={logoutEverywhere} disabled={busy === 'logout'}>
{busy === 'logout' ? 'Signing out…' : 'Sign out everywhere'}