Skip to content

Commit 9df7b1a

Browse files
committed
Fix browser history bug by using Sveltekit shallow routing
1 parent b9b4ad3 commit 9df7b1a

2 files changed

Lines changed: 46 additions & 20 deletions

File tree

src/app.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ declare global {
55
// interface Error {}
66
// interface Locals {}
77
// interface PageData {}
8-
// interface PageState {}
8+
interface PageState {
9+
researchFilters?: {
10+
themes: string[];
11+
tags: string[];
12+
};
13+
}
914
// interface Platform {}
1015
}
1116

src/routes/research/+page.svelte

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import Youtube from 'svelte-youtube-embed';
77
88
import type { PageProps } from './$types';
9-
import { goto } from '$app/navigation';
9+
import { goto, pushState } from '$app/navigation';
10+
import { page } from '$app/state';
1011
1112
let { data }: PageProps = $props();
1213
@@ -65,12 +66,14 @@
6566
} else {
6667
filters[type].push(key);
6768
}
69+
syncHistory();
6870
}
6971
7072
function clearFilters() {
7173
query = '';
7274
filters.themes = [];
7375
filters.tags = [];
76+
syncHistory();
7477
}
7578
7679
function gotoPub(pub: Publication) {
@@ -81,30 +84,36 @@
8184
}
8285
}
8386
84-
let initializedFromHash = $state(false);
87+
function syncHistory() {
88+
const parts = [
89+
...filters.themes.map((t) => `theme=${t}`),
90+
...filters.tags.map((t) => `tag=${t}`),
91+
];
92+
const hash = parts.length ? `#${parts.join('&')}` : '';
93+
const url = page.url.pathname + page.url.search + hash;
94+
pushState(url, {
95+
researchFilters: { themes: [...filters.themes], tags: [...filters.tags] },
96+
});
97+
}
8598
86-
function parseHash() {
87-
initializedFromHash = true;
88-
const hash = window.location.hash.substring(1);
99+
function parseHash() {
100+
filters.themes = [];
101+
filters.tags = [];
102+
const hash = location.hash.slice(1);
89103
if (!hash) return;
90104
91-
const params = new URLSearchParams(hash);
92-
for (const [key, value] of params.entries()) {
105+
for (const [key, value] of new URLSearchParams(hash)) {
93106
filters[`${key}s`].push(value);
94107
}
95108
}
96109
97-
function updateHash() {
98-
if (filters.themes.length || filters.tags.length) {
99-
window.history.replaceState(null, '', `#${[...filters.themes.map(t => `theme=${t}`), ...filters.tags.map(t => `tag=${t}`)].join('&')}`);
100-
} else {
101-
// Remove hash completely
102-
window.history.replaceState(null, '', window.location.pathname + window.location.search);
103-
}
104-
}
105-
110+
// Restore filters on back/forward (syncHistory is not called here)
106111
$effect(() => {
107-
if (initializedFromHash) updateHash();
112+
const rf = page.state.researchFilters;
113+
if (!rf) return;
114+
if (_.isEqual(rf.themes, filters.themes) && _.isEqual(rf.tags, filters.tags)) return;
115+
filters.themes = rf.themes;
116+
filters.tags = rf.tags;
108117
});
109118
110119
onMount(() => {
@@ -118,7 +127,19 @@
118127
});
119128
}
120129
121-
parseHash();
130+
if (page.state.researchFilters) {
131+
filters.themes = page.state.researchFilters.themes;
132+
filters.tags = page.state.researchFilters.tags;
133+
} else {
134+
parseHash();
135+
}
136+
137+
// Initial landing has no researchFilters in history; restore from hash on back
138+
const onPopState = () => {
139+
if (!page.state.researchFilters) parseHash();
140+
};
141+
addEventListener('popstate', onPopState);
142+
return () => removeEventListener('popstate', onPopState);
122143
});
123144
</script>
124145

@@ -214,7 +235,7 @@
214235
</div>
215236
{/if}
216237
<div class="group" role="button" tabindex="0" onclick={() => gotoPub(pub)} onkeydown={(e) => e.key === 'Enter' || e.key === ' ' ? gotoPub(pub) : null}>
217-
<a href={pub.type === 'video' ? `https://youtu.be/${pub.youtube}` : `/pubs/${pub.slug}`} class="block">
238+
<a href={pub.type === 'video' ? `https://youtu.be/${pub.youtube}` : `/pubs/${pub.slug}`} onclick={(e) => e.stopPropagation()} class="block">
218239
<h4 class="text-md font-bold {pub.award ? 'text-violet-800' : 'text-amber-700'}">
219240
{#if pub.award}
220241
<i class="fas fa-award mr-1"></i>

0 commit comments

Comments
 (0)