90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
/* -------------------------------------------------------------------------- */
|
|
/* Libraries */
|
|
/* -------------------------------------------------------------------------- */
|
|
import React from "react";
|
|
import { Langs } from "localization/i18n";
|
|
import { useTranslation } from "react-i18next";
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Hooks */
|
|
/* -------------------------------------------------------------------------- */
|
|
import { useLangugeViewModel } from "localization/controller/langugeViewModel";
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Components */
|
|
/* -------------------------------------------------------------------------- */
|
|
import Combox from "components/controls/Combox";
|
|
import Modal from "components/containers/modal/Modal";
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Icons */
|
|
/* -------------------------------------------------------------------------- */
|
|
import classNames from "classnames";
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Properties */
|
|
/* -------------------------------------------------------------------------- */
|
|
type Props = {
|
|
isShown: boolean;
|
|
onClose: VoidFunction;
|
|
};
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Language switcher */
|
|
/* -------------------------------------------------------------------------- */
|
|
function CheckIcon(props: React.SVGProps<SVGSVGElement>) {
|
|
return (
|
|
<svg viewBox="0 0 24 24" {...props}>
|
|
<circle cx={12} cy={12} r={12} stroke="none" opacity="0.2" />
|
|
<path
|
|
d="M7 13l3 3 7-7"
|
|
fill="none"
|
|
strokeWidth={1.5}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
export default function LanguageSelector({ isShown, onClose }: Props) {
|
|
const { t } = useTranslation();
|
|
const { selected, languages, switchLang } = useLangugeViewModel();
|
|
|
|
return (
|
|
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
|
<Modal.Header>{t("selectLanguage")}</Modal.Header>
|
|
<Combox
|
|
options={Object.keys(languages)}
|
|
displayValue={(key) => languages[key as Langs].nativeName}
|
|
keyMaper={(key) => key}
|
|
setSelected={switchLang}
|
|
filterRule={(query, item) => {
|
|
if (query === "") {
|
|
return true;
|
|
}
|
|
return languages[item as Langs].nativeName
|
|
.toLowerCase()
|
|
.replace(/\s+/g, "")
|
|
.includes(query.toLowerCase().replace(/\s+/g, ""));
|
|
}}
|
|
selected={selected}
|
|
itemBuilder={({ selected, active }, item) => {
|
|
return (
|
|
<div className="flex items-center justify-between">
|
|
<span
|
|
className={`block truncate ${
|
|
selected ? "font-medium" : "font-normal"
|
|
}`}
|
|
>
|
|
{languages[item as Langs].nativeName}
|
|
</span>
|
|
<CheckIcon
|
|
className={classNames("w-5 h-5", {
|
|
"stroke-blue-400 fill-white": selected,
|
|
"stroke-transparent fill-transparent": !selected,
|
|
})}
|
|
/>
|
|
</div>
|
|
);
|
|
}}
|
|
/>
|
|
</Modal>
|
|
);
|
|
}
|