|
- import axios from 'axios'
- import toCamel from 'camelcase-keys'
- import React, { useState, useEffect } from 'react'
- import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'
-
- import SettingsDialogue from '@/components/SettingsDialogue'
- import { Button } from '@/components/ui/button'
- import { API_BASE_URL } from '@/config'
- import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
- import { cn } from '@/lib/utils'
-
- import type { Tag, User, WikiPage } from '@/types'
-
- type Props = { user: User
- setUser: (user: User) => void }
-
- const enum Menu { None,
- Post,
- User,
- Tag,
- Wiki }
-
-
- const TopNav: React.FC = ({ user, setUser }: Props) => {
- const location = useLocation ()
- const navigate = useNavigate ()
-
- const [settingsVsbl, setSettingsVsbl] = useState (false)
- 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 [suggestions, setSuggestions] = useState<WikiPage[]> ([])
- const [suggestionsVsbl, setSuggestionsVsbl] = useState (false)
- const [tagSearch, setTagSearch] = useState ('')
- const [userSearch, setUserSearch] = useState ('')
- const [postCount, setPostCount] = useState<number | null> (null)
-
- const MyLink = ({ to, title, menu, base }: { to: string
- title: string
- menu?: Menu
- base?: string }) => (
- <Link to={to} className={cn ('hover:text-orange-500 h-full flex items-center',
- (location.pathname.startsWith (base ?? to)
- ? 'bg-gray-700 px-4 font-bold'
- : 'px-2'))}>
- {title}
- </Link>)
-
- const whenTagSearchChanged = ev => {
- // TODO: 実装
-
- setTagSearch (ev.target.value)
-
- const q: string = ev.target.value.split (' ').at (-1)
- if (!(q))
- {
- setSuggestions ([])
- return
- }
- }
-
- const whenWikiSearchChanged = ev => {
- // TODO: 実装
-
- setWikiSearch (ev.target.value)
-
- const q: string = ev.target.value.split (' ').at (-1)
- if (!(q))
- {
- setSuggestions ([])
- return
- }
- }
-
- const whenUserSearchChanged = ev => {
- // TODO: 実装
-
- setUserSearch (ev.target.value)
-
- const q: string = ev.target.value.split (' ').at (-1)
- if (!(q))
- {
- setSuggestions ([])
- return
- }
- }
-
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
- if (e.key === 'Enter' && wikiSearch.length && (!(suggestionsVsbl) || activeIndex < 0))
- {
- navigate (`/wiki/${ encodeURIComponent (wikiSearch) }`)
- setSuggestionsVsbl (false)
- }
- }
-
- const handleTagSelect = (tag: Tag) => {
- }
-
- useEffect (() => {
- const unsubscribe = WikiIdBus.subscribe (setWikiId)
- 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 (() => {
- if (!(wikiId))
- return
-
- void ((async () => {
- try
- {
- const { data: pageData } = await axios.get (`${ API_BASE_URL }/wiki/${ wikiId }`)
- const wikiPage: WikiPage = toCamel (pageData, { deep: true })
-
- const { data: tagData } = await axios.get (`${ API_BASE_URL }/tags/name/${ wikiPage.title }`)
- const tag: Tag = toCamel (tagData, { deep: true })
-
- setPostCount (tag.postCount)
- }
- catch
- {
- setPostCount (0)
- }
- }) ())
- }, [wikiId])
-
- return (
- <>
- <nav className="bg-gray-800 text-white px-3 flex justify-between items-center w-full min-h-[48px]">
- <div className="flex items-center gap-2 h-full">
- <Link to="/posts" className="mx-4 text-xl font-bold text-orange-500">ぼざクリ タグ広場</Link>
- <MyLink to="/posts" title="広場" />
- <MyLink to="/tags" title="タグ" />
- <MyLink to="/wiki/ヘルプ:ホーム" base="/wiki" title="Wiki" />
- <MyLink to="/users" title="ニジラー" />
- </div>
- <div className="ml-auto pr-4">
- <Button onClick={() => setSettingsVsbl (true)}>{user?.name || '名もなきニジラー'}</Button>
- <SettingsDialogue visible={settingsVsbl}
- onVisibleChange={setSettingsVsbl}
- user={user}
- setUser={setUser} />
- </div>
- </nav>
- {(() => {
- const className = 'bg-gray-700 text-white px-3 flex items-center w-full min-h-[40px]'
- const subClass = 'hover:text-orange-500 h-full flex items-center px-3'
- const inputBox = 'flex items-center px-3 mx-2'
- const Separator = () => <span className="flex items-center px-2">|</span>
- switch (selectedMenu)
- {
- case Menu.Post:
- 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}>
- <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="/wiki/ヘルプ:タグのつけ方" className={subClass}>タグのつけ方</Link>
- <Link to="/wiki/ヘルプ:タグ" className={subClass}>ヘルプ</Link>
- </div>)
- case Menu.Wiki:
- return (
- <div className={className}>
- <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}>
- <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>}
- </div>)
- }
- }) ()}
- </>)
- }
-
-
- export default TopNav
|