This commit is contained in:
2025-07-08 02:40:49 +09:00
parent 9c1efbf047
commit 57070ed49b
4 changed files with 131 additions and 116 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ export default () => {
if (data.valid) if (data.valid)
setUser (toCamel (data.user, { deep: true })) setUser (toCamel (data.user, { deep: true }))
else else
createUser () await createUser ()
}) () }) ()
} }
else else
+117 -109
View File
@@ -10,14 +10,14 @@ import { cn } from '@/lib/utils'
import type { Tag, User, WikiPage } from '@/types' import type { Tag, User, WikiPage } from '@/types'
type Props = { user: User type Props = { user: User
setUser: (user: User) => void } setUser: (user: User) => void }
const enum Menu { None, const enum Menu { None,
Post, Post,
User, User,
Tag, Tag,
Wiki } Wiki }
const TopNav: React.FC = ({ user, setUser }: Props) => { const TopNav: React.FC = ({ user, setUser }: Props) => {
@@ -35,14 +35,14 @@ const TopNav: React.FC = ({ user, setUser }: Props) => {
const [postCount, setPostCount] = useState<number | null> (null) const [postCount, setPostCount] = useState<number | null> (null)
const MyLink = ({ to, title, menu, base }: { to: string const MyLink = ({ to, title, menu, base }: { to: string
title: string title: string
menu?: Menu menu?: Menu
base?: string }) => ( base?: string }) => (
<Link to={to} className={cn ('hover:text-orange-500 h-full flex items-center', <Link to={to} className={cn ('hover:text-orange-500 h-full flex items-center',
(location.pathname.startsWith (base ?? to) (location.pathname.startsWith (base ?? to)
? 'bg-gray-700 px-4 font-bold' ? 'bg-gray-700 px-4 font-bold'
: 'px-2'))}> : 'px-2'))}>
{title} {title}
</Link>) </Link>)
const whenTagSearchChanged = ev => { const whenTagSearchChanged = ev => {
@@ -53,8 +53,8 @@ const TopNav: React.FC = ({ user, setUser }: Props) => {
const q: string = ev.target.value.split (' ').at (-1) const q: string = ev.target.value.split (' ').at (-1)
if (!(q)) if (!(q))
{ {
setSuggestions ([]) setSuggestions ([])
return return
} }
} }
@@ -66,8 +66,8 @@ const TopNav: React.FC = ({ user, setUser }: Props) => {
const q: string = ev.target.value.split (' ').at (-1) const q: string = ev.target.value.split (' ').at (-1)
if (!(q)) if (!(q))
{ {
setSuggestions ([]) setSuggestions ([])
return return
} }
} }
@@ -79,16 +79,16 @@ const TopNav: React.FC = ({ user, setUser }: Props) => {
const q: string = ev.target.value.split (' ').at (-1) const q: string = ev.target.value.split (' ').at (-1)
if (!(q)) if (!(q))
{ {
setSuggestions ([]) setSuggestions ([])
return return
} }
} }
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' && wikiSearch.length && (!(suggestionsVsbl) || activeIndex < 0)) if (e.key === 'Enter' && wikiSearch.length && (!(suggestionsVsbl) || activeIndex < 0))
{ {
navigate (`/wiki/${ encodeURIComponent (wikiSearch) }`) navigate (`/wiki/${ encodeURIComponent (wikiSearch) }`)
setSuggestionsVsbl (false) setSuggestionsVsbl (false)
} }
} }
@@ -120,105 +120,113 @@ const TopNav: React.FC = ({ user, setUser }: Props) => {
void ((async () => { void ((async () => {
try try
{ {
const { data: pageData } = await axios.get (`${ API_BASE_URL }/wiki/${ wikiId }`) const { data: pageData } = await axios.get (`${ API_BASE_URL }/wiki/${ wikiId }`)
const wikiPage: WikiPage = toCamel (pageData, { deep: true }) const wikiPage: WikiPage = toCamel (pageData, { deep: true })
const { data: tagData } = await axios.get (`${ API_BASE_URL }/tags/name/${ wikiPage.title }`) const { data: tagData } = await axios.get (`${ API_BASE_URL }/tags/name/${ wikiPage.title }`)
const tag: Tag = toCamel (tagData, { deep: true }) const tag: Tag = toCamel (tagData, { deep: true })
setPostCount (tag.postCount) setPostCount (tag.postCount)
} }
catch catch
{ {
setPostCount (0) setPostCount (0)
} }
}) ()) }) ())
}, [wikiId]) }, [wikiId])
return ( return (
<> <>
<nav className="bg-gray-800 text-white px-3 flex justify-between items-center w-full min-h-[48px]"> <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"> <div className="flex items-center gap-2 h-full">
<Link to="/posts" className="mx-4 text-xl font-bold text-orange-500"> </Link> <Link to="/posts" className="mx-4 text-xl font-bold text-orange-500"> </Link>
<MyLink to="/posts" title="広場" /> <MyLink to="/posts" title="広場" />
<MyLink to="/tags" title="タグ" /> <MyLink to="/tags" title="タグ" />
<MyLink to="/wiki/ヘルプ:ホーム" base="/wiki" title="Wiki" /> <MyLink to="/wiki/ヘルプ:ホーム" base="/wiki" title="Wiki" />
<MyLink to="/users" title="ニジラー" /> <MyLink to="/users/settings" base="/users" title="ニジラー" />
</div> </div>
<div className="ml-auto pr-4"> <div className="ml-auto pr-4">
<Button onClick={() => navigate ('/users/settings')}>{user?.name || '名もなきニジラー'}</Button> {user && (
</div> <Button onClick={() => navigate ('/users/settings')}
</nav> className="bg-gray-600">
{(() => { {user.name || '名もなきニジラー'}
const className = 'bg-gray-700 text-white px-3 flex items-center w-full min-h-[40px]' </Button>)}
const subClass = 'hover:text-orange-500 h-full flex items-center px-3' </div>
const inputBox = 'flex items-center px-3 mx-2' </nav>
const Separator = () => <span className="flex items-center px-2">|</span> {(() => {
switch (selectedMenu) 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'
case Menu.Post: const inputBox = 'flex items-center px-3 mx-2'
return ( const Separator = () => <span className="flex items-center px-2">|</span>
<div className={className}> switch (selectedMenu)
<Link to="/posts" className={subClass}></Link> {
<Link to="/posts/new" className={subClass}>稿</Link> case Menu.Post:
<Link to="/wiki/ヘルプ:広場" className={subClass}></Link> return (
</div>) <div className={className}>
case Menu.Tag: <Link to="/posts" className={subClass}></Link>
return ( <Link to="/posts/new" className={subClass}>稿</Link>
<div className={className}> <Link to="/wiki/ヘルプ:広場" className={subClass}></Link>
<input type="text" </div>)
className={inputBox} case Menu.Tag:
placeholder="タグ検索" return (
value={tagSearch} <div className={className}>
onChange={whenTagSearchChanged} {/* TODO: リリース後にやる */}
onFocus={() => setSuggestionsVsbl (true)} {/* <input type="text"
onBlur={() => setSuggestionsVsbl (false)} className={inputBox}
onKeyDown={handleKeyDown} /> placeholder="タグ検索"
<Link to="/tags" className={subClass}></Link> value={tagSearch}
<Link to="/tags/aliases" className={subClass}></Link> onChange={whenTagSearchChanged}
<Link to="/tags/implications" className={subClass}></Link> onFocus={() => setSuggestionsVsbl (true)}
<Link to="/wiki/ヘルプ:タグのつけ方" className={subClass}></Link> onBlur={() => setSuggestionsVsbl (false)}
<Link to="/wiki/ヘルプ:タグ" className={subClass}></Link> onKeyDown={handleKeyDown} /> */}
</div>) <Link to="/tags" className={subClass}></Link>
case Menu.Wiki: <Link to="/tags/aliases" className={subClass}></Link>
return ( <Link to="/tags/implications" className={subClass}></Link>
<div className={className}> <Link to="/wiki/ヘルプ:タグのつけ方" className={subClass}></Link>
<input type="text" <Link to="/wiki/ヘルプ:タグ" className={subClass}></Link>
className={inputBox} </div>)
placeholder="Wiki 検索" case Menu.Wiki:
value={wikiSearch} return (
onChange={whenWikiSearchChanged} <div className={className}>
onFocus={() => setSuggestionsVsbl (true)} {/* TODO: リリース後にやる */}
onBlur={() => setSuggestionsVsbl (false)} {/* <input type="text"
onKeyDown={handleKeyDown} /> className={inputBox}
<Link to="/wiki" className={subClass}></Link> placeholder="Wiki 検索"
<Link to="/wiki/new" className={subClass}></Link> value={wikiSearch}
<Link to="/wiki/changes" className={subClass}></Link> onChange={whenWikiSearchChanged}
<Link to="/wiki/ヘルプ:Wiki" className={subClass}></Link> onFocus={() => setSuggestionsVsbl (true)}
{(/^\/wiki\/(?!new|changes)[^\/]+/.test (location.pathname) && wikiId) && onBlur={() => setSuggestionsVsbl (false)}
<> onKeyDown={handleKeyDown} /> */}
<Separator /> <Link to="/wiki" className={subClass}></Link>
<Link to={`/posts?tags=${ location.pathname.split ('/')[2] }`} className={subClass}> ({postCount || 0})</Link> <Link to="/wiki/new" className={subClass}></Link>
<Link to={`/wiki/changes?id=${ wikiId }`} className={subClass}></Link> <Link to="/wiki/changes" className={subClass}></Link>
<Link to={`/wiki/${ wikiId || location.pathname.split ('/')[2] }/edit`} className={subClass}></Link> <Link to="/wiki/ヘルプ:Wiki" className={subClass}></Link>
</>} {(/^\/wiki\/(?!new|changes)[^\/]+/.test (location.pathname) && wikiId) &&
</div>) <>
case Menu.User: <Separator />
return ( <Link to={`/posts?tags=${ location.pathname.split ('/')[2] }`} className={subClass}> ({postCount || 0})</Link>
<div className={className}> <Link to={`/wiki/changes?id=${ wikiId }`} className={subClass}></Link>
<input type="text" <Link to={`/wiki/${ wikiId || location.pathname.split ('/')[2] }/edit`} className={subClass}></Link>
className={inputBox} </>}
placeholder="ニジラー検索" </div>)
value={userSearch} case Menu.User:
onChange={whenUserSearchChanged} return (
onFocus={() => setSuggestionsVsbl (true)} <div className={className}>
onBlur={() => setSuggestionsVsbl (false)} {/* TODO: リリース後にやる */}
onKeyDown={handleKeyDown} /> {/* <input type="text"
<Link to="/users" className={subClass}></Link> className={inputBox}
{user && <Link to={`/users/${ user.id }`} className={subClass}></Link>} placeholder="ニジラー検索"
</div>) 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>)
}
}) ()}
</>) </>)
} }
@@ -19,7 +19,7 @@ type Props = { visible: boolean
export default ({ visible, onVisibleChange, user, setUser }: Props) => { export default ({ visible, onVisibleChange, user, setUser }: Props) => {
const handleChange = async () => { const handleChange = async () => {
if (!(confirm ('引継ぎコードを再発行しますか?'))) if (!(confirm ('引継ぎコードを再発行しますか?\n再発行するとほかのブラウザからはログアウトされます.')))
return return
const { data } = await axios.post (`${ API_BASE_URL }/users/code/renew`, { }, { headers: { const { data } = await axios.post (`${ API_BASE_URL }/users/code/renew`, { }, { headers: {
+12 -5
View File
@@ -1,3 +1,5 @@
import axios from 'axios'
import toCamel from 'camelcase-keys'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
@@ -7,8 +9,9 @@ import PageTitle from '@/components/common/PageTitle'
import MainArea from '@/components/layout/MainArea' import MainArea from '@/components/layout/MainArea'
import InheritDialogue from '@/components/users/InheritDialogue' import InheritDialogue from '@/components/users/InheritDialogue'
import UserCodeDialogue from '@/components/users/UserCodeDialogue' import UserCodeDialogue from '@/components/users/UserCodeDialogue'
import { API_BASE_URL, SITE_TITLE } from '@/config'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast'
import { API_BASE_URL, SITE_TITLE } from '@/config'
import type { User } from '@/types' import type { User } from '@/types'
@@ -22,14 +25,18 @@ export default ({ user, setUser }: Props) => {
const [inheritVsbl, setInheritVsbl] = useState (false) const [inheritVsbl, setInheritVsbl] = useState (false)
const handleSubmit = async () => { const handleSubmit = async () => {
const formData = new FormData () if (!(user))
return
const formData = new FormData
formData.append ('name', name) formData.append ('name', name)
try try
{ {
await axios.post (`${ API_BASE_URL }/users`, formData, { headers: { const { data } = await axios.put (`${ API_BASE_URL }/users/${ user.id }`, formData, {
'Content-Type': 'multipart/form-data', headers: { 'Content-Type': 'multipart/form-data',
'X-Transfer-Code': localStorage.getItem ('user_code') || '' } }) 'X-Transfer-Code': localStorage.getItem ('user_code') || '' } })
setUser (user => ({ ...user, ...data }))
toast ({ title: '設定を更新しました.' }) toast ({ title: '設定を更新しました.' })
} }
catch catch