From f2490ee7751dd58cc371ee07df01fe5cf7ac7e84 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 24 Jun 2025 09:54:57 +0300 Subject: [PATCH] refactor(Dropdown): clean up --- .../MultiselectMenu/Dropdown/Dropdown.tsx | 57 +++---------------- .../Dropdown/Option/Option.less | 4 ++ .../Dropdown/Option/Option.tsx | 11 +++- .../Dropdown/useLanguageSorting.ts | 38 +++++++++++++ 4 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 src/components/MultiselectMenu/Dropdown/useLanguageSorting.ts diff --git a/src/components/MultiselectMenu/Dropdown/Dropdown.tsx b/src/components/MultiselectMenu/Dropdown/Dropdown.tsx index d25533732..ecc0800cb 100644 --- a/src/components/MultiselectMenu/Dropdown/Dropdown.tsx +++ b/src/components/MultiselectMenu/Dropdown/Dropdown.tsx @@ -7,7 +7,7 @@ import classNames from 'classnames'; import Option from './Option'; import Icon from '@stremio/stremio-icons/react'; import styles from './Dropdown.less'; -import interfaceLanguages from '../../../common/interfaceLanguages.json'; +import useLanguageSorting from './useLanguageSorting'; type Props = { options: MultiselectMenuOption[]; @@ -18,29 +18,9 @@ type Props = { onSelect: (value: any) => void; }; -function normalizeLanguageCode(langCode: string): string { - const language = interfaceLanguages.find((lang) => lang.codes.includes(langCode)); - if (!language) { - console.warn(`Unknown language code: ${langCode}. Falling back to 'eng'.`); - return 'eng'; - } - return language.codes[1]; -} - -function getOptionLanguageCode(option: MultiselectMenuOption) { - if (option.label === 'None') { - return 'None'; - } - if (!option || !option.value) { - console.warn('Invalid option or option value:', option); - return 'eng'; - } - const optionValue = String(option.value); - return optionValue.length === 3 ? optionValue : normalizeLanguageCode(optionValue) || 'eng'; -} - const Dropdown = ({ level, setLevel, options, onSelect, value, menuOpen }: Props) => { const { t } = useTranslation(); + const { isLanguageDropdown, sortedOptions } = useLanguageSorting(options); const optionsRef = useRef(new Map()); const containerRef = useRef(null); @@ -70,28 +50,6 @@ const Dropdown = ({ level, setLevel, options, onSelect, value, menuOpen }: Props } }, [menuOpen, selectedOption]); - const browserLocale = navigator.language || 'eng-US'; - const userLanguageCode = normalizeLanguageCode(browserLocale) || 'eng'; - - const priorityLanguage = userLanguageCode === 'eng' - ? ['eng', 'None'] - : [userLanguageCode, 'eng', 'None']; - - const isPriorityLanguage = (option: MultiselectMenuOption) => { - return priorityLanguage.includes(getOptionLanguageCode(option)); - }; - - const visibleOptions = options.filter((option: MultiselectMenuOption) => !option.hidden); - - const sortedOptions = [ - - ...priorityLanguage.flatMap((lang) => - visibleOptions.filter((option) => getOptionLanguageCode(option) === lang)), - - ...visibleOptions - .filter((option) => !isPriorityLanguage(option)) - .sort((a, b) => a.label.localeCompare(b.label)) - ]; return (
: null } - - {sortedOptions.map((option: MultiselectMenuOption) => ( -
+ {(isLanguageDropdown ? sortedOptions : options) + ?.filter((option: MultiselectMenuOption) => !option.hidden) + .map((option: MultiselectMenuOption) => (
- ))} + )) + }
); }; diff --git a/src/components/MultiselectMenu/Dropdown/Option/Option.less b/src/components/MultiselectMenu/Dropdown/Option/Option.less index a0ee1743f..ea69df18d 100644 --- a/src/components/MultiselectMenu/Dropdown/Option/Option.less +++ b/src/components/MultiselectMenu/Dropdown/Option/Option.less @@ -23,6 +23,10 @@ opacity: 1; } + &.separator { + border-bottom: thin solid var(--overlay-color); + } + &:hover { background-color: rgba(255, 255, 255, 0.15); } diff --git a/src/components/MultiselectMenu/Dropdown/Option/Option.tsx b/src/components/MultiselectMenu/Dropdown/Option/Option.tsx index 5d43fb45b..0abd6d3c7 100644 --- a/src/components/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/components/MultiselectMenu/Dropdown/Option/Option.tsx @@ -5,6 +5,8 @@ import classNames from 'classnames'; import { Button } from 'stremio/components'; import styles from './Option.less'; import Icon from '@stremio/stremio-icons/react'; +import useLanguageSorting from '../useLanguageSorting'; +import interfaceLanguages from 'stremio/common/interfaceLanguages.json'; type Props = { option: MultiselectMenuOption; @@ -13,8 +15,15 @@ type Props = { }; const Option = forwardRef(({ option, selectedValue, onSelect }, ref) => { + const { userLangCode } = useLanguageSorting(); + const selected = useMemo(() => option?.value === selectedValue, [option, selectedValue]); + const separator = useMemo(() => { + const lang = interfaceLanguages.find((l) => l.name === option?.label); + return lang ? userLangCode.some((code) => lang.codes.includes(code)) : false; + }, [option, userLangCode]); + const handleClick = useCallback(() => { onSelect(option.value); }, [onSelect, option.value]); @@ -22,7 +31,7 @@ const Option = forwardRef(({ option, selectedValue, on return (