fix(nav): clicking "Vinterliste" / "Min liste" while already there refreshes the list

Before: goHome() and goPublicHome() did pushUrl(path) + view=value.
When the user was already on /hjem (or /) both calls were no-ops —
clicking the wordmark or "Min liste" appeared to do nothing.

Add a monotonic reloadKey counter in App.svelte. Both nav handlers
bump it. Home.svelte takes reloadKey as a prop and runs load() in a
$effect when the value changes relative to what it last saw.

Skipping the first run is necessary because onMount() already kicks
off the initial load — the effect skips on init by comparing
reloadKey to lastSeenReloadKey, which both start equal. load()
doesn't touch reloadKey so the effect can't self-fire (the previous
$effect bug from the archive/hide toggles is documented inline).

Search query, edit-in-progress form, and other local state in Home
survive the refresh — only the activity fetch re-runs.
This commit is contained in:
Ole-Morten Duesund 2026-05-25 21:21:39 +02:00
commit 8ac1d8a0e6
2 changed files with 28 additions and 3 deletions

View file

@ -203,13 +203,22 @@
view = 'public-home';
}
// Bumped every time goHome / goPublicHome is invoked. Home.svelte
// watches it via a $effect and re-loads when it changes. This makes
// clicking the wordmark or "Min liste" while ALREADY on /hjem or /
// refresh the list — without it, pushUrl is a no-op (same path) and
// view = 'home' is a no-op (same value), so nothing happened before.
let reloadKey = $state(0);
function goHome() {
pushUrl('/hjem');
reloadKey++;
view = 'home';
}
function goPublicHome() {
pushUrl('/');
reloadKey++;
view = 'public-home';
}
</script>
@ -261,7 +270,7 @@
{:else if view === 'permalink'}
<ActivityPermalink id={activityId} onBack={backToCallerOrHome} />
{:else if view === 'public-home'}
<Home publicOnly={true} />
<Home publicOnly={true} reloadKey={reloadKey} />
{:else if view === 'login'}
<Login
defaultEmail={defaultEmail}
@ -291,7 +300,7 @@
{:else if view === 'tag'}
<TagPage tag={tagName} onBack={backToCallerOrHome} />
{:else}
<Home publicOnly={false} />
<Home publicOnly={false} reloadKey={reloadKey} />
{/if}
<footer style="margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--border); text-align: center;">

View file

@ -12,8 +12,12 @@
/** When true, render only public+semi (the "/" landing). When false, show
* the full authenticated dashboard including the viewer's own private rows. */
publicOnly?: boolean;
/** Monotonic counter from App. Changes (relative to the value at mount)
* trigger a re-fetch. Lets the wordmark / "Min liste" buttons refresh
* this view even when the user is already on /hjem or /. */
reloadKey?: number;
}
let { publicOnly = false }: Props = $props();
let { publicOnly = false, reloadKey = 0 }: Props = $props();
let activities: Activity[] = $state([]);
let loading = $state(true);
@ -31,8 +35,20 @@
let showArchived = $state(false);
let showHidden = $state(false);
// Track the reloadKey we've already reacted to so the $effect below
// only triggers when the prop CHANGES — not on first paint, where
// onMount already runs the initial load. load() doesn't touch reloadKey
// so this can't self-fire.
let lastSeenReloadKey = reloadKey;
onMount(() => load());
$effect(() => {
if (reloadKey !== lastSeenReloadKey) {
lastSeenReloadKey = reloadKey;
load();
}
});
async function load() {
loading = true;
try {