Skip to content

Commit 707e116

Browse files
mishig25claude
andauthored
fix(kit): keep shorthand doc URLs in the address bar on client-side nav (#794)
After #792, clicking a shorthand doc link (/docs/lib/page) canonicalized the address bar to the full /docs/lib/version/lang/page URL. Restore the old svelteKitCustomClient behavior: SvelteKit still resolves the expanded path internally (partial loading), but once the navigation completes the history entry is rewritten back to the shorthand the user clicked. The anchor's href is also restored right after SvelteKit reads it, and modified clicks (cmd/ctrl/middle) are left untouched so new tabs open the shorthand URL. Caveat: back/forward onto a shorthand history entry falls back to a full page load (the server serves the same page there). Verified with a browser test on the built accelerate docs: shorthand click SPA-navigates AND the address bar shows /docs/accelerate/quicktour. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent e2e7253 commit 707e116

1 file changed

Lines changed: 41 additions & 8 deletions

File tree

kit/src/routes/+layout.svelte

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
<script lang="ts">
33
import { onMount } from "svelte";
4+
import { afterNavigate } from "$app/navigation";
45
import { base } from "$app/paths";
56
import { getHfDocFullPath } from "$lib/hfDocPaths.js";
67
import type { RawChapter } from "./endpoints/toc/+server";
@@ -9,23 +10,55 @@
910
export let data;
1011
$: toc = (data.toc ?? []) as RawChapter[];
1112
13+
/**
14+
* Shorthand hf doc links (e.g. /docs/lib/page) should partial-load like
15+
* internal routes while keeping the shorthand URL in the address bar —
16+
* the behavior of the old `svelteKitCustomClient` fork.
17+
* SvelteKit treats URLs that don't start with the app's base path as
18+
* external before it consults the `reroute` hook (src/hooks.js), so:
19+
* 1. on click, momentarily expand the anchor's pathname to the full path
20+
* so SvelteKit's own click handler resolves it as an internal route,
21+
* 2. after the navigation completes, restore the shorthand URL in the
22+
* history entry.
23+
* Caveat: going back/forward onto a shorthand history entry falls back to
24+
* a full page load (the server serves the same page at shorthand URLs).
25+
*/
26+
let pendingShorthand: { href: string; fullPath: string } | null = null;
27+
1228
onMount(() => {
13-
// Expand shorthand hf doc links (e.g. /docs/lib/page) to the full path
14-
// before SvelteKit's own click handler reads the anchor, so they are
15-
// treated as internal routes (partial loading instead of a full reload).
16-
// Complements the `reroute` hook (src/hooks.js), which is not consulted
17-
// for URLs that don't start with the app's base path.
1829
const canonicalizeDocLinks = (event: MouseEvent) => {
30+
// same conditions as SvelteKit's click handler: plain left-clicks only,
31+
// so that e.g. cmd/ctrl-click opens the shorthand URL in a new tab
32+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
33+
return;
34+
}
1935
const anchor = (event.target as Element | null)?.closest("a");
20-
if (!anchor || anchor.origin !== location.origin) return;
21-
const fullPath = getHfDocFullPath(anchor.pathname);
22-
if (fullPath && fullPath !== anchor.pathname) {
36+
if (!anchor || anchor.origin !== location.origin || anchor.target) return;
37+
const shorthandPathname = anchor.pathname;
38+
const fullPath = getHfDocFullPath(shorthandPathname);
39+
if (fullPath && fullPath !== shorthandPathname) {
40+
pendingShorthand = { href: anchor.href, fullPath };
2341
anchor.pathname = fullPath;
42+
// restore the DOM link once SvelteKit's handler has read it
43+
setTimeout(() => {
44+
anchor.pathname = shorthandPathname;
45+
});
2446
}
2547
};
2648
document.addEventListener("click", canonicalizeDocLinks, { capture: true });
2749
return () => document.removeEventListener("click", canonicalizeDocLinks, { capture: true });
2850
});
51+
52+
afterNavigate((navigation) => {
53+
if (
54+
pendingShorthand &&
55+
navigation.type === "link" &&
56+
navigation.to?.url.pathname === pendingShorthand.fullPath
57+
) {
58+
history.replaceState(history.state, "", pendingShorthand.href);
59+
}
60+
pendingShorthand = null;
61+
});
2962
</script>
3063

3164
{#if !import.meta.env.DEV}

0 commit comments

Comments
 (0)