Skip to content

Commit 00e35af

Browse files
committed
fix: galgame page jump state
1 parent 6b1f0e5 commit 00e35af

File tree

8 files changed

+253
-138
lines changed

8 files changed

+253
-138
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"nord",
9696
"nospoiler",
9797
"nprogress",
98+
"nuqs",
9899
"Nuxt",
99100
"Nyaa",
100101
"nyne",

app/galgame/page.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,43 @@ import { CardContainer } from '~/components/galgame/Container'
22
import { kunGetActions } from './actions'
33
import { ErrorComponent } from '~/components/error/ErrorComponent'
44
import { kunMetadata } from './metadata'
5-
import { Suspense } from 'react'
5+
import { galgameSearchParamsCache } from '~/components/galgame/_searchParams'
6+
import { NuqsAdapter } from 'nuqs/adapters/next/app'
67
import type { Metadata } from 'next'
8+
import type { SearchParams } from 'nuqs/server'
79

810
export const revalidate = 5
911

1012
export const metadata: Metadata = kunMetadata
1113

1214
interface Props {
13-
searchParams?: Promise<{ page?: number }>
15+
searchParams: Promise<SearchParams>
1416
}
1517

1618
export default async function Kun({ searchParams }: Props) {
17-
const res = await searchParams
18-
const currentPage = res?.page ? res.page : 1
19+
const { page, type, sortField, sortOrder, years, months } =
20+
await galgameSearchParamsCache.parse(searchParams)
1921

2022
const response = await kunGetActions({
21-
selectedType: 'all',
22-
sortField: 'resource_update_time',
23-
sortOrder: 'desc',
24-
page: currentPage,
23+
selectedType: type,
24+
sortField,
25+
sortOrder,
26+
page,
2527
limit: 24,
26-
yearString: JSON.stringify(['all']),
27-
monthString: JSON.stringify(['all'])
28+
yearString: JSON.stringify(years),
29+
monthString: JSON.stringify(months)
2830
})
31+
2932
if (typeof response === 'string') {
3033
return <ErrorComponent error={response} />
3134
}
3235

3336
return (
34-
<Suspense>
37+
<NuqsAdapter>
3538
<CardContainer
3639
initialGalgames={response.galgames}
3740
initialTotal={response.total}
3841
/>
39-
</Suspense>
42+
</NuqsAdapter>
4043
)
4144
}

components/galgame/Container.tsx

