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

114 lines
3.3 KiB

  1. import { useQuery } from '@tanstack/react-query'
  2. import { useLayoutEffect, useRef, useState } from 'react'
  3. import { Helmet } from 'react-helmet-async'
  4. import { useLocation } from 'react-router-dom'
  5. import PostList from '@/components/PostList'
  6. import PrefetchLink from '@/components/PrefetchLink'
  7. import TagSidebar from '@/components/TagSidebar'
  8. import WikiBody from '@/components/WikiBody'
  9. import Pagination from '@/components/common/Pagination'
  10. import TabGroup, { Tab } from '@/components/common/TabGroup'
  11. import MainArea from '@/components/layout/MainArea'
  12. import { SITE_TITLE } from '@/config'
  13. import { fetchPosts } from '@/lib/posts'
  14. import { postsKeys } from '@/lib/queryKeys'
  15. import { fetchWikiPageByTitle } from '@/lib/wiki'
  16. import type { FC } from 'react'
  17. import type { WikiPage } from '@/types'
  18. export default (() => {
  19. const containerRef = useRef<HTMLDivElement | null> (null)
  20. const [wikiPage, setWikiPage] = useState<WikiPage | null> (null)
  21. const location = useLocation ()
  22. const query = new URLSearchParams (location.search)
  23. const tagsQuery = query.get ('tags') ?? ''
  24. const anyFlg = query.get ('match') === 'any'
  25. const match = anyFlg ? 'any' : 'all'
  26. const tags = tagsQuery.split (' ').filter (e => e !== '')
  27. const tagsKey = tags.join (' ')
  28. const page = Number (query.get ('page') ?? 1)
  29. const limit = Number (query.get ('limit') ?? 20)
  30. const keys = {
  31. tags: tagsKey, match, page, limit,
  32. url: '', title: '', originalCreatedFrom: '', originalCreatedTo: '',
  33. createdFrom: '', createdTo: '', updatedFrom: '', updatedTo: '',
  34. order: 'original_created_at:desc' } as const
  35. const { data, isLoading: loading } = useQuery ({
  36. queryKey: postsKeys.index (keys),
  37. queryFn: () => fetchPosts (keys) })
  38. const posts = data?.posts ?? []
  39. const cursor = ''
  40. const totalPages = data ? Math.ceil (data.count / limit) : 0
  41. useLayoutEffect (() => {
  42. scroll (0, 0)
  43. setWikiPage (null)
  44. if (tags.length !== 1)
  45. return
  46. void (async () => {
  47. try
  48. {
  49. const tagName = tags[0]
  50. setWikiPage (await fetchWikiPageByTitle (tagName, { }))
  51. }
  52. catch
  53. {
  54. ;
  55. }
  56. }) ()
  57. }, [location.search])
  58. return (
  59. <div className="md:flex md:flex-1" ref={containerRef}>
  60. <Helmet>
  61. <title>
  62. {tags.length
  63. ? `${ tags.join (anyFlg ? ' or ' : ' and ') } | ${ SITE_TITLE }`
  64. : `${ SITE_TITLE } 〜 ぼざろクリーチャーシリーズ綜合リンク集サイト`}
  65. </title>
  66. </Helmet>
  67. <TagSidebar posts={posts.slice (0, 20)} onClick={() => {
  68. const statesToSave = {
  69. posts, cursor,
  70. scroll: containerRef.current?.scrollTop ?? 0 }
  71. sessionStorage.setItem (`posts:${ tagsQuery }`,
  72. JSON.stringify (statesToSave))
  73. }}/>
  74. <MainArea>
  75. <TabGroup>
  76. <Tab name="広場">
  77. {posts.length > 0
  78. ? (
  79. <>
  80. <PostList posts={posts}/>
  81. <Pagination page={page} totalPages={totalPages}/>
  82. </>)
  83. : !(loading) && '広場には何もありませんよ.'}
  84. {loading && 'Loading...'}
  85. </Tab>
  86. {tags.length === 1 && (
  87. <Tab name="Wiki">
  88. <WikiBody title={tags[0]} body={wikiPage?.body}/>
  89. <div className="my-2">
  90. <PrefetchLink to={`/wiki/${ encodeURIComponent (tags[0]) }`}>
  91. Wiki を見る
  92. </PrefetchLink>
  93. </div>
  94. </Tab>)}
  95. </TabGroup>
  96. </MainArea>
  97. </div>)
  98. }) satisfies FC