このコミットが含まれているのは:
@@ -1,12 +1,12 @@
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useMemo } from 'react'
|
||||
import { forwardRef, useMemo } from 'react'
|
||||
import { createPath, useNavigate } from 'react-router-dom'
|
||||
|
||||
import { useOverlayStore } from '@/components/RouteBlockerOverlay'
|
||||
import { prefetchForURL } from '@/lib/prefetchers'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import type { AnchorHTMLAttributes, FC, MouseEvent, TouchEvent } from 'react'
|
||||
import type { AnchorHTMLAttributes, MouseEvent, TouchEvent } from 'react'
|
||||
import type { To } from 'react-router-dom'
|
||||
|
||||
type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
@@ -16,14 +16,15 @@ type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
cancelOnError?: boolean }
|
||||
|
||||
|
||||
export default (({ to,
|
||||
replace,
|
||||
className,
|
||||
onMouseEnter,
|
||||
onTouchStart,
|
||||
onClick,
|
||||
cancelOnError = false,
|
||||
...rest }: Props) => {
|
||||
export default forwardRef<HTMLAnchorElement, Props> (({
|
||||
to,
|
||||
replace,
|
||||
className,
|
||||
onMouseEnter,
|
||||
onTouchStart,
|
||||
onClick,
|
||||
cancelOnError = false,
|
||||
...rest }, ref) => {
|
||||
const navigate = useNavigate ()
|
||||
const qc = useQueryClient ()
|
||||
const url = useMemo (() => {
|
||||
@@ -47,12 +48,12 @@ export default (({ to,
|
||||
|
||||
const handleMouseEnter = async (ev: MouseEvent<HTMLAnchorElement>) => {
|
||||
onMouseEnter?.(ev)
|
||||
doPrefetch ()
|
||||
await doPrefetch ()
|
||||
}
|
||||
|
||||
const handleTouchStart = async (ev: TouchEvent<HTMLAnchorElement>) => {
|
||||
onTouchStart?.(ev)
|
||||
doPrefetch ()
|
||||
await doPrefetch ()
|
||||
}
|
||||
|
||||
const handleClick = async (ev: MouseEvent<HTMLAnchorElement>) => {
|
||||
@@ -78,10 +79,11 @@ export default (({ to,
|
||||
}
|
||||
|
||||
return (
|
||||
<a href={typeof to === 'string' ? to : createPath (to)}
|
||||
<a ref={ref}
|
||||
href={typeof to === 'string' ? to : createPath (to)}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onTouchStart={handleTouchStart}
|
||||
onClick={handleClick}
|
||||
className={cn ('cursor-pointer', className)}
|
||||
{...rest}/>)
|
||||
}) satisfies FC<Props>
|
||||
})
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import axios from 'axios'
|
||||
import toCamel from 'camelcase-keys'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { Fragment, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import Separator from '@/components/MenuSeparator'
|
||||
import PrefetchLink from '@/components/PrefetchLink'
|
||||
import TopNavUser from '@/components/TopNavUser'
|
||||
import { API_BASE_URL } from '@/config'
|
||||
import { WikiIdBus } from '@/lib/eventBus/WikiIdBus'
|
||||
import { fetchTagByName } from '@/lib/tags'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { fetchWikiPage } from '@/lib/wiki'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import type { FC, MouseEvent } from 'react'
|
||||
|
||||
import type { Menu, Tag, User, WikiPage } from '@/types'
|
||||
import type { Menu, User } from '@/types'
|
||||
|
||||
type Props = { user: User | null }
|
||||
|
||||
@@ -120,11 +120,8 @@ export default (({ user }: Props) => {
|
||||
const fetchPostCount = async () => {
|
||||
try
|
||||
{
|
||||
const pageRes = await axios.get (`${ API_BASE_URL }/wiki/${ wikiId }`)
|
||||
const wikiPage = toCamel (pageRes.data as any, { deep: true }) as WikiPage
|
||||
|
||||
const tagRes = await axios.get (`${ API_BASE_URL }/tags/name/${ wikiPage.title }`)
|
||||
const tag = toCamel (tagRes.data as any, { deep: true }) as Tag
|
||||
const wikiPage = await fetchWikiPage (String (wikiId ?? ''))
|
||||
const tag = await fetchTagByName (wikiPage.title)
|
||||
|
||||
setPostCount (tag.postCount)
|
||||
}
|
||||
@@ -141,11 +138,11 @@ export default (({ user }: Props) => {
|
||||
<nav className="px-3 flex justify-between items-center w-full min-h-[48px]
|
||||
bg-yellow-200 dark:bg-red-975 md:bg-yellow-50">
|
||||
<div className="flex items-center gap-2 h-full">
|
||||
<Link to="/"
|
||||
<PrefetchLink to="/"
|
||||
className="mx-4 text-xl font-bold text-pink-600 hover:text-pink-400
|
||||
dark:text-pink-300 dark:hover:text-pink-100">
|
||||
ぼざクリ タグ広場
|
||||
</Link>
|
||||
</PrefetchLink>
|
||||
|
||||
<div ref={navRef} className="relative hidden md:flex h-full items-center">
|
||||
<div aria-hidden
|
||||
@@ -157,15 +154,16 @@ export default (({ user }: Props) => {
|
||||
opacity: hl.visible ? 1 : 0 }}/>
|
||||
|
||||
{menu.map ((item, i) => (
|
||||
<Link key={i}
|
||||
to={item.to}
|
||||
ref={el => {
|
||||
itemsRef.current[i] = el
|
||||
}}
|
||||
className={cn ('relative z-10 flex h-full items-center px-5',
|
||||
(i === openItemIdx) && 'font-bold')}>
|
||||
<PrefetchLink
|
||||
key={i}
|
||||
to={item.to}
|
||||
ref={(el: (HTMLAnchorElement | null)) => {
|
||||
itemsRef.current[i] = el
|
||||
}}
|
||||
className={cn ('relative z-10 flex h-full items-center px-5',
|
||||
(i === openItemIdx) && 'font-bold')}>
|
||||
{item.name}
|
||||
</Link>))}
|
||||
</PrefetchLink>))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -203,11 +201,12 @@ export default (({ user }: Props) => {
|
||||
'component' in item
|
||||
? <Fragment key={`c-${ i }`}>{item.component}</Fragment>
|
||||
: (
|
||||
<Link key={`l-${ i }`}
|
||||
to={item.to}
|
||||
className="h-full flex items-center px-3">
|
||||
<PrefetchLink
|
||||
key={`l-${ i }`}
|
||||
to={item.to}
|
||||
className="h-full flex items-center px-3">
|
||||
{item.name}
|
||||
</Link>)))}
|
||||
</PrefetchLink>)))}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
@@ -229,19 +228,20 @@ export default (({ user }: Props) => {
|
||||
<Separator/>
|
||||
{menu.map ((item, i) => (
|
||||
<Fragment key={i}>
|
||||
<Link to={i === openItemIdx ? item.to : '#'}
|
||||
className={cn ('w-full min-h-[40px] flex items-center pl-8',
|
||||
((i === openItemIdx)
|
||||
&& 'font-bold bg-yellow-50 dark:bg-red-950'))}
|
||||
onClick={ev => {
|
||||
if (i !== openItemIdx)
|
||||
{
|
||||
ev.preventDefault ()
|
||||
setOpenItemIdx (i)
|
||||
}
|
||||
}}>
|
||||
<PrefetchLink
|
||||
to={i === openItemIdx ? item.to : '#'}
|
||||
className={cn ('w-full min-h-[40px] flex items-center pl-8',
|
||||
((i === openItemIdx)
|
||||
&& 'font-bold bg-yellow-50 dark:bg-red-950'))}
|
||||
onClick={(ev: MouseEvent<HTMLAnchorElement>) => {
|
||||
if (i !== openItemIdx)
|
||||
{
|
||||
ev.preventDefault ()
|
||||
setOpenItemIdx (i)
|
||||
}
|
||||
}}>
|
||||
{item.name}
|
||||
</Link>
|
||||
</PrefetchLink>
|
||||
|
||||
<AnimatePresence initial={false}>
|
||||
{i === openItemIdx && (
|
||||
@@ -267,11 +267,12 @@ export default (({ user }: Props) => {
|
||||
{subItem.component}
|
||||
</Fragment>)
|
||||
: (
|
||||
<Link key={`sp-l-${ i }-${ j }`}
|
||||
to={subItem.to}
|
||||
className="w-full min-h-[36px] flex items-center pl-12">
|
||||
<PrefetchLink
|
||||
key={`sp-l-${ i }-${ j }`}
|
||||
to={subItem.to}
|
||||
className="w-full min-h-[36px] flex items-center pl-12">
|
||||
{subItem.name}
|
||||
</Link>)))}
|
||||
</PrefetchLink>)))}
|
||||
</motion.div>)}
|
||||
</AnimatePresence>
|
||||
</Fragment>))}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import PrefetchLink from '@/components/PrefetchLink'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
@@ -61,7 +63,7 @@ export default (({ page, totalPages, siblingCount = 4 }) => {
|
||||
<nav className="mt-4 flex justify-center" aria-label="Pagination">
|
||||
<div className="flex items-center gap-2">
|
||||
{(page > 1)
|
||||
? <Link to={buildTo (page - 1)} aria-label="前のページ"><</Link>
|
||||
? <PrefetchLink to={buildTo (page - 1)} aria-label="前のページ"><</PrefetchLink>
|
||||
: <span aria-hidden><</span>}
|
||||
|
||||
{pages.map ((p, idx) => (
|
||||
@@ -69,10 +71,10 @@ export default (({ page, totalPages, siblingCount = 4 }) => {
|
||||
? <span key={`dots-${ idx }`}>…</span>
|
||||
: ((p === page)
|
||||
? <span key={p} className="font-bold" aria-current="page">{p}</span>
|
||||
: <Link key={p} to={buildTo (p)}>{p}</Link>)))}
|
||||
: <PrefetchLink key={p} to={buildTo (p)}>{p}</PrefetchLink>)))}
|
||||
|
||||
{(page < totalPages)
|
||||
? <Link to={buildTo (page + 1)} aria-label="次のページ">></Link>
|
||||
? <PrefetchLink to={buildTo (page + 1)} aria-label="次のページ">></PrefetchLink>
|
||||
: <span aria-hidden>></span>}
|
||||
</div>
|
||||
</nav>)
|
||||
|
||||
新しい課題から参照
ユーザをブロックする