This commit is contained in:
2025-07-21 16:54:30 +09:00
parent 69d111a133
commit 5a4919116d
4 changed files with 92 additions and 129 deletions
+54 -117
View File
@@ -7,41 +7,53 @@ import { API_BASE_URL } from '@/config'
import { WikiIdBus } from '@/lib/eventBus/WikiIdBus' import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import type { Tag, User, WikiPage } from '@/types' import type { Menu, Tag, User, WikiPage } from '@/types'
type Props = { user: User | null } type Props = { user: User | null }
const Menu = { None: 'None',
Post: 'Post',
User: 'User',
Tag: 'Tag',
Wiki: 'Wiki' } as const
type Menu = typeof Menu[keyof typeof Menu]
export default ({ user }: Props) => { export default ({ user }: Props) => {
const location = useLocation () const location = useLocation ()
// const navigate = useNavigate () // const navigate = useNavigate ()
const [selectedMenu, setSelectedMenu] = useState<Menu> (Menu.None)
const [wikiId, setWikiId] = useState<number | null> (WikiIdBus.get ())
// const [wikiSearch, setWikiSearch] = useState ('')
// const [activeIndex, setActiveIndex] = useState (-1) // const [activeIndex, setActiveIndex] = useState (-1)
// const [suggestions, setSuggestions] = useState<WikiPage[]> ([]) const [postCount, setPostCount] = useState<number | null> (null)
// const [suggestionsVsbl, setSuggestionsVsbl] = useState (false) // const [suggestionsVsbl, setSuggestionsVsbl] = useState (false)
// const [suggestions, setSuggestions] = useState<WikiPage[]> ([])
// const [tagSearch, setTagSearch] = useState ('') // const [tagSearch, setTagSearch] = useState ('')
// const [userSearch, setUserSearch] = useState ('') // const [userSearch, setUserSearch] = useState ('')
const [postCount, setPostCount] = useState<number | null> (null) const [wikiId, setWikiId] = useState<number | null> (WikiIdBus.get ())
// const [wikiSearch, setWikiSearch] = useState ('')
const MyLink = ({ to, title, base }: { to: string const wikiPageFlg = Boolean (/^\/wiki\/(?!new|changes)[^\/]+/.test (location.pathname) && wikiId)
title: string const wikiTitle = location.pathname.split ('/')[2]
base?: string }) => ( const menu: Menu = [
<Link to={to} className={cn ('h-full flex items-center', { name: '広場', to: '/posts', subMenu: [
(location.pathname.startsWith (base ?? to) { name: '一覧', to: '/posts' },
? 'bg-yellow-200 dark:bg-red-950 px-4 font-bold' { name: '投稿追加', to: '/posts/new' },
: 'px-2'))}> { name: 'ヘルプ', to: '/wiki/ヘルプ:広場' }] },
{title} { name: 'タグ', to: '/tags', subMenu: [
</Link>) { name: 'タグ一覧', to: '/tags', visible: false },
{ name: '別名タグ', to: '/tags/aliases', visible: false },
{ name: '上位タグ', to: '/tags/implications', visible: false },
{ name: 'ニコニコ連携', to: '/tags/posts' },
{ name: 'タグのつけ方', to: '/wiki/ヘルプ:タグのつけ方' },
{ name: 'ヘルプ', to: '/wiki/ヘルプ:タグ' }] },
{ name: 'Wiki', to: '/wiki/ヘルプ:ホーム', base: '/wiki', subMenu: [
{ name: '検索', to: '/wiki' },
{ name: '新規', to: '/wiki/new' },
{ name: '全体履歴', to: '/wiki/changes' },
{ name: 'ヘルプ', to: '/wiki/ヘルプ:Wiki' },
{ component: <span className="flex items-center px-2">|</span>,
visible: wikiPageFlg },
{ name: `広場 (${ postCount || 0 })`, to: `/posts?tags=${ wikiTitle }`,
visible: wikiPageFlg },
{ name: '履歴', to: `/wiki/changes?id=${ wikiId }`, visible: wikiPageFlg },
{ name: '編輯', to: `/wiki/${ wikiId || wikiTitle }/edit`, visible: wikiPageFlg }] },
{ name: 'ユーザ', to: '/users', subMenu: [
{ name: '一覧', to: '/users', visible: false },
{ name: 'お前', to: `/users/${ user?.id }`, visible: false },
{ name: '設定', to: '/users/settings', visible: Boolean (user) }] }]
// const whenTagSearchChanged = (ev: React.ChangeEvent<HTMLInputElement>) => { // const whenTagSearchChanged = (ev: React.ChangeEvent<HTMLInputElement>) => {
// // TODO: 実装 // // TODO: 実装
@@ -98,19 +110,6 @@ export default ({ user }: Props) => {
return () => unsubscribe () return () => unsubscribe ()
}, []) }, [])
useEffect (() => {
if (location.pathname.startsWith ('/posts'))
setSelectedMenu (Menu.Post)
else if (location.pathname.startsWith ('/users'))
setSelectedMenu (Menu.User)
else if (location.pathname.startsWith ('/tags'))
setSelectedMenu (Menu.Tag)
else if (location.pathname.startsWith ('/wiki'))
setSelectedMenu (Menu.Wiki)
else
setSelectedMenu (Menu.None)
}, [location])
useEffect (() => { useEffect (() => {
if (!(wikiId)) if (!(wikiId))
return return
@@ -144,95 +143,33 @@ export default ({ user }: Props) => {
dark:text-pink-300 dark:hover:text-pink-100"> dark:text-pink-300 dark:hover:text-pink-100">
</Link> </Link>
<MyLink to="/posts" title="広場" /> {menu.map (item => (
<MyLink to="/tags" title="タグ" /> <Link to={item.to}
<MyLink to="/wiki/ヘルプ:ホーム" base="/wiki" title="Wiki" /> className={cn ('h-full flex items-center',
<MyLink to="/users/settings" base="/users" title="ニジラー" /> (location.pathname.startsWith (item.base || item.to)
? 'bg-yellow-200 dark:bg-red-950 px-4 font-bold'
: 'px-2'))}>
{item.name}
</Link>
))}
</div> </div>
{user && {user && (
<div className="ml-auto pr-4"> <div className="ml-auto pr-4">
<Link to="/users/settings" <Link to="/users/settings"
className="font-bold text-red-600 hover:text-red-400 className="font-bold text-red-600 hover:text-red-400
dark:text-yellow-400 dark:hover:text-yellow-200"> dark:text-yellow-400 dark:hover:text-yellow-200">
{user.name || '名もなきニジラー'} {user.name || '名もなきニジラー'}
</Link> </Link>
</div>} </div>)}
</nav> </nav>
{(() => { <div className={cn ('bg-yellow-200 dark:bg-red-950',
const className = cn ('bg-yellow-200 dark:bg-red-950', 'text-white px-3 flex items-center w-full min-h-[40px]')}>
'text-white px-3 flex items-center w-full min-h-[40px]') {menu.find (item => location.pathname.startsWith (item.base || item.to))?.subMenu
const subClass = 'h-full flex items-center px-3' .filter (item => item.visible ?? true)
// const inputBox = 'flex items-center px-3 mx-2' .map (item => 'component' in item ? item.component : (
const Separator = () => <span className="flex items-center px-2">|</span> <Link to={item.to} className="h-full flex items-center px-3">
switch (selectedMenu) {item.name}
{ </Link>))}
case Menu.Post: </div>
return (
<div className={className}>
<Link to="/posts" className={subClass}></Link>
<Link to="/posts/new" className={subClass}>稿</Link>
<Link to="/wiki/ヘルプ:広場" className={subClass}></Link>
</div>)
case Menu.Tag:
return (
<div className={className}>
{/* TODO: リリース後にやる */}
{/* <input type="text"
className={inputBox}
placeholder="タグ検索"
value={tagSearch}
onChange={whenTagSearchChanged}
onFocus={() => setSuggestionsVsbl (true)}
onBlur={() => setSuggestionsVsbl (false)}
onKeyDown={handleKeyDown} /> */}
{/* <Link to="/tags" className={subClass}>タグ</Link> */}
{/* <Link to="/tags/aliases" className={subClass}>別名タグ</Link>
<Link to="/tags/implications" className={subClass}>上位タグ</Link> */}
<Link to="/tags/nico" className={subClass}></Link>
<Link to="/wiki/ヘルプ:タグのつけ方" className={subClass}></Link>
<Link to="/wiki/ヘルプ:タグ" className={subClass}></Link>
</div>)
case Menu.Wiki:
return (
<div className={className}>
{/* TODO: リリース後にやる */}
{/* <input type="text"
className={inputBox}
placeholder="Wiki 検索"
value={wikiSearch}
onChange={whenWikiSearchChanged}
onFocus={() => setSuggestionsVsbl (true)}
onBlur={() => setSuggestionsVsbl (false)}
onKeyDown={handleKeyDown} /> */}
<Link to="/wiki" className={subClass}></Link>
<Link to="/wiki/new" className={subClass}></Link>
<Link to="/wiki/changes" className={subClass}></Link>
<Link to="/wiki/ヘルプ:Wiki" className={subClass}></Link>
{(/^\/wiki\/(?!new|changes)[^\/]+/.test (location.pathname) && wikiId) &&
<>
<Separator />
<Link to={`/posts?tags=${ location.pathname.split ('/')[2] }`} className={subClass}> ({postCount || 0})</Link>
<Link to={`/wiki/changes?id=${ wikiId }`} className={subClass}></Link>
<Link to={`/wiki/${ wikiId || location.pathname.split ('/')[2] }/edit`} className={subClass}></Link>
</>}
</div>)
case Menu.User:
return (
<div className={className}>
{/* TODO: リリース後にやる */}
{/* <input type="text"
className={inputBox}
placeholder="ニジラー検索"
value={userSearch}
onChange={whenUserSearchChanged}
onFocus={() => setSuggestionsVsbl (true)}
onBlur={() => setSuggestionsVsbl (false)}
onKeyDown={handleKeyDown} /> */}
{/* <Link to="/users" className={subClass}>一覧</Link>
{user && <Link to={`/users/${ user.id }`} className={subClass}>お前</Link>} */}
{user && <Link to="/users/settings" className={subClass}></Link>}
</div>)
}
}) ()}
</>) </>)
} }
+5 -1
View File
@@ -136,7 +136,11 @@ export default ({ user }: Props) => {
handleEdit (tag.id) handleEdit (tag.id)
}}> }}>
{editing[tag.id] {editing[tag.id]
? <span className="text-red-400"></span> ? (
<span className="text-red-600 hover:text-red-400
dark:text-red-300 dark:hover:text-red-100">
</span>)
: <span></span>} : <span></span>}
</a> </a>
</td>)} </td>)}
+15 -11
View File
@@ -7,6 +7,7 @@ import { useLocation, useParams } from 'react-router-dom'
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'
import { cn } from '@/lib/utils'
import type { WikiPageDiff } from '@/types' import type { WikiPageDiff } from '@/types'
@@ -31,16 +32,19 @@ export default () => {
return ( return (
<MainArea> <MainArea>
<Helmet> <Helmet>
<title>{`Wiki 差分: ${ diff?.title } | ${ SITE_TITLE }`}</title> <title>{`Wiki 差分: ${ diff?.title } | ${ SITE_TITLE }`}</title>
</Helmet> </Helmet>
<PageTitle>{diff?.title}</PageTitle> <PageTitle>{diff?.title}</PageTitle>
<div className="prose mx-auto p-4"> <div className="prose mx-auto p-4">
{diff ? ( {diff
diff.diff.map (d => ( ? (
<span className={d.type === 'added' ? 'bg-green-800' : d.type === 'removed' ? 'bg-red-800' : ''}> diff.diff.map (d => (
{d.content == '\n' ? <br /> : d.content} <span className={cn (d.type === 'added' && 'bg-green-200 dark:bg-green-800',
</span>))) : 'Loading...'} d.type === 'removed' && 'bg-red-200 dark:bg-red-800')}>
</div> {d.content == '\n' ? <br /> : d.content}
</span>)))
: 'Loading...'}
</div>
</MainArea>) </MainArea>)
} }
+18
View File
@@ -1,7 +1,17 @@
import React from 'react'
import { CATEGORIES, USER_ROLES, ViewFlagBehavior } from '@/consts' import { CATEGORIES, USER_ROLES, ViewFlagBehavior } from '@/consts'
export type Category = typeof CATEGORIES[number] export type Category = typeof CATEGORIES[number]
export type Menu = MenuItem[]
export type MenuItem = {
name: string
to: string
base?: string
subMenu: SubMenuItem[] }
export type NicoTag = Tag & { export type NicoTag = Tag & {
category: 'nico' category: 'nico'
linkedTags: Tag[] } linkedTags: Tag[] }
@@ -15,6 +25,14 @@ export type Post = {
tags: Tag[] tags: Tag[]
viewed: boolean } viewed: boolean }
export type SubMenuItem = {
component: React.ReactNode
visible: boolean
} | {
name: string
to: string
visible?: boolean }
export type Tag = { export type Tag = {
id: number id: number
name: string name: string