Lines changed: 133 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,133 @@
1-
'use client'
2-
3-
import { useEffect, useState } from 'react'
4-
import { Pagination } from '@heroui/pagination'
5-
import { kunFetchGet } from '~/utils/kunFetch'
6-
import { GalgameCard } from './Card'
7-
import { FilterBar } from './FilterBar'
8-
import { useMounted } from '~/hooks/useMounted'
9-
import { KunLoading } from '~/components/kun/Loading'
10-
import { KunHeader } from '../kun/Header'
11-
import { useRouter, useSearchParams } from 'next/navigation'
12-
import type { SortDirection, SortOption } from './_sort'
13-
14-
interface Props {
15-
initialGalgames: GalgameCard[]
16-
initialTotal: number
17-
}
18-
19-
export const CardContainer = ({ initialGalgames, initialTotal }: Props) => {
20-
const [galgames, setGalgames] = useState<GalgameCard[]>(initialGalgames)
21-
const [total, setTotal] = useState(initialTotal)
22-
const [loading, setLoading] = useState(false)
23-
const [selectedType, setSelectedType] = useState<string>('all')
24-
const [sortField, setSortField] = useState<SortOption>('resource_update_time')
25-
const [sortOrder, setSortOrder] = useState<SortDirection>('desc')
26-
const [selectedYears, setSelectedYears] = useState<string[]>(['all'])
27-
const [selectedMonths, setSelectedMonths] = useState<string[]>(['all'])
28-
const isMounted = useMounted()
29-
const router = useRouter()
30-
const searchParams = useSearchParams()
31-
const [page, setPage] = useState(Number(searchParams.get('page')) || 1)
32-
33-
const fetchPatches = async () => {
34-
setLoading(true)
35-
36-
const { galgames, total } = await kunFetchGet<{
37-
galgames: GalgameCard[]
38-
total: number
39-
}>('/galgame', {
40-
selectedType,
41-
sortField,
42-
sortOrder,
43-
page,
44-
limit: 24,
45-
yearString: JSON.stringify(selectedYears),
46-
monthString: JSON.stringify(selectedMonths)
47-
})
48-
49-
setGalgames(galgames)
50-
setTotal(total)
51-
setLoading(false)
52-
}
53-
54-
useEffect(() => {
55-
if (!isMounted) {
56-
return
57-
}
58-
fetchPatches()
59-
}, [sortField, sortOrder, selectedType, page, selectedYears, selectedMonths])
60-
61-
const handlePageChange = (newPage: number) => {
62-
setPage(newPage)
63-
setTimeout(() => {
64-
window.scrollTo(0, 0)
65-
})
66-
const params = new URLSearchParams(window.location.search)
67-
params.set('page', newPage.toString())
68-
router.push(`?${params.toString()}`)
69-
}
70-
71-
return (
72-
<div className="container mx-auto my-4 space-y-6">
73-
<KunHeader
74-
name="Galgame"
75-
description="本页面默认仅显示了 SFW (内容安全) 的补丁, 您可以在网站右上角切换显示全部补丁 (包括 NSFW, 也就是显示可能带有涩涩的补丁)"
76-
/>
77-
78-
<FilterBar
79-
selectedType={selectedType}
80-
setSelectedType={(key) => {
81-
if (key) {
82-
setSelectedType(key)
83-
}
84-
}}
85-
sortField={sortField}
86-
setSortField={setSortField}
87-
sortOrder={sortOrder}
88-
setSortOrder={setSortOrder}
89-
selectedYears={selectedYears}
90-
setSelectedYears={setSelectedYears}
91-
selectedMonths={selectedMonths}
92-
setSelectedMonths={setSelectedMonths}
93-
/>
94-
95-
{loading ? (
96-
<KunLoading hint="正在获取 Galgame 数据..." />
97-
) : (
98-
<div className="grid grid-cols-2 gap-2 mx-auto mb-8 sm:gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
99-
{galgames.map((pa) => (
100-
<GalgameCard key={pa.id} patch={pa} />
101-
))}
102-
</div>
103-
)}
104-
105-
{total > 24 && (
106-
<div className="flex justify-center">
107-
<Pagination
108-
total={Math.ceil(total / 24)}
109-
page={page}
110-
onChange={handlePageChange}
111-
showControls
112-
color="primary"
113-
size="lg"
114-
/>
115-
</div>
116-
)}
117-
</div>
118-
)
119-
}
1+
'use client'
2+
3+
import { useEffect, useState, useTransition } from 'react'
4+
import { useQueryStates } from 'nuqs'
5+
import { kunFetchGet } from '~/utils/kunFetch'
6+
import { GalgameCard } from './Card'
7+
import { FilterBar } from './FilterBar'
8+
import { useMounted } from '~/hooks/useMounted'
9+
import { KunLoading } from '~/components/kun/Loading'
10+
import { KunHeader } from '../kun/Header'
11+
import { KunPagination } from '~/components/kun/KunPagination'
12+
import { galgameParsers } from './_searchParams'
13+
import type { SortDirection, SortOption } from './_searchParams'
14+
15+
interface Props {
16+
initialGalgames: GalgameCard[]
17+
initialTotal: number
18+
}
19+
20+
export const CardContainer = ({ initialGalgames, initialTotal }: Props) => {
21+
const [galgames, setGalgames] = useState<GalgameCard[]>(initialGalgames)
22+
const [total, setTotal] = useState(initialTotal)
23+
const [loading, setLoading] = useState(false)
24+
const isMounted = useMounted()
25+
const [isPending, startTransition] = useTransition()
26+
27+
const [params, setParams] = useQueryStates(galgameParsers, {
28+
shallow: false,
29+
startTransition
30+
})
31+
32+
const { page, type, sortField, sortOrder, years, months } = params
33+
34+
const fetchPatches = async () => {
35+
setLoading(true)
36+
37+
const { galgames, total } = await kunFetchGet<{
38+
galgames: GalgameCard[]
39+
total: number
40+
}>('/galgame', {
41+
selectedType: type,
42+
sortField,
43+
sortOrder,
44+
page,
45+
limit: 24,
46+
yearString: JSON.stringify(years),
47+
monthString: JSON.stringify(months)
48+
})
49+
50+
setGalgames(galgames)
51+
setTotal(total)
52+
setLoading(false)
53+
}
54+
55+
useEffect(() => {
56+
if (!isMounted) {
57+
return
58+
}
59+
fetchPatches()
60+
}, [sortField, sortOrder, type, page, years, months])
61+
62+
const handlePageChange = (newPage: number) => {
63+
setParams({ page: newPage })
64+
setTimeout(() => {
65+
window.scrollTo(0, 0)
66+
})
67+
}
68+
69+
const handleTypeChange = (newType: string) => {
70+
if (newType) {
71+
setParams({ type: newType, page: 1 })
72+
}
73+
}
74+
75+
const handleSortFieldChange = (newSortField: SortOption) => {
76+
setParams({ sortField: newSortField, page: 1 })
77+
}
78+
79+
const handleSortOrderChange = (newSortOrder: SortDirection) => {
80+
setParams({ sortOrder: newSortOrder, page: 1 })
81+
}
82+
83+
const handleYearsChange = (newYears: string[]) => {
84+
setParams({ years: newYears, page: 1 })
85+
}
86+
87+
const handleMonthsChange = (newMonths: string[]) => {
88+
setParams({ months: newMonths, page: 1 })
89+
}
90+
91+
return (
92+
<div className="container mx-auto my-4 space-y-6">
93+
<KunHeader
94+
name="Galgame"
95+
description="本页面默认仅显示了 SFW (内容安全) 的补丁, 您可以在网站右上角切换显示全部补丁 (包括 NSFW, 也就是显示可能带有涩涩的补丁)"
96+
/>
97+
98+
<FilterBar
99+
selectedType={type}
100+
setSelectedType={handleTypeChange}
101+
sortField={sortField}
102+
setSortField={handleSortFieldChange}
103+
sortOrder={sortOrder}
104+
setSortOrder={handleSortOrderChange}
105+
selectedYears={years}
106+
setSelectedYears={handleYearsChange}
107+
selectedMonths={months}
108+
setSelectedMonths={handleMonthsChange}
109+
/>
110+
111+
{loading || isPending ? (
112+
<KunLoading hint="正在获取 Galgame 数据..." />
113+
) : (
114+
<div className="grid grid-cols-2 gap-2 mx-auto mb-8 sm:gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
115+
{galgames.map((pa) => (
116+
<GalgameCard key={pa.id} patch={pa} />
117+
))}
118+
</div>
119+
)}
120+
121+
{total > 24 && (
122+
<div className="flex justify-center">
123+
<KunPagination
124+
page={page}
125+
total={Math.ceil(total / 24)}
126+
onChange={handlePageChange}
127+
isDisabled={loading || isPending}
128+
/>
129+
</div>
130+
)}
131+
</div>
132+
)
133+
}

