From 74aa1c79b520fc38d4180d75ae28c998209a86b6 Mon Sep 17 00:00:00 2001 From: Foysal Ahamed Date: Mon, 19 Feb 2024 17:05:07 +0100 Subject: [PATCH] :sparkles: Allow multiple language inclusion and exclusion from the language picker --- components/common/LanguagePicker.tsx | 205 +++++++++++++++++++++++---- 1 file changed, 175 insertions(+), 30 deletions(-) diff --git a/components/common/LanguagePicker.tsx b/components/common/LanguagePicker.tsx index baf16607..2078c67e 100644 --- a/components/common/LanguagePicker.tsx +++ b/components/common/LanguagePicker.tsx @@ -1,8 +1,56 @@ -import { LANGUAGES } from '@/lib/locale/languages' +import { LANGUAGES_MAP_CODE2 } from '@/lib/locale/languages' +import { Popover, Transition } from '@headlessui/react' +import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid' import { useSearchParams, useRouter, usePathname } from 'next/navigation' -import { Select } from './forms' +import { ActionButton } from './buttons' -const languagesInPicker = LANGUAGES.filter(({ code2 }) => !!code2.trim()) +const availableLanguageCodes = [ + 'en', + 'es', + 'fr', + 'de', + 'it', + 'ja', + 'ko', + 'pt', + 'ru', +] + +const SelectionTitle = ({ + includedLanguages, + excludedLanguages, +}: { + includedLanguages: string[] + excludedLanguages: string[] +}) => { + if (includedLanguages.length === 0 && excludedLanguages.length === 0) { + return <>All Languages + } + + const includedNames = includedLanguages.map( + (lang) => LANGUAGES_MAP_CODE2[lang].name, + ) + const excludedNames = excludedLanguages.map( + (lang) => LANGUAGES_MAP_CODE2[lang].name, + ) + + return ( + <> + {includedNames.join(', ')} + {includedNames.length > 0 && excludedNames.length > 0 && ( + | + )} + + {excludedNames.map((name, i) => ( + + {name} + {i < excludedNames.length - 1 && ', '} + + ))} + + + ) +} export const LanguagePicker: React.FC = () => { const searchParams = useSearchParams() @@ -10,46 +58,143 @@ export const LanguagePicker: React.FC = () => { const pathname = usePathname() const tagsParam = searchParams.get('tags') + const excludeTagsParam = searchParams.get('excludeTags') const tags = tagsParam?.split(',') || [] - const lang = tags.find((tag) => tag.includes('lang:'))?.split(':')[1] + const excludedTags = excludeTagsParam?.split(',') || [] + const includedLanguages = tags + .filter((tag) => tag.includes('lang:')) + .map((tag) => tag.split(':')[1]) + const excludedLanguages = excludedTags + .filter((tag) => tag.includes('lang:')) + .map((tag) => tag.split(':')[1]) - const changeLanguage = (newLang: string) => { + const toggleLanguage = (section: 'include' | 'exclude', newLang: string) => { const nextParams = new URLSearchParams(searchParams) + const urlQueryKey = section === 'include' ? 'tags' : 'excludeTags' + const selectedLanguages = + section === 'include' ? includedLanguages : excludedLanguages + const selectedLanguageTags = section === 'include' ? tags : excludedTags - if (newLang) { - nextParams.set( - 'tags', - [ - ...tags.filter((tag) => !tag.includes('lang:')), - `lang:${newLang}`, - ].join(','), + if (selectedLanguages.includes(newLang)) { + const newTags = selectedLanguageTags.filter( + (tag) => `lang:${newLang}` !== tag, ) - } else { - const newTags = tags.filter((tag) => !tag.includes('lang:')) if (newTags.length) { - nextParams.set('tags', newTags.join(',')) + nextParams.set(urlQueryKey, newTags.join(',')) } else { - nextParams.delete('tags') + nextParams.delete(urlQueryKey) } + } else { + nextParams.set( + urlQueryKey, + [...selectedLanguageTags, `lang:${newLang}`].join(','), + ) } router.push((pathname ?? '') + '?' + nextParams.toString()) } + const clearLanguages = () => { + const nextParams = new URLSearchParams(searchParams) + + nextParams.delete('tags') + nextParams.delete('excludeTags') + router.push((pathname ?? '') + '?' + nextParams.toString()) + } return ( - + + {({ open, close }) => ( + <> + + + + + + {/* Use the `Transition` component. */} + + +
+
+ toggleLanguage('include', lang)} + /> + toggleLanguage('exclude', lang)} + /> +
+ {(includedLanguages.length > 0 || + excludedLanguages.length > 0) && ( +
+ { + clearLanguages() + close() + }} + > + Clear All + +
+ )} +
+
+
+ + )} +
+ ) +} + +const LanguageList = ({ + header, + onSelect, + selected = [], + disabled = [], +}: { + selected: string[] + disabled: string[] + header: string + onSelect: (lang: string) => void +}) => { + return ( +
+

+ {header} +

+
+ {availableLanguageCodes.map((code2) => { + const isDisabled = disabled.includes(code2) + return ( + + ) + })} +
+
) }