mirror of
https://github.com/sipeed/NanoKVM-USB.git
synced 2026-09-11 05:59:57 -05:00
fix: menu bar position calculation incorrect
This commit is contained in:
@@ -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} />
|
||||
|
||||
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user