components/galgame/FilterBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
GALGAME_SORT_YEARS_MAP,
2424
GALGAME_SORT_MONTHS
2525
} from '~/constants/galgame'
26-
import type { SortDirection, SortOption } from './_sort'
26+
import type { SortDirection, SortOption } from './_searchParams'
2727

2828
interface Props {
2929
selectedType: string
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {
2+
createSearchParamsCache,
3+
parseAsArrayOf,
4+
parseAsInteger,
5+
parseAsString,
6+
parseAsStringLiteral
7+
} from 'nuqs/server'
8+
9+
export const sortFieldOptions = [
10+
'resource_update_time',
11+
'created',
12+
'view',
13+
'download'
14+
] as const
15+
export type SortOption = (typeof sortFieldOptions)[number]
16+
17+
export const sortOrderOptions = ['asc', 'desc'] as const
18+
export type SortDirection = (typeof sortOrderOptions)[number]
19+
20+
export const galgameParsers = {
21+
page: parseAsInteger.withDefault(1),
22+
type: parseAsString.withDefault('all'),
23+
sortField: parseAsStringLiteral(sortFieldOptions).withDefault(
24+
'resource_update_time'
25+
),
26+
sortOrder: parseAsStringLiteral(sortOrderOptions).withDefault('desc'),
27+
years: parseAsArrayOf(parseAsString).withDefault(['all']),
28+
months: parseAsArrayOf(parseAsString).withDefault(['all'])
29+
}
30+
31+
export const galgameSearchParamsCache = createSearchParamsCache(galgameParsers)

components/galgame/_sort.d.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
"node-cron": "^4.2.1",
102102
"nodemailer": "^7.0.9",
103103
"nodemailer-smtp-transport": "^2.7.4",
104+
"nuqs": "^2.8.9",
104105
"react": "^19.2.1",
105106
"react-dom": "^19.2.1",
106107
"react-dropzone": "^14.3.8",

0 commit comments

Comments
 (0)