feat: language selector (#484)

* feat: language selector

* refactor: move user general page

* feat: language selector

* refactor: move user general page

* feat: add language combobox in user general
This commit is contained in:
Manuel
2024-05-18 13:54:43 +02:00
committed by GitHub
parent 8e8f9081b0
commit 31c2694185
17 changed files with 188 additions and 29 deletions

View File

@@ -0,0 +1,3 @@
.flagIcon {
border-radius: 4px;
}

View File

@@ -0,0 +1,94 @@
"use client";
import React from "react";
import { Combobox, Group, InputBase, Text, useCombobox } from "@mantine/core";
import { IconCheck } from "@tabler/icons-react";
import type { SupportedLanguage } from "@homarr/translation";
import { localeAttributes, supportedLanguages } from "@homarr/translation";
import { useChangeLocale, useCurrentLocale } from "@homarr/translation/client";
import classes from "./language-combobox.module.css";
export const LanguageCombobox = () => {
const combobox = useCombobox({
onDropdownClose: () => combobox.resetSelectedOption(),
});
const currentLocale = useCurrentLocale();
const changeLocale = useChangeLocale();
const handleOnOptionSubmit = React.useCallback(
(value: string) => {
if (!value) {
return;
}
changeLocale(value as SupportedLanguage);
combobox.closeDropdown();
},
[changeLocale, combobox],
);
const handleOnClick = React.useCallback(() => {
combobox.toggleDropdown();
}, [combobox]);
return (
<Combobox store={combobox} onOptionSubmit={handleOnOptionSubmit}>
<Combobox.Target>
<InputBase
component="button"
type="button"
pointer
rightSection={<Combobox.Chevron />}
rightSectionPointerEvents="none"
onClick={handleOnClick}
variant="filled"
>
<OptionItem currentLocale={currentLocale} localeKey={currentLocale} />
</InputBase>
</Combobox.Target>
<Combobox.Dropdown>
<Combobox.Options>
{supportedLanguages.map((languageKey) => (
<Combobox.Option value={languageKey} key={languageKey}>
<OptionItem
currentLocale={currentLocale}
localeKey={languageKey}
showCheck
/>
</Combobox.Option>
))}
</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
);
};
const OptionItem = ({
currentLocale,
localeKey,
showCheck,
}: {
currentLocale: SupportedLanguage;
localeKey: SupportedLanguage;
showCheck?: boolean;
}) => {
return (
<Group wrap="nowrap" justify="space-between">
<Group wrap="nowrap">
<span
className={`fi fi-${localeAttributes[localeKey].flagIcon} ${classes.flagIcon}`}
></span>
<Group wrap="nowrap" gap="xs">
<Text>{localeAttributes[localeKey].name}</Text>
<Text size="xs" c="dimmed" inherit>
({localeAttributes[localeKey].translatedName})
</Text>
</Group>
</Group>
{showCheck && localeKey === currentLocale && (
<IconCheck color="currentColor" size={16} />
)}
</Group>
);
};

View File

@@ -27,6 +27,10 @@ import { signOut, useSession } from "@homarr/auth/client";
import { createModal, useModalAction } from "@homarr/modals";
import { useScopedI18n } from "@homarr/translation/client";
import "flag-icons/css/flag-icons.min.css";
import { LanguageCombobox } from "./language/language-combobox";
interface UserAvatarMenuProps {
children: ReactNode;
}
@@ -57,7 +61,7 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => {
}, [openModal, router]);
return (
<Menu width={200} withArrow withinPortal>
<Menu width={300} withArrow withinPortal>
<Menu.Dropdown>
<Menu.Item
onClick={toggleColorScheme}
@@ -72,23 +76,32 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => {
>
{t("navigateDefaultBoard")}
</Menu.Item>
{Boolean(session.data) && (
<Menu.Item
component={Link}
href={`/manage/users/${session.data?.user.id}`}
leftSection={<IconSettings size="1rem" />}
>
{t("preferences")}
</Menu.Item>
)}
<Menu.Item
component={Link}
href="/manage"
leftSection={<IconTool size="1rem" />}
>
{t("management")}
<Menu.Divider />
<Menu.Item p={0} closeMenuOnClick={false}>
<LanguageCombobox />
</Menu.Item>
<Menu.Divider />
{Boolean(session.data) && (
<>
<Menu.Item
component={Link}
href={`/manage/users/${session.data?.user.id}`}
leftSection={<IconSettings size="1rem" />}
>
{t("preferences")}
</Menu.Item>
<Menu.Item
component={Link}
href="/manage"
leftSection={<IconTool size="1rem" />}
>
{t("management")}
</Menu.Item>
</>
)}
<Menu.Divider />
{session.status === "authenticated" ? (
<Menu.Item
onClick={handleSignout}