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

143 lines
4.3 KiB

  1. import { useQuery } from '@tanstack/react-query'
  2. import { motion } from 'framer-motion'
  3. import { useEffect } from 'react'
  4. import { Helmet } from 'react-helmet-async'
  5. import { useLocation } from 'react-router-dom'
  6. import TagLink from '@/components/TagLink'
  7. import PrefetchLink from '@/components/PrefetchLink'
  8. import PageTitle from '@/components/common/PageTitle'
  9. import Pagination from '@/components/common/Pagination'
  10. import MainArea from '@/components/layout/MainArea'
  11. import { SITE_TITLE } from '@/config'
  12. import { fetchPostChanges } from '@/lib/posts'
  13. import { postsKeys, tagsKeys } from '@/lib/queryKeys'
  14. import { fetchTag } from '@/lib/tags'
  15. import { cn, dateString } from '@/lib/utils'
  16. import type { FC } from 'react'
  17. export default (() => {
  18. const location = useLocation ()
  19. const query = new URLSearchParams (location.search)
  20. const id = query.get ('id')
  21. const tagId = query.get ('tag')
  22. const page = Number (query.get ('page') ?? 1)
  23. const limit = Number (query.get ('limit') ?? 20)
  24. // 投稿列の結合で使用
  25. let rowsCnt: number
  26. const { data: tag } =
  27. tagId
  28. ? useQuery ({ queryKey: tagsKeys.show (tagId),
  29. queryFn: () => fetchTag (tagId) })
  30. : { data: null }
  31. const { data, isLoading: loading } = useQuery ({
  32. queryKey: postsKeys.changes ({ ...(id && { id }),
  33. ...(tagId && { tag: tagId }),
  34. page, limit }),
  35. queryFn: () => fetchPostChanges ({ ...(id && { id }),
  36. ...(tagId && { tag: tagId }),
  37. page, limit }) })
  38. const changes = data?.changes ?? []
  39. const totalPages = data ? Math.ceil (data.count / limit) : 0
  40. useEffect (() => {
  41. document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' })
  42. }, [location.search])
  43. const layoutIds: string[] = []
  44. return (
  45. <MainArea>
  46. <Helmet>
  47. <title>{`耕作履歴 | ${ SITE_TITLE }`}</title>
  48. </Helmet>
  49. <PageTitle>
  50. 耕作履歴
  51. {id && <>: 投稿 {<PrefetchLink to={`/posts/${ id }`}>#{id}</PrefetchLink>}</>}
  52. {tag && <>(<TagLink tag={tag} withWiki={false} withCount={false}/>)</>}
  53. </PageTitle>
  54. {loading ? 'Loading...' : (
  55. <>
  56. <table className="table-auto w-full border-collapse">
  57. <thead className="border-b-2 border-black dark:border-white">
  58. <tr>
  59. <th className="p-2 text-left">投稿</th>
  60. <th className="p-2 text-left">変更</th>
  61. <th className="p-2 text-left">日時</th>
  62. </tr>
  63. </thead>
  64. <tbody>
  65. {changes.map ((change, i) => {
  66. const withPost = i === 0 || change.post.id !== changes[i - 1].post.id
  67. if (withPost)
  68. {
  69. rowsCnt = 1
  70. for (let j = i + 1;
  71. (j < changes.length
  72. && change.post.id === changes[j].post.id);
  73. ++j)
  74. ++rowsCnt
  75. }
  76. let layoutId: string | undefined = `page-${ change.post.id }`
  77. if (layoutIds.includes (layoutId))
  78. layoutId = undefined
  79. else
  80. layoutIds.push (layoutId)
  81. return (
  82. <tr key={`${ change.timestamp }-${ change.post.id }-${ change.tag?.id }`}
  83. className={cn ('even:bg-gray-100 dark:even:bg-gray-700',
  84. withPost && 'border-t')}>
  85. {withPost && (
  86. <td className="align-top p-2 bg-white dark:bg-[#242424] border-r"
  87. rowSpan={rowsCnt}>
  88. <PrefetchLink to={`/posts/${ change.post.id }`}>
  89. <motion.div
  90. layoutId={layoutId}
  91. transition={{ type: 'spring',
  92. stiffness: 500,
  93. damping: 40,
  94. mass: .5 }}>
  95. <img src={change.post.thumbnail
  96. || change.post.thumbnailBase
  97. || undefined}
  98. alt={change.post.title || change.post.url}
  99. title={change.post.title || change.post.url || undefined}
  100. className="w-40"/>
  101. </motion.div>
  102. </PrefetchLink>
  103. </td>)}
  104. <td className="p-2">
  105. {change.tag
  106. ? <TagLink tag={change.tag} withWiki={false} withCount={false}/>
  107. : '(マスタ削除済のタグ) '}
  108. {`を${ change.changeType === 'add' ? '記載' : '消除' }`}
  109. </td>
  110. <td className="p-2">
  111. {change.user
  112. ? (
  113. <PrefetchLink to={`/users/${ change.user.id }`}>
  114. {change.user.name}
  115. </PrefetchLink>)
  116. : 'bot 操作'}
  117. <br/>
  118. {dateString (change.timestamp)}
  119. </td>
  120. </tr>)
  121. })}
  122. </tbody>
  123. </table>
  124. <Pagination page={page} totalPages={totalPages}/>
  125. </>)}
  126. </MainArea>)
  127. }) satisfies FC