import { useQuery } from '@tanstack/react-query' import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { Helmet } from 'react-helmet-async' import { useLocation, useNavigate } from 'react-router-dom' import PostList from '@/components/PostList' import PrefetchLink from '@/components/PrefetchLink' import TagSidebar from '@/components/TagSidebar' import WikiBody from '@/components/WikiBody' import Pagination from '@/components/common/Pagination' import TabGroup, { Tab } from '@/components/common/TabGroup' import MainArea from '@/components/layout/MainArea' import { SITE_TITLE } from '@/config' import { fetchPosts } from '@/lib/posts' import { postsKeys } from '@/lib/queryKeys' import { DEFAULT_POST_LIST_LIMIT, getClientListLimit, LIST_LIMIT_OPTIONS, setClientListSettings, } from '@/lib/settings' import { useKeyboardShortcuts } from '@/lib/useKeyboardShortcuts' import { fetchWikiPageByTitle } from '@/lib/wiki' import type { FC } from 'react' import type { WikiPage } from '@/types' const parseLimit = (value: string | null): 20 | 50 | 100 | null => { const n = Number (value) return n === 20 || n === 50 || n === 100 ? n : null } const PostListPage: FC = () => { const containerRef = useRef (null) const [wikiPage, setWikiPage] = useState (null) const location = useLocation () const navigate = useNavigate () const query = new URLSearchParams (location.search) const tagsQuery = query.get ('tags') ?? '' const anyFlg = query.get ('match') === 'any' const match = anyFlg ? 'any' : 'all' const tags = useMemo (() => tagsQuery.split (' ').filter (e => e !== ''), [tagsQuery]) const tagsKey = tags.join (' ') const page = Number (query.get ('page') ?? 1) const limit = ( parseLimit (query.get ('limit')) ?? getClientListLimit ('postList') ?? DEFAULT_POST_LIST_LIMIT ) const order = 'original_created_at:desc' as const const keys = { tags: tagsKey, match, page, limit, url: '', title: '', originalCreatedFrom: '', originalCreatedTo: '', createdFrom: '', createdTo: '', updatedFrom: '', updatedTo: '', order } as const const { data, isLoading: loading } = useQuery ({ queryKey: postsKeys.index (keys), queryFn: () => fetchPosts (keys) }) const posts = data?.posts ?? [] const cursor = '' const totalPages = data ? Math.ceil (data.count / limit) : 0 useEffect (() => { setClientListSettings ('postList', { limit }) }, [limit]) const updatePage = (nextPage: number) => { const params = new URLSearchParams (location.search) params.set ('page', String (Math.max (1, nextPage))) navigate (`${ location.pathname }?${ params.toString () }`) } const updateListQuery = (next: { limit?: 20 | 50 | 100 }) => { const params = new URLSearchParams (location.search) params.set ('limit', String (next.limit ?? limit)) params.set ('page', '1') navigate (`${ location.pathname }?${ params.toString () }`) } useKeyboardShortcuts (useMemo (() => ({ ...(page > 1 ? { 'pagination.previous': () => { updatePage (page - 1) }, } : { }), ...(totalPages > 0 && page < totalPages ? { 'pagination.next': () => { updatePage (Math.min (page + 1, totalPages)) }, } : { }), }), [page, totalPages, location.search])) useLayoutEffect (() => { scroll (0, 0) setWikiPage (null) if (tags.length !== 1) return void (async () => { try { const tagName = tags[0] setWikiPage (await fetchWikiPageByTitle (tagName, { })) } catch { ; } }) () }, [location.search, tags]) return (
{tags.length ? `${ tags.join (anyFlg ? ' or ' : ' and ') } | ${ SITE_TITLE }` : `${ SITE_TITLE }\u3000〜 ぼざろクリーチャーシリーズ綜合リンク集サイト`} { const statesToSave = { posts, cursor, scroll: containerRef.current?.scrollTop ?? 0 } sessionStorage.setItem (`posts:${ tagsQuery }`, JSON.stringify (statesToSave)) }}/> 件数 }> {posts.length > 0 ? ( <> ) : !(loading) && '広場には何もありませんよ.'} {loading && 'Loading...'} {tags.length === 1 && (
Wiki を見る
)}
) } export default PostListPage