This commit is contained in:
2025-06-13 01:36:53 +09:00
parent 3363fcd2ae
commit 32ed235807
11 changed files with 327 additions and 259 deletions
@@ -0,0 +1,60 @@
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import { Link, useParams } from 'react-router-dom'
import { API_BASE_URL } from '@/config'
import TagSearch from './TagSearch'
import SidebarComponent from './layout/SidebarComponent'
import type { Post, Tag } from '@/types'
type TagByCategory = { [key: string]: Tag[] }
type Props = { post: Post | null }
export default ({ post }: Props) => {
const [tags, setTags] = useState<TagByCategory> ({ })
const categoryNames: { [key: string]: string } = {
general: '一般',
deerjikist: 'ニジラー',
nico: 'ニコニコタグ' }
useEffect (() => {
if (!(post))
return
const fetchTags = async () => {
const tagsTmp: TagByCategory = { }
for (const tag of post.tags)
{
if (!(tag.category in tagsTmp))
tagsTmp[tag.category] = []
tagsTmp[tag.category].push (tag)
}
for (const cat of Object.keys (tagsTmp))
tagsTmp[cat].sort ((tagA, tagB) => tagA.name < tagB.name ? -1 : 1)
setTags (tagsTmp)
}
fetchTags ()
}, [post])
return (
<SidebarComponent>
<TagSearch />
{['general', 'deerjikist', 'nico'].map (cat => cat in tags && (
<>
<h2>{categoryNames[cat]}</h2>
<ul>
{tags[cat].map (tag => (
<li key={tag.id} className="mb-2">
<Link to={`/posts?${ (new URLSearchParams ({ tags: tag.name })).toString () }`}
className="text-blue-600 hover:underline">
{tag.name}
</Link>
</li>))}
</ul>
</>))}
</SidebarComponent>)
}
+23 -36
View File
@@ -1,15 +1,15 @@
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import { Link, useParams } from 'react-router-dom'
import { API_BASE_URL } from '../config'
import { API_BASE_URL } from '@/config'
import TagSearch from './TagSearch'
import SidebarComponent from './layout/SidebarComponent'
import type { Post, Tag } from '@/types'
type TagByCategory = { [key: string]: Tag[] }
type Props = { posts: Post[]
setPosts: (posts: Post[]) => void }
type Props = { posts: Post[] }
const tagNameMap: { [key: string]: string } = {
@@ -17,46 +17,35 @@ const tagNameMap: { [key: string]: string } = {
deerjikist: 'ニジラー',
nico: 'ニコニコタグ' }
const TagSidebar: React.FC = (props: Props) => {
const { posts, setPosts } = props
export default ({ posts }: Props) => {
const [tags, setTags] = useState<TagByCategory> ({ })
const [tagsCounts, setTagsCounts] = useState<{ [key: id]: number }> ({ })
const [tagsCounts, setTagsCounts] = useState<{ [key: number]: number }> ({ })
useEffect (() => {
const fetchTags = async () => {
try
const tagsTmp: TagByCategory = { }
const tagsCountsTmp: { [key: number]: number } = { }
for (const post of posts)
{
let tagsTmp: TagByCategory = { }
let tagsCountsTmp: { [key: id]: number } = { }
for (const post of posts)
for (const tag of post.tags)
{
for (const tag of post.tags)
{
if (!(tag.category in tagsTmp))
tagsTmp[tag.category] = []
tagsTmp[tag.category].push (tag)
if (!(tag.id in tagsCountsTmp))
tagsCountsTmp[tag.id] = 0
++tagsCountsTmp[tag.id]
}
if (!(tag.category in tagsTmp))
tagsTmp[tag.category] = []
if (!(tagsTmp[tag.category].map (t => t.id).includes (tag.id)))
tagsTmp[tag.category].push (tag)
if (!(tag.id in tagsCountsTmp))
tagsCountsTmp[tag.id] = 0
++tagsCountsTmp[tag.id]
}
for (const cat of Object.keys (tagsTmp))
tagsTmp[cat].sort ((tagA, tagB) => tagA.name < tagB.name ? -1 : 1)
setTags (tagsTmp)
setTagsCounts (tagsCountsTmp)
}
catch (error)
{
console.error ('Failed to fetch tags:', error)
}
}
fetchTags ()
for (const cat of Object.keys (tagsTmp))
tagsTmp[cat].sort ((tagA, tagB) => tagA.name < tagB.name ? -1 : 1)
setTags (tagsTmp)
setTagsCounts (tagsCountsTmp)
}, [posts])
return (
<div className="w-64 bg-gray-100 p-4 border-r border-gray-200 h-full">
<SidebarComponent>
<TagSearch />
{['general', 'deerjikist', 'nico'].map (cat => cat in tags && <>
<h2>{tagNameMap[cat]}</h2>
@@ -67,11 +56,9 @@ const TagSidebar: React.FC = (props: Props) => {
className="text-blue-600 hover:underline">
{tag.name}
</Link>
{posts.length > 1 && <span className="ml-1">{tagsCounts[tag.id]}</span>}
<span className="ml-1">{tagsCounts[tag.id]}</span>
</li>))}
</ul>
</>)}
</div>)
</SidebarComponent>)
}
export default TagSidebar
@@ -0,0 +1,9 @@
import React from 'react'
type Props = { children: React.ReactNode }
export default ({ children }: Props) => (
<main className="flex-1 overflow-y-auto p-4">
{children}
</main>)
@@ -0,0 +1,9 @@
import React from 'react'
type Props = { children: React.ReactNode }
export default ({ children }: Props) => (
<div className="w-64 bg-gray-100 p-4 border-r border-gray-200 h-full">
{children}
</div>)