Skip to content

Commit

Permalink
refactor(pagination): support navigating to history page in `paginati…
Browse files Browse the repository at this point in the history
…on` mode (#246)
  • Loading branch information
Lanfei authored Feb 16, 2025
1 parent c8bd5f1 commit 7b6755d
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 90 deletions.
1 change: 0 additions & 1 deletion src/components/Base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export const Error = (props: {
},
props,
)
console.log(merged.h)
return (
<Center h={merged.h} p="$2" flexDirection="column">
<Box
Expand Down
90 changes: 25 additions & 65 deletions src/hooks/usePath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
State,
getPagination,
objStore,
getHistoryKey,
hasHistory,
recoverHistory,
clearHistory,
Expand All @@ -26,65 +27,21 @@ let first_fetch = true

let cancelObj: Canceler
let cancelList: Canceler
export function addOrUpdateQuery(
key: string,
value: any,
type = "replaceState",
) {
let url = type === "location" ? location.href : location.hash

if (!url.includes("?")) {
url = `${url}?${key}=${value}`
} else {
if (!url.includes(key)) {
url = `${url}&${key}=${value}`
} else {
const re = `(\\?|&|\#)${key}([^&|^#]*)(&|$|#)`
url = url.replace(new RegExp(re), "$1" + key + "=" + value + "$3")
}
}

if (type === "location") {
location.href = url
}

if (type === "pushState") {
history.pushState({}, "", url)
}

if (type === "replaceState") {
history.replaceState({}, "", url)
}
}
function getQueryVariable(name: string): string {
var query = window.location.search.substring(1)
var vars = query.split("&")
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=")
if (pair[0] == name) {
return pair[1]
}
}
return ""
}
const IsDirRecord: Record<string, boolean> = {}
let globalPage = 1
export const getGlobalPage = () => {
return globalPage
}
export const setGlobalPage = (page: number) => {
const pagination = getPagination()
globalPage = page
if (pagination.type === "pagination") {
addOrUpdateQuery("page", page)
}
console.log("setGlobalPage", globalPage)
// console.log("setGlobalPage", globalPage)
}
export const resetGlobalPage = () => {
setGlobalPage(1)
}
export const usePath = () => {
const { pathname, to } = useRouter()
const { pathname, to, searchParams } = useRouter()
const [, getObj] = useFetch((path: string) =>
fsGet(
path,
Expand All @@ -95,8 +52,8 @@ export const usePath = () => {
),
)
const pagination = getPagination()
if (pagination.type === "pagination" && getQueryVariable("page")) {
globalPage = parseInt(getQueryVariable("page"))
if (pagination.type === "pagination") {
setGlobalPage(parseInt(searchParams["page"]) || 1)
}
const [, getObjs] = useFetch(
(arg?: {
Expand Down Expand Up @@ -139,23 +96,30 @@ export const usePath = () => {
// handle pathname change
// if confirm current path is dir, fetch List directly
// if not, fetch get then determine if it is dir or file
const handlePathChange = (path: string, rp?: boolean, force?: boolean) => {
log(`handle [${path}] change`)
const handlePathChange = (
path: string,
index?: number,
rp?: boolean,
force?: boolean,
) => {
cancelObj?.()
cancelList?.()
retry_pass = rp ?? false
ObjStore.setErr("")
if (hasHistory(path)) {
return recoverHistory(path)
if (hasHistory(path, index)) {
log(`handle [${getHistoryKey(path, index)}] from history`)
return recoverHistory(path, index)
} else if (IsDirRecord[path]) {
return handleFolder(path, globalPage, undefined, undefined, force)
log(`handle [${getHistoryKey(path, index)}] as folder`)
return handleFolder(path, index, undefined, undefined, force)
} else {
return handleObj(path)
log(`handle [${getHistoryKey(path, index)}] as obj`)
return handleObj(path, index)
}
}

// handle enter obj that don't know if it is dir or file
const handleObj = async (path: string) => {
const handleObj = async (path: string, index?: number) => {
ObjStore.setState(State.FetchingObj)
const resp = await getObj(path)
handleRespWithoutNotify(
Expand All @@ -165,7 +129,7 @@ export const usePath = () => {
ObjStore.setProvider(data.provider)
if (data.is_dir) {
setPathAs(path)
handleFolder(path, globalPage)
handleFolder(path, index)
} else {
ObjStore.setReadme(data.readme)
ObjStore.setHeader(data.header)
Expand Down Expand Up @@ -197,7 +161,7 @@ export const usePath = () => {
handleRespWithoutNotify(
resp,
(data) => {
globalPage = index ?? 1
setGlobalPage(index ?? 1)
if (append) {
appendObjs(data.content)
} else {
Expand Down Expand Up @@ -237,35 +201,31 @@ export const usePath = () => {
}
}
}
const pageChange = (index?: number, size?: number, append = false) => {
return handleFolder(pathname(), index, size, append)
}
const loadMore = () => {
return pageChange(globalPage + 1, undefined, true)
return handleFolder(pathname(), globalPage + 1, undefined, true)
}
return {
handlePathChange: handlePathChange,
setPathAs: setPathAs,
refresh: async (retry_pass?: boolean, force?: boolean) => {
const path = pathname()
const scroll = window.scrollY
clearHistory(path)
clearHistory(path, globalPage)
if (
pagination.type === "load_more" ||
pagination.type === "auto_load_more"
) {
const page = globalPage
resetGlobalPage()
await handlePathChange(path, retry_pass, force)
await handlePathChange(path, globalPage, retry_pass, force)
while (globalPage < page) {
await loadMore()
}
} else {
await handlePathChange(path, retry_pass, force)
await handlePathChange(path, globalPage, retry_pass, force)
}
window.scroll({ top: scroll, behavior: "smooth" })
},
pageChange: pageChange,
loadMore: loadMore,
allLoaded: () => globalPage >= Math.ceil(objStore.total / pagination.size),
}
Expand Down
23 changes: 18 additions & 5 deletions src/hooks/useRouter.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {
NavigateOptions,
SetParams,
useLocation,
useNavigate,
useParams,
useSearchParams,
_mergeSearchString,
} from "@solidjs/router"
import { createMemo } from "solid-js"
import { createMemo, untrack } from "solid-js"
import { encodePath, joinBase, log, pathDir, pathJoin, trimBase } from "~/utils"
import { clearHistory } from "~/store"

const useRouter = () => {
const navigate = useNavigate()
const location = useLocation()
const [searchParams, setSearchParams] = useSearchParams()
const params = useParams()
const pathname = createMemo(() => {
return trimBase(location.pathname)
Expand Down Expand Up @@ -43,8 +43,21 @@ const useRouter = () => {
navigate(1)
},
pathname: pathname,
searchParams: searchParams,
setSearchParams: setSearchParams,
search: location.search,
searchParams: location.query,
setSearchParams: (
params: SetParams,
options?: Partial<NavigateOptions>,
) => {
const searchString = untrack(() =>
_mergeSearchString(location.search, params),
)
navigate(pathname() + searchString, {
scroll: false,
...options,
resolve: true,
})
},
params: params,
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/pages/home/Obj.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Text, useColorModeValue, VStack } from "@hope-ui/solid"
import {
createEffect,
createMemo,
createSignal,
lazy,
Match,
Expand All @@ -11,6 +12,7 @@ import {
import { Error, FullLoading, LinkWithBase } from "~/components"
import { resetGlobalPage, useObjTitle, usePath, useRouter, useT } from "~/hooks"
import {
getPagination,
objStore,
password,
recordHistory,
Expand All @@ -31,19 +33,27 @@ let first = true
export const Obj = () => {
const t = useT()
const cardBg = useColorModeValue("white", "$neutral3")
const { pathname } = useRouter()
const { pathname, searchParams } = useRouter()
const { handlePathChange, refresh } = usePath()
const pagination = getPagination()
const page = createMemo(() => {
return pagination.type === "pagination"
? parseInt(searchParams["page"]) || 1
: undefined
})
let lastPathname = pathname()
let lastPage = page()
createEffect(
on(pathname, (pathname) => {
on([pathname, page], async ([pathname, page]) => {
useObjTitle()
if (!first) {
recordHistory(lastPathname)
recordHistory(lastPathname, lastPage)
resetGlobalPage()
}
first = false
handlePathChange(pathname)
await handlePathChange(pathname, page)
lastPathname = pathname
lastPage = page
}),
)
return (
Expand Down
10 changes: 5 additions & 5 deletions src/pages/home/folder/Pager.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button, Text } from "@hope-ui/solid"
import { Match, onCleanup, onMount, Show, Switch } from "solid-js"
import { FullLoading, Paginator } from "~/components"
import { addOrUpdateQuery, getGlobalPage, usePath, useT } from "~/hooks"
import { getPagination, objStore, State } from "~/store"
import { getGlobalPage, usePath, useRouter, useT } from "~/hooks"
import { clearHistory, getPagination, objStore, State } from "~/store"

const Pagination = () => {
const pagination = getPagination()
const { pageChange } = usePath()
const { pathname, setSearchParams } = useRouter()
return (
<Paginator
total={objStore.total}
defaultCurrent={getGlobalPage()}
defaultPageSize={pagination.size}
onChange={(page) => {
addOrUpdateQuery("page", page)
pageChange(page)
clearHistory(pathname(), page)
setSearchParams({ page })
}}
/>
)
Expand Down
28 changes: 18 additions & 10 deletions src/store/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const waitForNextFrame = () => {
return new Promise((resolve) => setTimeout(resolve))
}

export const recordHistory = (path: string) => {
export const getHistoryKey = (path: string, page?: number) => {
return page && page > 1 ? `${path}?page=${page}` : path
}

export const recordHistory = (path: string, page?: number) => {
const obj = JSON.parse(JSON.stringify(objStore))
if (
![State.FetchingMore, State.Folder, State.File].includes(objStore.state)
Expand All @@ -23,17 +27,19 @@ export const recordHistory = (path: string) => {
if (objStore.state === State.FetchingMore) {
obj.state = State.Folder
}
const key = getHistoryKey(path, page)
const history = {
obj,
page: getGlobalPage(),
page: page ?? getGlobalPage(),
scroll: window.scrollY,
}
HistoryMap.set(path, history)
HistoryMap.set(key, history)
}

export const recoverHistory = async (path: string) => {
if (!HistoryMap.has(path)) return
const history = HistoryMap.get(path)!
export const recoverHistory = async (path: string, page?: number) => {
const key = getHistoryKey(path, page)
if (!HistoryMap.has(key)) return
const history = HistoryMap.get(key)!
setGlobalPage(history.page)
ObjStore.setState(State.Initial)
await waitForNextFrame()
Expand All @@ -42,10 +48,12 @@ export const recoverHistory = async (path: string) => {
window.scroll({ top: history.scroll, behavior: "smooth" })
}

export const hasHistory = (path: string) => {
return HistoryMap.has(path)
export const hasHistory = (path: string, page?: number) => {
const key = getHistoryKey(path, page)
return HistoryMap.has(key)
}

export const clearHistory = (path: string) => {
HistoryMap.delete(path)
export const clearHistory = (path: string, page?: number) => {
const key = getHistoryKey(path, page)
HistoryMap.delete(key)
}

0 comments on commit 7b6755d

Please sign in to comment.