このコミットが含まれているのは:
@@ -139,6 +139,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
const navRef = useRef<HTMLDivElement | null> (null)
|
||||
const layoutRef = useRef<HTMLDivElement | null> (null)
|
||||
const barRef = useRef<HTMLElement | null> (null)
|
||||
const submenuContentRef = useRef<HTMLDivElement | null> (null)
|
||||
|
||||
const measure = (idx: number) => {
|
||||
const nav = navRef.current
|
||||
@@ -167,6 +168,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
const [density, setDensity] = useState<NavDensity> ('auto')
|
||||
const [moreVsbl, setMoreVsbl] = useState (false)
|
||||
const [openItemIdx, setOpenItemIdx] = useState (-1)
|
||||
const [submenuHeight, setSubmenuHeight] = useState (0)
|
||||
const [wikiId, setWikiId] = useState<number | null> (WikiIdBus.get ())
|
||||
|
||||
const wikiIdStr = String (wikiId ?? '')
|
||||
@@ -201,7 +203,6 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
|| item.subMenu.filter (subItem => subItem.visible ?? true).length > 0)
|
||||
const activeIdx =
|
||||
visibleMenu.findIndex (item => pathname.startsWith (item.base || item.to))
|
||||
const submenuHeight = moreVsbl ? 40 * moreMenu.length : (activeIdx < 0 ? 0 : 40)
|
||||
const topNavTransition =
|
||||
animationsOff
|
||||
? { duration: 0 }
|
||||
@@ -260,11 +261,16 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
{
|
||||
layout.setAttribute ('data-density', candidate)
|
||||
const style = getComputedStyle (bar)
|
||||
const required = primary.getBoundingClientRect ().width
|
||||
+ (account?.getBoundingClientRect ().width ?? 0)
|
||||
const primaryWidth = Math.max (
|
||||
primary.getBoundingClientRect ().width, primary.scrollWidth)
|
||||
const accountWidth =
|
||||
account == null
|
||||
? 0
|
||||
: Math.max (account.getBoundingClientRect ().width, account.scrollWidth)
|
||||
const required = primaryWidth + accountWidth
|
||||
+ parseFloat (style.paddingLeft) + parseFloat (style.paddingRight)
|
||||
+ (account == null ? 0 : parseFloat (style.columnGap))
|
||||
if (required <= bar.clientWidth)
|
||||
if (Math.ceil (required) <= bar.clientWidth)
|
||||
return candidate
|
||||
}
|
||||
return null
|
||||
@@ -313,6 +319,26 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
return () => unsubscribe ()
|
||||
}, [])
|
||||
|
||||
useLayoutEffect (() => {
|
||||
const content = submenuContentRef.current
|
||||
if (content == null)
|
||||
return
|
||||
|
||||
const update = () => {
|
||||
setSubmenuHeight (Math.ceil (content.getBoundingClientRect ().height))
|
||||
}
|
||||
const observer =
|
||||
typeof ResizeObserver === 'undefined' ? null : new ResizeObserver (update)
|
||||
observer?.observe (content)
|
||||
update ()
|
||||
addEventListener ('resize', update)
|
||||
|
||||
return () => {
|
||||
observer?.disconnect ()
|
||||
removeEventListener ('resize', update)
|
||||
}
|
||||
}, [activeIdx, moreVsbl, desktop, density, locale])
|
||||
|
||||
useEffect (() => {
|
||||
setMenuOpen (false)
|
||||
setOpenItemIdx (activeIdx)
|
||||
@@ -447,12 +473,11 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
onAnimationComplete={() => {
|
||||
measure (moreVsbl ? -1 : activeIdx)
|
||||
}}>
|
||||
<div ref={submenuContentRef} className={cn (moreVsbl && 'top-nav-more-menu')}>
|
||||
{moreVsbl
|
||||
? (
|
||||
moreMenu.map ((item, i) => (
|
||||
<div key={i} className="relative h-[40px]">
|
||||
<div className="absolute inset-0 flex items-center px-3
|
||||
overflow-x-auto whitespace-nowrap">
|
||||
<div key={i} className="contents">
|
||||
<motion.div
|
||||
transition={topNavTransition}
|
||||
{...(animationsOff
|
||||
@@ -462,13 +487,14 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
: { initial: { x: 40, y: -40, opacity: 0 },
|
||||
animate: { x: 0, y: 0, opacity: 1 },
|
||||
exit: { x: 40, y: -40, opacity: 0 } }))}
|
||||
className="z-10 h-full flex shrink-0 items-center px-3 font-bold w-28">
|
||||
className="z-10 min-w-0 px-3 py-2 font-bold">
|
||||
<h2>
|
||||
<LocalisedText language={item.nameLanguage ?? 'ja'}>
|
||||
{item.name}
|
||||
</LocalisedText>
|
||||
</h2>
|
||||
</motion.div>
|
||||
<div className="top-nav-more-links flex min-w-0 flex-wrap items-center">
|
||||
{item.subMenu
|
||||
.filter (subItem => subItem.visible ?? true)
|
||||
.map ((subItem, j) => (
|
||||
@@ -476,6 +502,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
? (
|
||||
<motion.div
|
||||
key={`c-${ i }-${ j }`}
|
||||
className="min-w-0 max-w-full"
|
||||
transition={topNavTransition}
|
||||
{...(animationsOff
|
||||
? { }
|
||||
@@ -490,6 +517,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
: (
|
||||
<motion.div
|
||||
key={`l-${ i }-${ j }`}
|
||||
className="min-w-0 max-w-full"
|
||||
transition={topNavTransition}
|
||||
{...(animationsOff
|
||||
? { }
|
||||
@@ -503,7 +531,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
to={subItem.to}
|
||||
target={subItem.to.slice (0, 2) === '//' ? '_blank' : undefined}
|
||||
onClick={() => setMoreVsbl (false)}
|
||||
className="top-nav-menu-link h-full flex items-center px-3">
|
||||
className="top-nav-menu-link flex min-h-[40px] items-center px-3 py-2">
|
||||
<LocalisedText language={subItem.nameLanguage ?? 'ja'}>
|
||||
{subItem.name}
|
||||
</LocalisedText>
|
||||
@@ -513,27 +541,27 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
</div>)))
|
||||
: ((visibleMenu[activeIdx]?.subMenu ?? []).length > 0
|
||||
&& (
|
||||
<div className="relative h-[40px]">
|
||||
<div className="relative min-h-[40px]">
|
||||
{animationsOff
|
||||
? (
|
||||
<div className="absolute inset-0 flex items-center px-3
|
||||
overflow-x-auto whitespace-nowrap">
|
||||
<div className="flex min-h-[40px] flex-wrap items-center px-3">
|
||||
{(visibleMenu[activeIdx]?.subMenu ?? [])
|
||||
.filter (item => item.visible ?? true)
|
||||
.map ((item, i) => (
|
||||
'component' in item
|
||||
? (
|
||||
<div key={`c-${ i }`}>
|
||||
<div key={`c-${ i }`} className="min-w-0 max-w-full">
|
||||
{item.component}
|
||||
</div>)
|
||||
: (
|
||||
<div key={`l-${ i }`}>
|
||||
<div key={`l-${ i }`} className="min-w-0 max-w-full">
|
||||
<PrefetchLink
|
||||
to={item.to}
|
||||
target={item.to.slice (0, 2) === '//'
|
||||
? '_blank'
|
||||
: undefined}
|
||||
className="top-nav-menu-link h-full flex items-center px-3">
|
||||
className="top-nav-menu-link flex min-h-[40px]
|
||||
items-center px-3 py-2">
|
||||
<LocalisedText language={item.nameLanguage ?? 'ja'}>
|
||||
{item.name}
|
||||
</LocalisedText>
|
||||
@@ -541,15 +569,14 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
</div>)))}
|
||||
</div>)
|
||||
: (
|
||||
<AnimatePresence initial={false} custom={dir}>
|
||||
<AnimatePresence initial={false} custom={dir} mode="popLayout">
|
||||
<motion.div
|
||||
key={activeIdx}
|
||||
custom={dir}
|
||||
variants={{ enter: (d: -1 | 1) => ({ y: d * 24, opacity: 0 }),
|
||||
centre: { y: 0, opacity: 1 },
|
||||
exit: (d: -1 | 1) => ({ y: (-d) * 24, opacity: 0 }) }}
|
||||
className="absolute inset-0 flex items-center px-3
|
||||
overflow-x-auto whitespace-nowrap"
|
||||
className="relative flex min-h-[40px] flex-wrap items-center px-3"
|
||||
initial="enter"
|
||||
animate="centre"
|
||||
exit="exit"
|
||||
@@ -561,6 +588,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
? (
|
||||
<motion.div
|
||||
key={`c-${ i }`}
|
||||
className="min-w-0 max-w-full"
|
||||
transition={{ layout: topNavTransition }}
|
||||
layoutId={`submenu-${ visibleMenu[activeIdx].name }-${ i }`}>
|
||||
{item.component}
|
||||
@@ -568,6 +596,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
: (
|
||||
<motion.div
|
||||
key={`l-${ i }`}
|
||||
className="min-w-0 max-w-full"
|
||||
transition={{ layout: topNavTransition }}
|
||||
layoutId={`submenu-${ visibleMenu[activeIdx].name }-${ i }`}>
|
||||
<PrefetchLink
|
||||
@@ -575,7 +604,8 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
target={item.to.slice (0, 2) === '//'
|
||||
? '_blank'
|
||||
: undefined}
|
||||
className="top-nav-menu-link h-full flex items-center px-3">
|
||||
className="top-nav-menu-link flex min-h-[40px]
|
||||
items-center px-3 py-2">
|
||||
<LocalisedText language={item.nameLanguage ?? 'ja'}>
|
||||
{item.name}
|
||||
</LocalisedText>
|
||||
@@ -584,6 +614,7 @@ const TopNav: FC<Props> = ({ user, locales }) => {
|
||||
</motion.div>
|
||||
</AnimatePresence>)}
|
||||
</div>))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする