fix: menu bar position calculation incorrect

This commit is contained in:
wj-xiao
2026-01-31 15:59:18 +08:00
parent 18bfcb15c3
commit 4eebba0cf9
2 changed files with 36 additions and 86 deletions

View File

@@ -21,65 +21,37 @@ export const Menu = () => {
const [isMenuOpen, setIsMenuOpen] = useState(true);
const [menuBounds, setMenuBounds] = useState({ left: 0, right: 0, top: 0, bottom: 0 });
const [position, setPosition] = useState({ x: 0, y: 0 });
const [initialized, setInitialized] = useState(false);
const nodeRef = useRef<HTMLDivElement | null>(null);
const handleResize = useCallback(() => {
if (!nodeRef.current) return;
const { innerWidth, innerHeight } = window;
const { offsetWidth, offsetHeight } = nodeRef.current;
const elementRect = nodeRef.current.getBoundingClientRect();
const width = (window.innerWidth - elementRect.width) / 2;
setMenuBounds({
left: 0,
top: 0,
right: innerWidth - offsetWidth,
bottom: innerHeight - offsetHeight
left: -width,
top: -10,
right: width,
bottom: window.innerHeight - elementRect.height - 10
});
}, []);
const initializePosition = useCallback(() => {
if (!nodeRef.current || initialized) return;
const { innerWidth } = window;
requestAnimationFrame(() => {
if (!nodeRef.current) return;
const width = nodeRef.current.offsetWidth;
setPosition({
x: (innerWidth - width) / 2,
y: 10
});
setInitialized(true);
});
}, [initialized]);
useEffect(() => {
const isOpen = storage.getIsMenuOpen();
setIsMenuOpen(isOpen);
window.addEventListener('resize', handleResize);
const observer = new ResizeObserver(() => {
handleResize();
});
if (nodeRef.current) {
observer.observe(nodeRef.current);
}
return () => {
window.removeEventListener('resize', handleResize);
observer.disconnect();
};
}, [handleResize]);
useEffect(() => {
handleResize();
initializePosition();
}, [isMenuOpen, handleResize, initializePosition]);
}, [isMenuOpen, serialState, handleResize]);
function toggleMenu() {
const isOpen = !isMenuOpen;
@@ -93,10 +65,12 @@ export const Menu = () => {
nodeRef={nodeRef}
bounds={menuBounds}
handle="strong"
position={position}
onDrag={(_, data) => setPosition({ x: data.x, y: data.y })}
positionOffset={{ x: '-50%', y: '0%' }}
>
<div ref={nodeRef} className="fixed left-0 top-0 z-[1000]">
<div
ref={nodeRef}
className="fixed left-1/2 top-[10px] z-[1000] -translate-x-1/2 transition-opacity duration-300"
>
{/* Menubar */}
<div className="sticky top-[10px] flex w-full justify-center">
<div
@@ -106,7 +80,7 @@ export const Menu = () => {
)}
>
<strong>
<div className="flex h-[28px] cursor-move select-none items-center justify-center text-neutral-500">
<div className="flex h-[28px] cursor-move select-none items-center justify-center text-neutral-400">
<GripVerticalIcon size={18} />
</div>
</strong>
@@ -143,13 +117,13 @@ export const Menu = () => {
{!isMenuOpen && (
<div className="flex items-center rounded-lg bg-neutral-800/50 p-1">
<strong>
<div className="flex size-[26px] cursor-move select-none items-center justify-center text-neutral-500">
<div className="flex size-[26px] cursor-move select-none items-center justify-center text-neutral-400">
<GripVerticalIcon size={18} />
</div>
</strong>
<Divider type="vertical" style={{ margin: '0 4px' }} />
<div
className="flex size-[26px] cursor-pointer items-center justify-center rounded text-neutral-500 hover:bg-neutral-700/70 hover:text-white"
className="flex size-[26px] cursor-pointer items-center justify-center rounded text-neutral-400 hover:bg-neutral-700/70 hover:text-white"
onClick={toggleMenu}
>
<ChevronRightIcon size={18} />

View File

@@ -1,4 +1,4 @@
import { ReactElement, useCallback, useEffect, useRef, useState } from 'react'
import { ReactElement, useEffect, useRef, useState } from 'react'
import { Divider } from 'antd'
import clsx from 'clsx'
import { ChevronRightIcon, GripVerticalIcon, XIcon } from 'lucide-react'
@@ -16,65 +16,39 @@ import { Video } from './video'
export const Menu = (): ReactElement => {
const [isMenuOpen, setIsMenuOpen] = useState(true)
const [menuBounds, setMenuBounds] = useState({ left: 0, right: 0, top: 0, bottom: 0 })
const [position, setPosition] = useState({ x: 0, y: 0 })
const [initialized, setInitialized] = useState(false)
const nodeRef = useRef<HTMLDivElement | null>(null)
const handleResize = useCallback(() => {
const handleResize = (): void => {
if (!nodeRef.current) return
const { innerWidth, innerHeight } = window
const { offsetWidth, offsetHeight } = nodeRef.current
const elementRect = nodeRef.current.getBoundingClientRect()
const width = (window.innerWidth - elementRect.width) / 2
setMenuBounds({
left: 0,
top: 0,
right: innerWidth - offsetWidth,
bottom: innerHeight - offsetHeight
left: -width,
top: -10,
right: width,
bottom: window.innerHeight - elementRect.height - 10
})
}, [])
const initializePosition = useCallback(() => {
if (!nodeRef.current || initialized) return
const { innerWidth } = window
requestAnimationFrame(() => {
if (!nodeRef.current) return
const width = nodeRef.current.offsetWidth
setPosition({
x: (innerWidth - width) / 2,
y: 10
})
setInitialized(true)
})
}, [initialized])
}
useEffect(() => {
const isOpen = storage.getIsMenuOpen()
setIsMenuOpen(isOpen)
handleResize()
window.addEventListener('resize', handleResize)
const observer = new ResizeObserver(() => {
handleResize()
})
if (nodeRef.current) {
observer.observe(nodeRef.current)
}
return () => {
window.removeEventListener('resize', handleResize)
observer.disconnect()
}
}, [handleResize])
}, [])
useEffect(() => {
handleResize()
initializePosition()
}, [isMenuOpen, handleResize, initializePosition])
}, [isMenuOpen])
function toggleMenu(): void {
setIsMenuOpen(!isMenuOpen)
@@ -85,10 +59,12 @@ export const Menu = (): ReactElement => {
nodeRef={nodeRef}
bounds={menuBounds}
handle="strong"
position={position}
onDrag={(_, data) => setPosition({ x: data.x, y: data.y })}
positionOffset={{ x: '-50%', y: '0%' }}
>
<div ref={nodeRef} className="fixed top-0 left-0 z-[1000]">
<div
ref={nodeRef}
className="fixed top-[10px] left-1/2 z-[1000] transition-opacity duration-300"
>
{/* Menubar */}
<div className="sticky top-[10px] flex w-full justify-center">
<div
@@ -98,7 +74,7 @@ export const Menu = (): ReactElement => {
)}
>
<strong>
<div className="flex h-[28px] cursor-move items-center justify-center pl-1 text-neutral-500 select-none">
<div className="flex h-[28px] cursor-move items-center justify-center pl-1 text-neutral-400 select-none">
<GripVerticalIcon size={18} />
</div>
</strong>
@@ -127,13 +103,13 @@ export const Menu = (): ReactElement => {
{!isMenuOpen && (
<div className="flex items-center rounded-lg bg-neutral-800/50 p-1">
<strong>
<div className="flex size-[26px] cursor-move items-center justify-center text-neutral-500 select-none">
<div className="flex size-[26px] cursor-move items-center justify-center text-neutral-400 select-none">
<GripVerticalIcon size={18} />
</div>
</strong>
<Divider type="vertical" style={{ margin: '0 4px' }} />
<div
className="flex size-[26px] cursor-pointer items-center justify-center rounded text-neutral-500 hover:bg-neutral-800/60 hover:text-white"
className="flex size-[26px] cursor-pointer items-center justify-center rounded text-neutral-400 hover:bg-neutral-800/60 hover:text-white"
onClick={toggleMenu}
>
<ChevronRightIcon size={18} />