2022-09-22 09:37:49 +00:00
|
|
|
import type { Accessor } from 'solid-js'
|
2022-09-09 13:30:25 +00:00
|
|
|
import { createRouter, createSearchParams } from '@nanostores/router'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { isServer } from 'solid-js/web'
|
2022-09-22 09:37:49 +00:00
|
|
|
import { useStore } from '@nanostores/solid'
|
2023-07-18 15:42:34 +00:00
|
|
|
import { hydrationPromise } from '../utils/hydrationPromise'
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2023-02-10 01:19:20 +00:00
|
|
|
export const ROUTES = {
|
|
|
|
home: '/',
|
|
|
|
inbox: '/inbox',
|
|
|
|
connect: '/connect',
|
|
|
|
create: '/create',
|
2023-05-08 17:21:06 +00:00
|
|
|
edit: '/edit/:shoutId',
|
|
|
|
editSettings: '/edit/:shoutId/settings',
|
2023-04-21 15:10:23 +00:00
|
|
|
drafts: '/drafts',
|
2023-02-10 01:19:20 +00:00
|
|
|
topics: '/topics',
|
|
|
|
topic: '/topic/:slug',
|
|
|
|
authors: '/authors',
|
|
|
|
author: '/author/:slug',
|
|
|
|
feed: '/feed',
|
2023-07-07 16:53:01 +00:00
|
|
|
feedMy: '/feed/my',
|
|
|
|
feedNotifications: '/feed/notifications',
|
|
|
|
feedDiscussions: '/feed/discussions',
|
|
|
|
feedBookmarks: '/feed/bookmarks',
|
|
|
|
feedCollaborations: '/feed/collaborations',
|
2023-02-10 01:19:20 +00:00
|
|
|
search: '/search/:q?',
|
|
|
|
dogma: '/about/dogma',
|
|
|
|
discussionRules: '/about/discussion-rules',
|
|
|
|
guide: '/about/guide',
|
|
|
|
help: '/about/help',
|
|
|
|
manifest: '/about/manifest',
|
|
|
|
partners: '/about/partners',
|
|
|
|
principles: '/about/principles',
|
|
|
|
projects: '/about/projects',
|
|
|
|
termsOfUse: '/about/terms-of-use',
|
|
|
|
thanks: '/about/thanks',
|
|
|
|
expo: '/expo/:layout',
|
|
|
|
profileSettings: '/profile/settings',
|
|
|
|
profileSecurity: '/profile/security',
|
2023-07-31 20:19:08 +00:00
|
|
|
profileSubscriptions: '/profile/subscriptions',
|
|
|
|
fourOuFour: '/404',
|
|
|
|
article: '/:slug'
|
2023-02-10 01:19:20 +00:00
|
|
|
} as const
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-09-22 09:37:49 +00:00
|
|
|
const searchParamsStore = createSearchParams()
|
2023-02-10 01:19:20 +00:00
|
|
|
const routerStore = createRouter(ROUTES, {
|
|
|
|
search: false,
|
|
|
|
links: false
|
|
|
|
})
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-09-22 09:37:49 +00:00
|
|
|
export const router = routerStore
|
|
|
|
|
2023-07-31 21:43:41 +00:00
|
|
|
export const DEFAULT_HEADER_OFFSET = 80 // 80px for header
|
|
|
|
|
2023-04-03 12:55:00 +00:00
|
|
|
const checkOpenOnClient = (link: HTMLAnchorElement, event) => {
|
|
|
|
return (
|
2022-09-22 09:37:49 +00:00
|
|
|
link &&
|
|
|
|
event.button === 0 &&
|
|
|
|
link.target !== '_blank' &&
|
|
|
|
link.rel !== 'external' &&
|
|
|
|
!link.download &&
|
|
|
|
!event.metaKey &&
|
|
|
|
!event.ctrlKey &&
|
|
|
|
!event.shiftKey &&
|
|
|
|
!event.altKey
|
2023-04-03 12:55:00 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-04-03 14:22:59 +00:00
|
|
|
const scrollToHash = (hash: string) => {
|
|
|
|
let selector = hash
|
|
|
|
|
|
|
|
if (/^#\d+/.test(selector)) {
|
|
|
|
// id="1" fix
|
|
|
|
// https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers
|
|
|
|
selector = `[id="${selector.replace('#', '')}"]`
|
|
|
|
}
|
|
|
|
|
|
|
|
const anchor = document.querySelector(selector)
|
|
|
|
const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0
|
2023-07-31 21:43:41 +00:00
|
|
|
const newScrollTop = elementPosition + window.scrollY - DEFAULT_HEADER_OFFSET
|
2023-04-03 14:22:59 +00:00
|
|
|
|
|
|
|
window.scrollTo({
|
|
|
|
top: newScrollTop,
|
|
|
|
behavior: 'smooth'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleClientRouteLinkClick = async (event) => {
|
2023-04-03 12:55:00 +00:00
|
|
|
const link = event.target.closest('a')
|
|
|
|
|
|
|
|
if (!checkOpenOnClient(link, event)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const url = new URL(link.href)
|
|
|
|
if (url.origin !== location.origin) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
2023-07-18 15:42:34 +00:00
|
|
|
await hydrationPromise
|
|
|
|
|
2023-04-03 12:55:00 +00:00
|
|
|
if (url.pathname) {
|
|
|
|
routerStore.open(url.pathname)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (url.search) {
|
|
|
|
const params = Object.fromEntries(new URLSearchParams(url.search))
|
|
|
|
searchParamsStore.open(params)
|
|
|
|
}
|
|
|
|
|
2023-04-03 14:22:59 +00:00
|
|
|
if (!url.hash) {
|
2023-04-03 12:55:00 +00:00
|
|
|
window.scrollTo({
|
2023-04-03 14:22:59 +00:00
|
|
|
top: 0,
|
|
|
|
left: 0
|
2023-04-03 12:55:00 +00:00
|
|
|
})
|
|
|
|
return
|
2022-09-22 09:37:49 +00:00
|
|
|
}
|
2023-04-20 14:01:15 +00:00
|
|
|
scrollToHash(url.hash)
|
2022-09-22 09:37:49 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 20:19:08 +00:00
|
|
|
export const initRouter = (pathname: string, search?: Record<string, string>) => {
|
2022-09-22 09:37:49 +00:00
|
|
|
routerStore.open(pathname)
|
|
|
|
const params = Object.fromEntries(new URLSearchParams(search))
|
|
|
|
searchParamsStore.open(params)
|
2022-11-15 16:16:31 +00:00
|
|
|
|
|
|
|
if (!isServer) {
|
|
|
|
document.addEventListener('click', handleClientRouteLinkClick)
|
|
|
|
}
|
2022-09-09 11:53:35 +00:00
|
|
|
}
|
|
|
|
|
2022-09-22 09:37:49 +00:00
|
|
|
export const useRouter = <TSearchParams extends Record<string, string> = Record<string, string>>() => {
|
2022-10-25 16:25:42 +00:00
|
|
|
const page = useStore(routerStore)
|
|
|
|
const searchParams = useStore(searchParamsStore) as unknown as Accessor<TSearchParams>
|
|
|
|
|
|
|
|
const changeSearchParam = <TKey extends keyof TSearchParams>(
|
|
|
|
key: TKey,
|
|
|
|
value: TSearchParams[TKey],
|
|
|
|
replace = false
|
|
|
|
) => {
|
|
|
|
const newSearchParams = { ...searchParamsStore.get() }
|
|
|
|
if (value === null) {
|
|
|
|
delete newSearchParams[key.toString()]
|
|
|
|
} else {
|
|
|
|
newSearchParams[key.toString()] = value
|
|
|
|
}
|
2022-09-22 09:37:49 +00:00
|
|
|
|
2022-10-25 16:25:42 +00:00
|
|
|
searchParamsStore.open(newSearchParams, replace)
|
2022-09-22 09:37:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2022-10-25 16:25:42 +00:00
|
|
|
page,
|
|
|
|
searchParams,
|
2023-04-03 12:55:00 +00:00
|
|
|
changeSearchParam
|
2022-09-22 09:37:49 +00:00
|
|
|
}
|
2022-09-09 11:53:35 +00:00
|
|
|
}
|