import clsx from 'clsx'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { PiDotsThreeVerticalBold } from 'react-icons/pi'; import { Insets } from '@/types/misc'; import { useEnv } from '@/context/EnvContext'; import { useThemeStore } from '@/store/themeStore'; import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useTrafficLightStore } from '@/store/trafficLightStore'; import { useTrafficLight } from '@/hooks/useTrafficLight'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import WindowButtons from '@/components/WindowButtons'; import Dropdown from '@/components/Dropdown'; import SidebarToggler from './SidebarToggler'; import BookmarkToggler from './BookmarkToggler'; import NotebookToggler from './NotebookToggler'; import SettingsToggler from './SettingsToggler'; import TranslationToggler from './TranslationToggler'; import ViewMenu from './ViewMenu'; interface HeaderBarProps { bookKey: string; bookTitle: string; isTopLeft: boolean; isHoveredAnim: boolean; gridInsets: Insets; onCloseBook: (bookKey: string) => void; } const HeaderBar: React.FC = ({ bookKey, bookTitle, isTopLeft, isHoveredAnim, gridInsets, onCloseBook, }) => { const _ = useTranslation(); const { appService } = useEnv(); const headerRef = useRef(null); const { isTrafficLightVisible } = useTrafficLight(); const { trafficLightInFullscreen, setTrafficLightVisibility } = useTrafficLightStore(); const [isDropdownOpen, setIsDropdownOpen] = useState(false); const { bookKeys, hoveredBookKey, setHoveredBookKey } = useReaderStore(); const { systemUIVisible, statusBarHeight } = useThemeStore(); const { isSideBarVisible } = useSidebarStore(); const iconSize16 = useResponsiveSize(16); const windowButtonVisible = appService?.hasWindowBar && !isTrafficLightVisible; const handleToggleDropdown = (isOpen: boolean) => { setIsDropdownOpen(isOpen); if (!isOpen) setHoveredBookKey(''); }; useEffect(() => { if (!appService?.hasTrafficLight) return; if (isSideBarVisible) return; if (hoveredBookKey === bookKey && isTopLeft) { setTrafficLightVisibility(true, { x: 10, y: 20 }); } else if (!hoveredBookKey) { setTrafficLightVisibility(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [appService, isSideBarVisible, hoveredBookKey]); // Check if mouse is outside header area to avoid false positive event of MouseLeave when clicking inside header on Windows const isMouseOutsideHeader = useCallback((clientX: number, clientY: number) => { if (!headerRef.current) return true; const rect = headerRef.current.getBoundingClientRect(); return ( clientX <= rect.left || clientX >= rect.right || clientY <= rect.top || clientY >= rect.bottom ); }, []); const isHeaderVisible = hoveredBookKey === bookKey || isDropdownOpen; const trafficLightInHeader = appService?.hasTrafficLight && !trafficLightInFullscreen && !isSideBarVisible && isTopLeft; return (
setHoveredBookKey(bookKey)} onMouseEnter={() => !appService?.isMobile && setHoveredBookKey(bookKey)} onTouchStart={() => !appService?.isMobile && setHoveredBookKey(bookKey)} />
!appService?.isMobile && setHoveredBookKey(bookKey)} onMouseLeave={(e) => { if (!appService?.isMobile && isMouseOutsideHeader(e.clientX, e.clientY)) { setHoveredBookKey(''); } }} >
} onToggle={handleToggleDropdown} > { setHoveredBookKey(null); onCloseBook(bookKey); }} />
); }; export default HeaderBar;