import clsx from 'clsx'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { FaSearch } from 'react-icons/fa'; import { PiPlus } from 'react-icons/pi'; import { PiSelectionAllDuotone } from 'react-icons/pi'; import { PiDotsThreeCircle } from 'react-icons/pi'; import { MdOutlineMenu, MdArrowBackIosNew } from 'react-icons/md'; import { IoMdCloseCircle } from 'react-icons/io'; import { useEnv } from '@/context/EnvContext'; import { useThemeStore } from '@/store/themeStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useLibraryStore } from '@/store/libraryStore'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import { useSafeAreaInsets } from '@/hooks/useSafeAreaInsets'; import { useTrafficLightStore } from '@/store/trafficLightStore'; import { navigateToLibrary } from '@/utils/nav'; import { debounce } from '@/utils/debounce'; import useShortcuts from '@/hooks/useShortcuts'; import WindowButtons from '@/components/WindowButtons'; import Dropdown from '@/components/Dropdown'; import SettingsMenu from './SettingsMenu'; import ImportMenu from './ImportMenu'; import ViewMenu from './ViewMenu'; interface LibraryHeaderProps { isSelectMode: boolean; isSelectAll: boolean; onImportBooks: () => void; onToggleSelectMode: () => void; onSelectAll: () => void; onDeselectAll: () => void; } const LibraryHeader: React.FC = ({ isSelectMode, isSelectAll, onImportBooks, onToggleSelectMode, onSelectAll, onDeselectAll, }) => { const _ = useTranslation(); const router = useRouter(); const searchParams = useSearchParams(); const { appService } = useEnv(); const { systemUIVisible, statusBarHeight } = useThemeStore(); const { currentBookshelf } = useLibraryStore(); const { isTrafficLightVisible, initializeTrafficLightStore, initializeTrafficLightListeners, setTrafficLightVisibility, cleanupTrafficLightListeners, } = useTrafficLightStore(); const [searchQuery, setSearchQuery] = useState(searchParams?.get('q') ?? ''); const headerRef = useRef(null); const iconSize18 = useResponsiveSize(18); const iconSize20 = useResponsiveSize(20); const insets = useSafeAreaInsets(); useShortcuts({ onToggleSelectMode, }); // eslint-disable-next-line react-hooks/exhaustive-deps const debouncedUpdateQueryParam = useCallback( debounce((value: string) => { const params = new URLSearchParams(searchParams?.toString()); if (value) { params.set('q', value); } else { params.delete('q'); } router.push(`?${params.toString()}`); }, 500), [searchParams], ); const handleSearchChange = (e: React.ChangeEvent) => { const newQuery = e.target.value; setSearchQuery(newQuery); debouncedUpdateQueryParam(newQuery); }; useEffect(() => { if (!appService?.hasTrafficLight) return; initializeTrafficLightStore(appService); initializeTrafficLightListeners(); setTrafficLightVisibility(true); return () => { cleanupTrafficLightListeners(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const windowButtonVisible = appService?.hasWindowBar && !isTrafficLightVisible; const isInGroupView = !!searchParams?.get('group'); const currentBooksCount = currentBookshelf.reduce( (acc, item) => acc + ('books' in item ? item.books.length : 1), 0, ); if (!insets) return null; return (
{isInGroupView && ( )}
1 ? _('Search in {{count}} Book(s)...', { count: currentBooksCount, }) : _('Search Books...') } onChange={handleSearchChange} spellCheck='false' className={clsx( 'input rounded-badge bg-base-300/50 h-9 w-full pl-10 pr-10 sm:h-7', 'font-sans text-sm font-light', 'border-none focus:outline-none focus:ring-0', )} />
{searchQuery && ( )}
} > {appService?.isMobile ? null : ( )}
{isSelectMode ? (
) : (
} > } > {appService?.hasWindowBar && ( )}
)}
); }; export default LibraryHeader;