ぼざクリタグ広場 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.
 
 
 
 
 
 

150 lines
3.8 KiB

  1. import axios from 'axios'
  2. import toCamel from 'camelcase-keys'
  3. import { useEffect, useState } from 'react'
  4. import { Helmet } from 'react-helmet-async'
  5. import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'
  6. import PostList from '@/components/PostList'
  7. import TagLink from '@/components/TagLink'
  8. import WikiBody from '@/components/WikiBody'
  9. import PageTitle from '@/components/common/PageTitle'
  10. import TabGroup, { Tab } from '@/components/common/TabGroup'
  11. import MainArea from '@/components/layout/MainArea'
  12. import { API_BASE_URL, SITE_TITLE } from '@/config'
  13. import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
  14. import type { Post, Tag, WikiPage } from '@/types'
  15. export default () => {
  16. const params = useParams ()
  17. const title = params.title ?? ''
  18. const location = useLocation ()
  19. const navigate = useNavigate ()
  20. const defaultTag = { name: title, category: 'general' } as Tag
  21. const [posts, setPosts] = useState<Post[]> ([])
  22. const [tag, setTag] = useState (defaultTag)
  23. const [wikiPage, setWikiPage] = useState<WikiPage | null | undefined> (undefined)
  24. const query = new URLSearchParams (location.search)
  25. const version = query.get ('version')
  26. useEffect (() => {
  27. if (/^\d+$/.test (title))
  28. {
  29. void (async () => {
  30. setWikiPage (undefined)
  31. try
  32. {
  33. const res = await axios.get (`${ API_BASE_URL }/wiki/${ title }`)
  34. const data = res.data as WikiPage
  35. navigate (`/wiki/${ encodeURIComponent(data.title) }`, { replace: true })
  36. }
  37. catch
  38. {
  39. ;
  40. }
  41. }) ()
  42. return
  43. }
  44. void (async () => {
  45. setWikiPage (undefined)
  46. try
  47. {
  48. const res = await axios.get (
  49. `${ API_BASE_URL }/wiki/title/${ encodeURIComponent (title) }`,
  50. { params: version ? { version } : { } })
  51. const data = toCamel (res.data as any, { deep: true }) as WikiPage
  52. if (data.title !== title)
  53. navigate (`/wiki/${ encodeURIComponent(data.title) }`, { replace: true })
  54. setWikiPage (data)
  55. WikiIdBus.set (data.id)
  56. }
  57. catch
  58. {
  59. setWikiPage (null)
  60. }
  61. }) ()
  62. setPosts ([])
  63. void (async () => {
  64. try
  65. {
  66. const res = await axios.get (
  67. `${ API_BASE_URL }/posts?${ new URLSearchParams ({ tags: title,
  68. limit: '8' }) }`)
  69. const data = toCamel (res.data as any,
  70. { deep: true }) as { posts: Post[]
  71. nextCursor: string }
  72. setPosts (data.posts)
  73. }
  74. catch
  75. {
  76. ;
  77. }
  78. }) ()
  79. void (async () => {
  80. try
  81. {
  82. const res = await axios.get (
  83. `${ API_BASE_URL }/tags/name/${ encodeURIComponent (title) }`)
  84. setTag (toCamel (res.data as any, { deep: true }) as Tag)
  85. }
  86. catch
  87. {
  88. setTag (defaultTag)
  89. }
  90. }) ()
  91. return () => WikiIdBus.set (null)
  92. }, [title, location.search])
  93. return (
  94. <MainArea>
  95. <Helmet>
  96. <title>{`${ title } Wiki | ${ SITE_TITLE }`}</title>
  97. {!(wikiPage?.body) && <meta name="robots" content="noindex"/>}
  98. </Helmet>
  99. {(wikiPage && version) && (
  100. <div className="text-sm flex gap-3 items-center justify-center border border-gray-700 rounded px-2 py-1 mb-4">
  101. {wikiPage.pred ? (
  102. <Link to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.pred }`}>
  103. &lt; 古
  104. </Link>) : '(最古)'}
  105. <span>{wikiPage.updatedAt}</span>
  106. {wikiPage.succ ? (
  107. <Link to={`/wiki/${ encodeURIComponent (title) }?version=${ wikiPage.succ }`}>
  108. 新 &gt;
  109. </Link>) : '(最新)'}
  110. </div>)}
  111. <PageTitle>
  112. <TagLink tag={tag}
  113. withWiki={false}
  114. withCount={false}
  115. {...(version && { to: `/wiki/${ encodeURIComponent (title) }` })}/>
  116. </PageTitle>
  117. <div className="prose mx-auto p-4">
  118. {wikiPage === undefined
  119. ? 'Loading...'
  120. : <WikiBody title={title} body={wikiPage?.body}/>}
  121. </div>
  122. {(!(version) && posts.length > 0) && (
  123. <TabGroup>
  124. <Tab name="広場">
  125. <PostList posts={posts}/>
  126. </Tab>
  127. </TabGroup>)}
  128. </MainArea>)
  129. }