|
1 | 1 |
|
2 | 2 | <script lang="ts"> |
3 | 3 | import { onMount } from "svelte"; |
| 4 | + import { afterNavigate } from "$app/navigation"; |
4 | 5 | import { base } from "$app/paths"; |
5 | 6 | import { getHfDocFullPath } from "$lib/hfDocPaths.js"; |
6 | 7 | import type { RawChapter } from "./endpoints/toc/+server"; |
|
9 | 10 | export let data; |
10 | 11 | $: toc = (data.toc ?? []) as RawChapter[]; |
11 | 12 |
|
| 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 | +
|
12 | 28 | 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. |
18 | 29 | 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 | + } |
19 | 35 | 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 }; |
23 | 41 | anchor.pathname = fullPath; |
| 42 | + // restore the DOM link once SvelteKit's handler has read it |
| 43 | + setTimeout(() => { |
| 44 | + anchor.pathname = shorthandPathname; |
| 45 | + }); |
24 | 46 | } |
25 | 47 | }; |
26 | 48 | document.addEventListener("click", canonicalizeDocLinks, { capture: true }); |
27 | 49 | return () => document.removeEventListener("click", canonicalizeDocLinks, { capture: true }); |
28 | 50 | }); |
| 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 | + }); |
29 | 62 | </script> |
30 | 63 |
|
31 | 64 | {#if !import.meta.env.DEV} |
|
0 commit comments