48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import type { Action } from "svelte/action"
|
|
|
|
export const spaLink: Action<HTMLAnchorElement> = (node) => {
|
|
const onClick = (event: MouseEvent) => {
|
|
if (node.dataset.spaPrevent && node.dataset.spaPrevent !== "false") {
|
|
return
|
|
}
|
|
|
|
const anchor = event.currentTarget as HTMLAnchorElement
|
|
const isSelfTarget = anchor.target === "" || anchor.target === "_self"
|
|
|
|
if (isSelfTarget && anchor.href.startsWith(window.location.origin)) {
|
|
event.preventDefault()
|
|
const nextUrl = anchor.pathname + anchor.search + anchor.hash
|
|
const currentUrl = window.location.pathname + window.location.search + window.location.hash
|
|
|
|
if (nextUrl === currentUrl) {
|
|
window.scrollTo({ top: 0, behavior: "smooth" })
|
|
return
|
|
}
|
|
|
|
spaNavigate(nextUrl)
|
|
}
|
|
}
|
|
|
|
node.addEventListener("click", onClick)
|
|
|
|
return {
|
|
destroy() {
|
|
node.removeEventListener("click", onClick)
|
|
},
|
|
}
|
|
}
|
|
|
|
export const spaNavigate = (to: string, options?: { replace?: boolean }) => {
|
|
if (options?.replace) {
|
|
window.history.replaceState(null, "", to)
|
|
} else {
|
|
window.history.pushState(null, "", to)
|
|
}
|
|
|
|
window.scrollTo({ top: 0, behavior: "smooth" })
|
|
}
|
|
|
|
export const spaBack = () => {
|
|
window.history.back()
|
|
}
|