Files
btrc-hub/frontend/src/pages/wiki/WikiDetailPage.tsx
T
2026-04-23 00:06:49 +09:00

129 lines
4.0 KiB
TypeScript

import { useQuery } from '@tanstack/react-query'
import { useEffect, useMemo } from 'react'
import { Helmet } from 'react-helmet-async'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import PostList from '@/components/PostList'
import PrefetchLink from '@/components/PrefetchLink'
import TagLink from '@/components/TagLink'
import WikiBody from '@/components/WikiBody'
import TabGroup, { Tab } from '@/components/common/TabGroup'
import MainArea from '@/components/layout/MainArea'
import { SITE_TITLE } from '@/config'
import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
import { fetchPosts } from '@/lib/posts'
import { postsKeys, tagsKeys, wikiKeys } from '@/lib/queryKeys'
import { fetchTagByName } from '@/lib/tags'
import { fetchWikiPage, fetchWikiPageByTitle } from '@/lib/wiki'
import type { Tag } from '@/types'
export default () => {
const params = useParams ()
const title = params.title ?? ''
const location = useLocation ()
const navigate = useNavigate ()
const defaultTag = useMemo (() => ({ name: title, category: 'general' } as Tag), [title])
const query = new URLSearchParams (location.search)
const version = query.get ('version') || undefined
const { data: wikiPage, isLoading: loading } = useQuery ({
enabled: Boolean (title) && !(/^\d+$/.test (title)),
queryKey: wikiKeys.show (title, { version }),
queryFn: () => fetchWikiPageByTitle (title, { version }) })
const effectiveTitle = wikiPage?.title ?? title
const { data: tag } = useQuery ({
enabled: Boolean (effectiveTitle),
queryKey: tagsKeys.show (effectiveTitle),
queryFn: () => fetchTagByName (effectiveTitle) })
const keys = {
tags: effectiveTitle, match: 'all', page: 1, limit: 8, url: '', title: '',
originalCreatedFrom: '', originalCreatedTo: '',
createdFrom: '', createdTo: '', updatedFrom: '', updatedTo: '',
order: 'original_created_at:desc' } as const
const { data } = useQuery ({
enabled: Boolean (effectiveTitle) && !(version),
queryKey: postsKeys.index (keys),
queryFn: () => fetchPosts (keys) })
const posts = data?.posts || []
useEffect (() => {
if (!(wikiPage))
return
WikiIdBus.set (wikiPage.id)
if (wikiPage.title !== title)
navigate (`/wiki/${ encodeURIComponent(wikiPage.title) }`, { replace: true })
return () => WikiIdBus.set (null)
}, [wikiPage, title, navigate])
useEffect (() => {
if (!(/^\d+$/.test (title)))
return
void (async () => {
try
{
const data = await fetchWikiPage (title, { })
navigate (`/wiki/${ encodeURIComponent(data.title) }`, { replace: true })
}
catch
{
;
}
}) ()
}, [title, navigate])
return (
<MainArea>
<Helmet>
<title>{`${ title } Wiki | ${ SITE_TITLE }`}</title>
{!(wikiPage?.body) && <meta name="robots" content="noindex"/>}
</Helmet>
{(wikiPage && version) && (
<div className="text-sm flex gap-3 items-center justify-center
border border-gray-700 rounded px-2 py-1 mb-4">
{wikiPage.pred ? (
<PrefetchLink to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.pred }`}>
&lt;
</PrefetchLink>) : '(最古)'}
<span>{wikiPage.updatedAt}</span>
{wikiPage.succ ? (
<PrefetchLink to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.succ }`}>
&gt;
</PrefetchLink>) : '(最新)'}
</div>)}
<article className="prose dark:prose-invert mx-auto p-4">
<h1 className="prose-a:no-underline">
<TagLink tag={tag ?? defaultTag}
withWiki={false}
withCount={false}
{...(version && { to: `/wiki/${ encodeURIComponent (title) }` })}/>
</h1>
{loading ? <div>Loading...</div> : <WikiBody title={title} body={wikiPage?.body}/>}
{(!(version) && posts.length > 0) && (
<div className="not-prose">
<TabGroup>
<Tab name="広場">
<PostList posts={posts}/>
</Tab>
</TabGroup>
</div>)}
</article>
</MainArea>)
}