This commit is contained in:
2025-06-29 05:21:40 +09:00
parent 934225f9e8
commit 8814be9ee9
4 changed files with 61 additions and 37 deletions
+13
View File
@@ -0,0 +1,13 @@
import ReactMarkdown from 'react-markdown'
import { Link } from 'react-router-dom'
type Props = { body: string }
export default ({ body }: Props) => (
<ReactMarkdown components={{ a: (
({ href, children }) => (['/', '.'].some (e => href?.startsWith (e))
? <Link to={href!}>{children}</Link>
: <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>)) }}>
{body}
</ReactMarkdown>)
+1 -1
View File
@@ -5,7 +5,7 @@ type TabProps = { name: string
init?: boolean init?: boolean
children: React.ReactNode } children: React.ReactNode }
type Props = { children: React.ReactElement<{ name: string }>[] } type Props = { children: React.ReactElement<TabProps>[] }
export const Tab = ({ children }: TabProps) => <>{children}</> export const Tab = ({ children }: TabProps) => <>{children}</>
+43 -26
View File
@@ -1,17 +1,21 @@
import axios from 'axios' import axios from 'axios'
import toCamel from 'camelcase-keys'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import TagSidebar from '@/components/TagSidebar' import TagSidebar from '@/components/TagSidebar'
import WikiBody from '@/components/WikiBody'
import TabGroup, { Tab } from '@/components/common/TabGroup'
import MainArea from '@/components/layout/MainArea' import MainArea from '@/components/layout/MainArea'
import { API_BASE_URL, SITE_TITLE } from '@/config' import { API_BASE_URL, SITE_TITLE } from '@/config'
import type { Post, Tag } from '@/types' import type { Post, Tag, WikiPage } from '@/types'
export default () => { export default () => {
const [posts, setPosts] = useState<Post[]> ([]) const [posts, setPosts] = useState<Post[]> ([])
const [wikiPage, setWikiPage] = useState<WikiPage | null> (null)
const location = useLocation () const location = useLocation ()
const query = new URLSearchParams (location.search) const query = new URLSearchParams (location.search)
@@ -21,21 +25,20 @@ export default () => {
const tags = tagsQuery.split (' ').filter (e => e !== '') const tags = tagsQuery.split (' ').filter (e => e !== '')
useEffect(() => { useEffect(() => {
const fetchPosts = async () => { void (axios.get (`${ API_BASE_URL }/posts`, {
try params: { tags: tags.join (','),
{ match: (anyFlg ? 'any' : 'all') } })
const res = await axios.get (`${ API_BASE_URL }/posts`, { .then (res => setPosts (res.data))
params: { tags: tags.join (','), .catch (err => {
match: (anyFlg ? 'any' : 'all') } }) console.error ('Failed to fetch posts:', err)
setPosts (res.data) setPosts ([])
} }))
catch (error)
{ if (!(tags.length))
console.error ('Failed to fetch posts:', error) return
setPosts ([]) void (axios.get (`${ API_BASE_URL }/wiki/title/${ encodeURIComponent (tags.join (' ')) }`)
} .then (res => setWikiPage (toCamel (res.data, { deep: true })))
} .catch (() => setWikiPage (null)))
fetchPosts()
}, [location.search]) }, [location.search])
return ( return (
@@ -49,16 +52,30 @@ export default () => {
</Helmet> </Helmet>
<TagSidebar posts={posts} /> <TagSidebar posts={posts} />
<MainArea> <MainArea>
<div className="flex flex-wrap gap-4 p-4"> <TabGroup key={wikiPage}>
{posts.map (post => ( <Tab name="広場">
<Link to={`/posts/${ post.id }`} {posts.length
key={post.id} ? (
className="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg"> <div className="flex flex-wrap gap-4 p-4">
<img src={post.thumbnail ?? post.thumbnail_base} {posts.map (post => (
className="object-none w-full h-full" /> <Link to={`/posts/${ post.id }`}
</Link> key={post.id}
))} className="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg">
</div> <img src={post.thumbnail ?? post.thumbnail_base}
className="object-none w-full h-full" />
</Link>
))}
</div>)
: '広場には何もありませんよ.'}
</Tab>
{(wikiPage && wikiPage.body) && (
<Tab name="Wiki" init={!(posts.length)}>
<WikiBody body={wikiPage.body} />
<div className="my-2">
<Link to={`/wiki/${ wikiPage.title }`}>Wiki </Link>
</div>
</Tab>)}
</TabGroup>
</MainArea> </MainArea>
</>) </>)
} }
+4 -10
View File
@@ -2,9 +2,9 @@ import axios from 'axios'
import toCamel from 'camelcase-keys' import toCamel from 'camelcase-keys'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import ReactMarkdown from 'react-markdown'
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom' import { Link, useLocation, useParams, useNavigate } from 'react-router-dom'
import WikiBody from '@/components/WikiBody'
import PageTitle from '@/components/common/PageTitle' import PageTitle from '@/components/common/PageTitle'
import MainArea from '@/components/layout/MainArea' import MainArea from '@/components/layout/MainArea'
import { API_BASE_URL, SITE_TITLE } from '@/config' import { API_BASE_URL, SITE_TITLE } from '@/config'
@@ -61,15 +61,9 @@ export default () => {
</div>)} </div>)}
<PageTitle>{title}</PageTitle> <PageTitle>{title}</PageTitle>
<div className="prose mx-auto p-4"> <div className="prose mx-auto p-4">
{wikiPage === undefined ? 'Loading...' : ( {wikiPage === undefined
<> ? 'Loading...'
<ReactMarkdown components={{ a: ( : <WikiBody body={wikiPage?.body || `このページは存在しません。[新規作成してください](/wiki/new?title=${ title })。`} />}
({ href, children }) => (['/', '.'].some (e => href?.startsWith (e))
? <Link to={href!}>{children}</Link>
: <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>)) }}>
{wikiPage?.body || `このページは存在しません。[新規作成してください](/wiki/new?title=${ title })。`}
</ReactMarkdown>
</>)}
</div> </div>
</MainArea>) </MainArea>)
} }