ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

129 lines
4.0 KiB

  1. import { useQuery } from '@tanstack/react-query'
  2. import { useEffect, useMemo } from 'react'
  3. import { Helmet } from 'react-helmet-async'
  4. import { useLocation, useNavigate, useParams } from 'react-router-dom'
  5. import PostList from '@/components/PostList'
  6. import PrefetchLink from '@/components/PrefetchLink'
  7. import TagLink from '@/components/TagLink'
  8. import WikiBody from '@/components/WikiBody'
  9. import TabGroup, { Tab } from '@/components/common/TabGroup'
  10. import MainArea from '@/components/layout/MainArea'
  11. import { SITE_TITLE } from '@/config'
  12. import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
  13. import { fetchPosts } from '@/lib/posts'
  14. import { postsKeys, tagsKeys, wikiKeys } from '@/lib/queryKeys'
  15. import { fetchTagByName } from '@/lib/tags'
  16. import { fetchWikiPage, fetchWikiPageByTitle } from '@/lib/wiki'
  17. import type { Tag } from '@/types'
  18. export default () => {
  19. const params = useParams ()
  20. const title = params.title ?? ''
  21. const location = useLocation ()
  22. const navigate = useNavigate ()
  23. const defaultTag = useMemo (() => ({ name: title, category: 'general' } as Tag), [title])
  24. const query = new URLSearchParams (location.search)
  25. const version = query.get ('version') || undefined
  26. const { data: wikiPage, isLoading: loading } = useQuery ({
  27. enabled: Boolean (title) && !(/^\d+$/.test (title)),
  28. queryKey: wikiKeys.show (title, { version }),
  29. queryFn: () => fetchWikiPageByTitle (title, { version }) })
  30. const effectiveTitle = wikiPage?.title ?? title
  31. const { data: tag } = useQuery ({
  32. enabled: Boolean (effectiveTitle),
  33. queryKey: tagsKeys.show (effectiveTitle),
  34. queryFn: () => fetchTagByName (effectiveTitle) })
  35. const keys = {
  36. tags: effectiveTitle, match: 'all', page: 1, limit: 8, url: '', title: '',
  37. originalCreatedFrom: '', originalCreatedTo: '',
  38. createdFrom: '', createdTo: '', updatedFrom: '', updatedTo: '',
  39. order: 'original_created_at:desc' } as const
  40. const { data } = useQuery ({
  41. enabled: Boolean (effectiveTitle) && !(version),
  42. queryKey: postsKeys.index (keys),
  43. queryFn: () => fetchPosts (keys) })
  44. const posts = data?.posts || []
  45. useEffect (() => {
  46. if (!(wikiPage))
  47. return
  48. WikiIdBus.set (wikiPage.id)
  49. if (wikiPage.title !== title)
  50. navigate (`/wiki/${ encodeURIComponent(wikiPage.title) }`, { replace: true })
  51. return () => WikiIdBus.set (null)
  52. }, [wikiPage, title, navigate])
  53. useEffect (() => {
  54. if (!(/^\d+$/.test (title)))
  55. return
  56. void (async () => {
  57. try
  58. {
  59. const data = await fetchWikiPage (title, { })
  60. navigate (`/wiki/${ encodeURIComponent(data.title) }`, { replace: true })
  61. }
  62. catch
  63. {
  64. ;
  65. }
  66. }) ()
  67. }, [title, navigate])
  68. return (
  69. <MainArea>
  70. <Helmet>
  71. <title>{`${ title } Wiki | ${ SITE_TITLE }`}</title>
  72. {!(wikiPage?.body) && <meta name="robots" content="noindex"/>}
  73. </Helmet>
  74. {(wikiPage && version) && (
  75. <div className="text-sm flex gap-3 items-center justify-center
  76. border border-gray-700 rounded px-2 py-1 mb-4">
  77. {wikiPage.pred ? (
  78. <PrefetchLink to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.pred }`}>
  79. &lt; 古
  80. </PrefetchLink>) : '(最古)'}
  81. <span>{wikiPage.updatedAt}</span>
  82. {wikiPage.succ ? (
  83. <PrefetchLink to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.succ }`}>
  84. 新 &gt;
  85. </PrefetchLink>) : '(最新)'}
  86. </div>)}
  87. <article className="prose dark:prose-invert mx-auto p-4">
  88. <h1 className="prose-a:no-underline">
  89. <TagLink tag={tag ?? defaultTag}
  90. withWiki={false}
  91. withCount={false}
  92. {...(version && { to: `/wiki/${ encodeURIComponent (title) }` })}/>
  93. </h1>
  94. {loading ? <div>Loading...</div> : <WikiBody title={title} body={wikiPage?.body}/>}
  95. {(!(version) && posts.length > 0) && (
  96. <div className="not-prose">
  97. <TabGroup>
  98. <Tab name="広場">
  99. <PostList posts={posts}/>
  100. </Tab>
  101. </TabGroup>
  102. </div>)}
  103. </article>
  104. </MainArea>)
  105. }