@@ -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>)
|
||||
}
|
||||
@@ -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>)
|
||||
Reference in New Issue
Block a user