diff --git a/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx b/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx index b97ad63a..2781479e 100644 --- a/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx +++ b/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx @@ -1,5 +1,6 @@ import clsx from 'clsx'; -import React from 'react'; +import React, { useMemo } from 'react'; +import { FixedSizeList as List } from 'react-window'; import { FiChevronUp, FiChevronLeft } from 'react-icons/fi'; import { MdCheck } from 'react-icons/md'; import { useEnv } from '@/context/EnvContext'; @@ -15,6 +16,44 @@ interface DropdownProps { onGetFontFamily: (option: string, family: string) => string; } +interface FontItemProps { + index: number; + style: React.CSSProperties; + data: { + options: { option: string; label?: string }[]; + selected: string; + onSelect: (option: string) => void; + onGetFontFamily: (option: string, family: string) => string; + family: string; + iconSize: number; + }; +} + +const FontItem: React.FC = ({ index, style, data }) => { + const { options, selected, onSelect, onGetFontFamily, family, iconSize: iconSize16 } = data; + const option = options[index]!; + + return ( +
  • onSelect(option.option)} + > +
    + + {selected === option.option && ( + + )} + + + {option.label || option.option} + +
    +
  • + ); +}; + const FontDropdown: React.FC = ({ family, selected, @@ -25,9 +64,38 @@ const FontDropdown: React.FC = ({ }) => { const _ = useTranslation(); const { appService } = useEnv(); - const iconSize16 = useResponsiveSize(16); + const iconSize = useResponsiveSize(16); const allOptions = [...options, ...(moreOptions ?? [])]; const selectedOption = allOptions.find((option) => option.option === selected) ?? allOptions[0]!; + + const ITEM_HEIGHT = 40; + const MAX_HEIGHT = 320; + + const mainListData = useMemo( + () => ({ + options, + selected, + onSelect, + onGetFontFamily, + family: family ?? '', + iconSize, + appService, + }), + [options, selected, onSelect, onGetFontFamily, family, iconSize, appService], + ); + + const moreListData = useMemo( + () => ({ + options: moreOptions ?? [], + selected, + onSelect, + onGetFontFamily, + family: family ?? '', + iconSize, + }), + [moreOptions, selected, onSelect, onGetFontFamily, family, iconSize], + ); + return (
      - {options.map(({ option, label }) => ( -
    • onSelect(option)}> -
      - - {selected === option && } - - - {label || option} - -
      -
    • - ))} + {/* Virtualized main options */} +
      + + {FontItem} + +
      + + {/* More options with nested dropdown */} {moreOptions && moreOptions.length > 0 && ( -
    • +
    • - - + + {_('System Fonts')}
      @@ -79,29 +149,21 @@ const FontDropdown: React.FC = ({ tabIndex={0} className={clsx( 'dropdown-content bgcolor-base-200 menu rounded-box relative z-[1] shadow', - '!sm:px-2 !mr-4 mb-[-46px] inline max-h-80 w-[46vw] overflow-y-scroll !px-1 sm:w-[200px]', + '!mr-4 mb-[-46px] inline w-[46vw] overflow-hidden !px-0 sm:w-[200px]', )} > - {moreOptions.map((option, index) => ( -
    • onSelect(option.option)}> -
      - - {selected === option.option && ( - - )} - - - {option.label || option.option} - -
      -
    • - ))} + {/* Virtualized more options */} +
      + + {FontItem} + +
    )} diff --git a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx index 963141f5..bc2cb119 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx @@ -204,6 +204,7 @@ const TOCView: React.FC<{ if (flatItems.length > 0) { setTimeout(scrollToActiveItem, appService?.isAndroidApp ? 300 : 0); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [flatItems, scrollToActiveItem]); return flatItems.length > 256 ? (