mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-09 01:18:20 +00:00
merge design protal and backoffice
This commit is contained in:
83
libs/ui/src/lib/layout/LanguageSwitcher.tsx
Normal file
83
libs/ui/src/lib/layout/LanguageSwitcher.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Menu, UnstyledButton, Text, rem } from '@mantine/core';
|
||||
import { IconWorld, IconCheck, IconChevronDown } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface LanguageSwitcherProps {
|
||||
supportedLanguages: readonly string[];
|
||||
/** `icon` renders a compact globe button; `button` shows the language label. */
|
||||
variant?: 'icon' | 'button';
|
||||
}
|
||||
|
||||
export function LanguageSwitcher({ supportedLanguages, variant = 'icon' }: LanguageSwitcherProps) {
|
||||
const { t, i18n } = useTranslation();
|
||||
const current = i18n.language;
|
||||
|
||||
const change = (lng: string) => {
|
||||
if (lng !== current) i18n.changeLanguage(lng);
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu shadow="md" width={160} position="bottom-end" withinPortal>
|
||||
<Menu.Target>
|
||||
<UnstyledButton
|
||||
aria-label={t('language.label')}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: rem(4),
|
||||
width: variant === 'icon' ? rem(38) : 'auto',
|
||||
height: rem(38),
|
||||
padding: variant === 'icon' ? 0 : '0 12px',
|
||||
borderRadius: rem(12),
|
||||
background: 'var(--mantine-color-body)',
|
||||
color: 'var(--mantine-color-gray-6)',
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px rgba(0,0,0,0.06)',
|
||||
transition: 'all 150ms ease',
|
||||
cursor: 'pointer',
|
||||
border: 'none',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = 'var(--mantine-color-primary-light)';
|
||||
e.currentTarget.style.color = 'var(--mantine-color-primary-6)';
|
||||
e.currentTarget.style.boxShadow =
|
||||
'0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px var(--mantine-color-primary-2)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'var(--mantine-color-body)';
|
||||
e.currentTarget.style.color = 'var(--mantine-color-gray-6)';
|
||||
e.currentTarget.style.boxShadow =
|
||||
'0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px rgba(0,0,0,0.06)';
|
||||
}}
|
||||
>
|
||||
<IconWorld size={19} />
|
||||
{variant !== 'icon' && (
|
||||
<>
|
||||
<Text size="sm" fw={500}>
|
||||
{t(`language.${current}`)}
|
||||
</Text>
|
||||
<IconChevronDown size={14} />
|
||||
</>
|
||||
)}
|
||||
</UnstyledButton>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown
|
||||
style={{ borderRadius: rem(12), padding: rem(6) }}
|
||||
>
|
||||
<Menu.Label>{t('language.label')}</Menu.Label>
|
||||
{supportedLanguages.map((lng) => (
|
||||
<Menu.Item
|
||||
key={lng}
|
||||
onClick={() => change(lng)}
|
||||
rightSection={
|
||||
current === lng ? <IconCheck size={16} /> : undefined
|
||||
}
|
||||
style={{ borderRadius: rem(8) }}
|
||||
>
|
||||
{t(`language.${lng}`)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user