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

169 lines
4.2 KiB

  1. import { Fragment, useEffect, useState } from 'react'
  2. import { Helmet } from 'react-helmet-async'
  3. import { useLocation } from 'react-router-dom'
  4. import nikumaru from '@/assets/fonts/nikumaru.otf'
  5. import PrefetchLink from '@/components/PrefetchLink'
  6. import TagLink from '@/components/TagLink'
  7. import PageTitle from '@/components/common/PageTitle'
  8. import SectionTitle from '@/components/common/SectionTitle'
  9. import SubsectionTitle from '@/components/common/SubsectionTitle'
  10. import MainArea from '@/components/layout/MainArea'
  11. import { SITE_TITLE } from '@/config'
  12. import { apiGet } from '@/lib/api'
  13. import type { FC } from 'react'
  14. import type { Material, Tag } from '@/types'
  15. type TagWithMaterial = Omit<Tag, 'children'> & {
  16. children: TagWithMaterial[]
  17. material: Material | null }
  18. const MaterialCard = ({ tag }: { tag: TagWithMaterial }) => {
  19. if (!(tag.material))
  20. return
  21. return (
  22. <PrefetchLink
  23. to={`/materials/${ tag.material.id }`}
  24. className="block w-40 h-40">
  25. <div
  26. className="w-full h-full overflow-hidden rounded-xl shadow
  27. text-center content-center text-4xl"
  28. style={{ fontFamily: 'Nikumaru' }}>
  29. {(tag.material.contentType && /image\/.*/.test (tag.material.contentType))
  30. ? <img src={tag.material.file || undefined}/>
  31. : <span>照会</span>}
  32. </div>
  33. </PrefetchLink>)
  34. }
  35. const MaterialListPage: FC = () => {
  36. const [loading, setLoading] = useState (false)
  37. const [tag, setTag] = useState<TagWithMaterial | null> (null)
  38. const location = useLocation ()
  39. const query = new URLSearchParams (location.search)
  40. const tagQuery = query.get ('tag') ?? ''
  41. useEffect (() => {
  42. if (!(tagQuery))
  43. {
  44. setTag (null)
  45. return
  46. }
  47. void (async () => {
  48. try
  49. {
  50. setLoading (true)
  51. setTag (
  52. await apiGet<TagWithMaterial> (
  53. `/tags/name/${ encodeURIComponent (tagQuery) }/materials`))
  54. }
  55. finally
  56. {
  57. setLoading (false)
  58. }
  59. }) ()
  60. }, [location.search, tagQuery])
  61. return (
  62. <MainArea>
  63. <Helmet>
  64. <style>
  65. {`
  66. @font-face
  67. {
  68. font-family: 'Nikumaru';
  69. src: url(${ nikumaru }) format('opentype');
  70. }`}
  71. </style>
  72. <title>{`${ tag ? `${ tag.name } 素材集` : '素材集' } | ${ SITE_TITLE }`}</title>
  73. </Helmet>
  74. {loading ? 'Loading...' : (
  75. tag
  76. ? (
  77. <>
  78. <PageTitle>
  79. <TagLink
  80. tag={tag}
  81. withWiki={false}
  82. withCount={false}
  83. to={tag.material
  84. ? `/materials/${ tag.material.id }`
  85. : `/materials?tag=${ encodeURIComponent (tag.name) }`}/>
  86. </PageTitle>
  87. {(!(tag.material) && tag.category !== 'meme') && (
  88. <div className="-mt-2">
  89. <PrefetchLink
  90. to={`/materials/new?tag=${ encodeURIComponent (tag.name) }`}>
  91. 追加
  92. </PrefetchLink>
  93. </div>)}
  94. <MaterialCard tag={tag}/>
  95. <div className="ml-2">
  96. {tag.children.map (c2 => (
  97. <Fragment key={c2.id}>
  98. <SectionTitle>
  99. <TagLink
  100. tag={c2}
  101. withWiki={false}
  102. withCount={false}
  103. to={`/materials?tag=${ encodeURIComponent (c2.name) }`}/>
  104. </SectionTitle>
  105. {(!(c2.material) && c2.category !== 'meme') && (
  106. <div className="-mt-4">
  107. <PrefetchLink
  108. to={`/materials/new?tag=${ encodeURIComponent (c2.name) }`}>
  109. 追加
  110. </PrefetchLink>
  111. </div>)}
  112. <MaterialCard tag={c2}/>
  113. <div className="ml-2">
  114. {c2.children.map (c3 => (
  115. <Fragment key={c3.id}>
  116. <SubsectionTitle>
  117. <TagLink
  118. tag={c3}
  119. withWiki={false}
  120. withCount={false}
  121. to={`/materials?tag=${ encodeURIComponent (c3.name) }`}/>
  122. </SubsectionTitle>
  123. {(!(c3.material) && c3.category !== 'meme') && (
  124. <div className="-mt-2">
  125. <PrefetchLink
  126. to={`/materials/new?tag=${
  127. encodeURIComponent (c3.name) }`}>
  128. 追加
  129. </PrefetchLink>
  130. </div>)}
  131. <MaterialCard tag={c3}/>
  132. </Fragment>))}
  133. </div>
  134. </Fragment>))}
  135. </div>
  136. </>)
  137. : (
  138. <>
  139. <p>左のリストから照会したいタグを選択してください。</p>
  140. <p>もしくは……</p>
  141. <ul>
  142. <li><PrefetchLink to="/materials/new">素材を新規追加する</PrefetchLink></li>
  143. {/* <li><a href="#">すべての素材をダウンロードする</a></li> */}
  144. </ul>
  145. </>))}
  146. </MainArea>)
  147. }
  148. export default MaterialListPage