Files
btrc-hub/frontend/src/pages/materials/MaterialListPage.tsx
T
2026-04-07 07:44:50 +09:00

167 lines
4.2 KiB
TypeScript

import { Fragment, useEffect, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useLocation } from 'react-router-dom'
import nikumaru from '@/assets/fonts/nikumaru.otf'
import PrefetchLink from '@/components/PrefetchLink'
import TagLink from '@/components/TagLink'
import PageTitle from '@/components/common/PageTitle'
import SectionTitle from '@/components/common/SectionTitle'
import SubsectionTitle from '@/components/common/SubsectionTitle'
import MainArea from '@/components/layout/MainArea'
import { SITE_TITLE } from '@/config'
import { apiGet } from '@/lib/api'
import type { FC } from 'react'
import type { Material, Tag } from '@/types'
type TagWithMaterial = Omit<Tag, 'children'> & {
children: TagWithMaterial[]
material: Material | null }
const MaterialCard = ({ tag }: { tag: TagWithMaterial }) => {
if (!(tag.material))
return
return (
<PrefetchLink
to={`/materials/${ tag.material.id }`}
className="block w-40 h-40">
<div
className="w-full h-full overflow-hidden rounded-xl shadow
text-center content-center text-4xl"
style={{ fontFamily: 'Nikumaru' }}>
{(tag.material.contentType && /image\/.*/.test (tag.material.contentType))
? <img src={tag.material.file || undefined}/>
: <span></span>}
</div>
</PrefetchLink>)
}
export default (() => {
const [loading, setLoading] = useState (false)
const [tag, setTag] = useState<TagWithMaterial | null> (null)
const location = useLocation ()
const query = new URLSearchParams (location.search)
const tagQuery = query.get ('tag') ?? ''
useEffect (() => {
if (!(tagQuery))
{
setTag (null)
return
}
void (async () => {
try
{
setLoading (true)
setTag (
await apiGet<TagWithMaterial> (
`/tags/name/${ encodeURIComponent (tagQuery) }/materials`))
}
finally
{
setLoading (false)
}
}) ()
}, [location.search])
return (
<MainArea>
<Helmet>
<style>
{`
@font-face
{
font-family: 'Nikumaru';
src: url(${ nikumaru }) format('opentype');
}`}
</style>
<title>{`${ tag ? `${ tag.name } 素材集` : '素材集' } | ${ SITE_TITLE }`}</title>
</Helmet>
{loading ? 'Loading...' : (
tag
? (
<>
<PageTitle>
<TagLink
tag={tag}
withWiki={false}
withCount={false}
to={tag.material
? `/materials/${ tag.material.id }`
: `/materials?tag=${ encodeURIComponent (tag.name) }`}/>
</PageTitle>
{(!(tag.material) && tag.category !== 'meme') && (
<div className="-mt-2">
<PrefetchLink
to={`/materials/new?tag=${ encodeURIComponent (tag.name) }`}>
</PrefetchLink>
</div>)}
<MaterialCard tag={tag}/>
<div className="ml-2">
{tag.children.map (c2 => (
<Fragment key={c2.id}>
<SectionTitle>
<TagLink
tag={c2}
withWiki={false}
withCount={false}
to={`/materials?tag=${ encodeURIComponent (c2.name) }`}/>
</SectionTitle>
{(!(c2.material) && c2.category !== 'meme') && (
<div className="-mt-4">
<PrefetchLink
to={`/materials/new?tag=${ encodeURIComponent (c2.name) }`}>
</PrefetchLink>
</div>)}
<MaterialCard tag={c2}/>
<div className="ml-2">
{c2.children.map (c3 => (
<Fragment key={c3.id}>
<SubsectionTitle>
<TagLink
tag={c3}
withWiki={false}
withCount={false}
to={`/materials?tag=${ encodeURIComponent (c3.name) }`}/>
</SubsectionTitle>
{(!(c3.material) && c3.category !== 'meme') && (
<div className="-mt-2">
<PrefetchLink
to={`/materials/new?tag=${
encodeURIComponent (c3.name) }`}>
</PrefetchLink>
</div>)}
<MaterialCard tag={c3}/>
</Fragment>))}
</div>
</Fragment>))}
</div>
</>)
: (
<>
<p></p>
<p></p>
<ul>
<li><PrefetchLink to="/materials/new"></PrefetchLink></li>
{/* <li><a href="#">すべての素材をダウンロードする</a></li> */}
</ul>
</>))}
</MainArea>)
}) satisfies FC