Move language settings (#2426)

* added date formatting according to chosen language

* deleted spaces

* deleted spaces

* fixed typos

* set date formats after

* move

* add L LT

---------

Co-authored-by: Artsiom Voitas <artsiom.voitas@gmail.com>
This commit is contained in:
Utku 2024-04-30 18:58:02 -04:00 committed by GitHub
parent dee3ca0524
commit 312524a860
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 167 deletions

View file

@ -77,6 +77,7 @@ export function generateLocaleDateFormats(language: string) {
value: 'L',
label: dayjs().locale(language).format('L')
},
{ value: 'L LT', label: dayjs().locale(language).format('L LT') },
{
value: 'll',
label: dayjs().locale(language).format('ll')

View file

@ -1,18 +1,13 @@
import { CheckCircle } from '@phosphor-icons/react';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
import {
Themes,
unitFormatStore,
useExplorerLayoutStore,
useThemeStore,
useUnitFormatStore,
useZodForm
} from '@sd/client';
import { Button, Divider, Form, Select, SelectOption, SwitchField, z } from '@sd/ui';
import { useState } from 'react';
import { Themes, useExplorerLayoutStore, useThemeStore, useUnitFormatStore } from '@sd/client';
import { Select, SelectOption } from '@sd/ui';
import i18n from '~/app/I18n';
import { useLocale } from '~/hooks';
import { usePlatform } from '~/util/Platform';
import { generateLocaleDateFormats } from '../../Explorer/util';
import HorizontalScroll from '../../overview/Layout/HorizontalScroll';
import { Heading } from '../Layout';
import Setting from '../Setting';
@ -28,12 +23,6 @@ type Theme = {
type ThemeProps = Theme & { isSelected?: boolean; className?: string };
const schema = z.object({
uiAnimations: z.boolean(),
syncThemeWithSystem: z.boolean(),
blurEffects: z.boolean()
});
const themes: Theme[] = [
{
insideColor: 'bg-white',
@ -61,32 +50,42 @@ const themes: Theme[] = [
}
];
// Unsorted list of languages available in the app.
const LANGUAGE_OPTIONS = [
{ value: 'en', label: 'English (US)' },
{ value: 'en_gb', label: 'English (UK)' },
{ value: 'de', label: 'Deutsch' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'tr', label: 'Türkçe' },
{ value: 'nl', label: 'Nederlands' },
{ value: 'be', label: 'Беларуская' },
{ value: 'ru', label: 'Русский' },
{ value: 'zh_CN', label: '中文(简体)' },
{ value: 'zh_TW', label: '中文(繁體)' },
{ value: 'it', label: 'Italiano' },
{ value: 'ja', label: '日本語' }
];
// Sort the languages by their label
LANGUAGE_OPTIONS.sort((a, b) => a.label.localeCompare(b.label));
export const Component = () => {
const { lockAppTheme } = usePlatform();
const themeStore = useThemeStore();
const formatStore = useUnitFormatStore();
const explorerLayout = useExplorerLayoutStore();
const { t } = useLocale();
const [dateFormats, setDateFormats] = useState(
generateLocaleDateFormats(i18n.resolvedLanguage || i18n.language || 'en')
);
const { t, dateFormat, setDateFormat } = useLocale();
const [selectedTheme, setSelectedTheme] = useState<Theme['themeValue']>(
themeStore.syncThemeWithSystem === true ? 'system' : themeStore.theme
);
const form = useZodForm({
schema
});
const onSubmit = form.handleSubmit(async (data) => {
console.log({ data });
});
useEffect(() => {
const subscription = form.watch(() => onSubmit());
return () => {
subscription.unsubscribe();
};
}, [form, onSubmit]);
const themeSelectHandler = (theme: Theme['themeValue']) => {
setSelectedTheme(theme);
if (theme === 'system') {
@ -103,68 +102,40 @@ export const Component = () => {
}
};
const hueSliderHandler = (hue: number) => {
themeStore.hueValue = hue;
if (themeStore.theme === 'vanilla') {
document.documentElement.style.setProperty('--light-hue', hue.toString());
} else if (themeStore.theme === 'dark') {
document.documentElement.style.setProperty('--dark-hue', hue.toString());
}
};
return (
<>
<Form className="relative" form={form} onSubmit={onSubmit}>
<Heading
title={t('appearance')}
description={t('appearance_description')}
rightArea={
<div>
<Button
disabled={themeStore.hueValue === 235}
variant={themeStore.hueValue === 235 ? 'outline' : 'accent'}
size="sm"
className="flex items-center gap-1"
onClick={() => {
hueSliderHandler(235);
}}
<Heading title={t('appearance')} description={t('appearance_description')} />
<HorizontalScroll className="!mb-5 mt-4 !pl-0">
<div className="flex gap-3 md:w-[300px] lg:w-full">
{themes.map((theme, i) => {
return (
<div
onClick={() => themeSelectHandler(theme.themeValue)}
className={clsx(
'shrink-0',
selectedTheme !== theme.themeValue &&
'opacity-70 transition-all duration-300 hover:opacity-100'
)}
key={i}
>
{t('reset')}
</Button>
</div>
}
/>
<HorizontalScroll className="!mb-5 mt-4 !pl-0">
<div className="flex gap-3 md:w-[300px] lg:w-full">
{themes.map((theme, i) => {
return (
<div
onClick={() => themeSelectHandler(theme.themeValue)}
className={clsx(
'shrink-0',
selectedTheme !== theme.themeValue &&
'opacity-70 transition-all duration-300 hover:opacity-100'
)}
key={i}
>
{theme.themeValue === 'system' ? (
<SystemTheme
{...theme}
isSelected={selectedTheme === 'system'}
/>
) : (
<Theme
{...theme}
isSelected={selectedTheme === theme.themeValue}
/>
)}
</div>
);
})}
</div>
</HorizontalScroll>
{theme.themeValue === 'system' ? (
<SystemTheme
{...theme}
isSelected={selectedTheme === 'system'}
/>
) : (
<Theme
{...theme}
isSelected={selectedTheme === theme.themeValue}
/>
)}
</div>
);
})}
</div>
</HorizontalScroll>
{/* {themeStore.theme === 'dark' && (
{/* {themeStore.theme === 'dark' && (
<Setting mini title="Theme hue value" description="Change the hue of the theme">
<div className="mr-3 w-full max-w-[200px] justify-between gap-5">
<div className="w-full">
@ -184,7 +155,7 @@ export const Component = () => {
</Setting>
)} */}
<div className="flex flex-col gap-4">
{/* <div className="flex flex-col gap-4">
<Setting
mini
title={t('ui_animations')}
@ -210,9 +181,51 @@ export const Component = () => {
className="m-2 ml-4"
/>
</Setting>
</div> */}
{/* Language Settings */}
<Setting mini title={t('language')} description={t('language_description')}>
<div className="flex h-[30px] gap-2">
<Select
value={i18n.resolvedLanguage || i18n.language || 'en'}
onChange={(e) => {
// add "i18nextLng" key to localStorage and set it to the selected language
localStorage.setItem('i18nextLng', e);
i18n.changeLanguage(e);
setDateFormats(generateLocaleDateFormats(e));
}}
containerClassName="h-[30px] whitespace-nowrap"
>
{LANGUAGE_OPTIONS.map((lang, key) => (
<SelectOption key={key} value={lang.value}>
{lang.label}
</SelectOption>
))}
</Select>
</div>
</Form>
<Divider />
</Setting>
{/* Date Formatting Settings */}
<Setting mini title={t('date_format')} description={t('date_format_description')}>
<div className="flex h-[30px] gap-2">
<Select
value={dateFormat}
onChange={(e) => {
// add "dateFormat" key to localStorage and set it as default date format
localStorage.setItem('sd-date-format', e);
setDateFormat(e);
}}
containerClassName="h-[30px] whitespace-nowrap"
>
{dateFormats.map((format, key) => (
<SelectOption key={key} value={format.value}>
{format.label}
</SelectOption>
))}
</Select>
</div>
</Setting>
{/* <Divider /> */}
<div className="flex flex-col gap-4">
<h1 className="mb-3 text-lg font-bold text-ink">{t('default_settings')}</h1>
<Setting
@ -230,10 +243,9 @@ export const Component = () => {
</Select>
</Setting>
</div>
<Divider />
{/* <Divider />
<div className="flex flex-col gap-4">
<h1 className="mb-3 text-lg font-bold text-ink">{t('display_formats')}</h1>
<Setting mini title={t('coordinates')}>
<Select
onChange={(e) => (unitFormatStore.coordinatesFormat = e)}
@ -263,7 +275,7 @@ export const Component = () => {
<SelectOption value="fahrenheit">{t('fahrenheit')}</SelectOption>
</Select>
</Setting>
</div>
</div> */}
</>
);
};

View file

@ -1,6 +1,4 @@
import clsx from 'clsx';
import dayjs from 'dayjs';
import { useState } from 'react';
import { FormProvider } from 'react-hook-form';
import {
useBridgeMutation,
@ -11,38 +9,16 @@ import {
useZodForm
} from '@sd/client';
import { Button, Card, Input, Select, SelectOption, Slider, Switch, tw, z } from '@sd/ui';
import i18n from '~/app/I18n';
import { Icon } from '~/components';
import { useDebouncedFormWatch, useLocale } from '~/hooks';
import { usePlatform } from '~/util/Platform';
import { generateLocaleDateFormats } from '../../Explorer/util';
import { Heading } from '../Layout';
import Setting from '../Setting';
const NodePill = tw.div`px-1.5 py-[2px] rounded text-xs font-medium bg-app-selected`;
const NodeSettingLabel = tw.div`mb-1 text-xs font-medium`;
// Unsorted list of languages available in the app.
const LANGUAGE_OPTIONS = [
{ value: 'en', label: 'English (US)' },
{ value: 'en_gb', label: 'English (UK)' },
{ value: 'de', label: 'Deutsch' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'tr', label: 'Türkçe' },
{ value: 'nl', label: 'Nederlands' },
{ value: 'be', label: 'Беларуская' },
{ value: 'ru', label: 'Русский' },
{ value: 'zh_CN', label: '中文(简体)' },
{ value: 'zh_TW', label: '中文(繁體)' },
{ value: 'it', label: 'Italiano' },
{ value: 'ja', label: '日本語' }
];
// Sort the languages by their label
LANGUAGE_OPTIONS.sort((a, b) => a.label.localeCompare(b.label));
const u16 = () => z.number().min(0).max(65535);
export const Component = () => {
@ -54,9 +30,7 @@ export const Component = () => {
// const image_labeler_versions = useBridgeQuery(['models.image_detection.list']);
const updateThumbnailerPreferences = useBridgeMutation('nodes.updateThumbnailerPreferences');
const [dateFormats, setDateFormats] = useState(
generateLocaleDateFormats(i18n.resolvedLanguage || i18n.language || 'en')
);
const { t } = useLocale();
const form = useZodForm({
schema: z
@ -132,8 +106,6 @@ export const Component = () => {
}
});
const { t, dateFormat, setDateFormat } = useLocale();
const isP2PWipFeatureEnabled = useFeatureFlag('wipP2P');
return (
@ -230,48 +202,6 @@ export const Component = () => {
</div> */}
</div>
</Card>
{/* Language Settings */}
<Setting mini title={t('language')} description={t('language_description')}>
<div className="flex h-[30px] gap-2">
<Select
value={i18n.resolvedLanguage || i18n.language || 'en'}
onChange={(e) => {
// add "i18nextLng" key to localStorage and set it to the selected language
localStorage.setItem('i18nextLng', e);
i18n.changeLanguage(e);
setDateFormats(generateLocaleDateFormats(e));
}}
containerClassName="h-[30px] whitespace-nowrap"
>
{LANGUAGE_OPTIONS.map((lang, key) => (
<SelectOption key={key} value={lang.value}>
{lang.label}
</SelectOption>
))}
</Select>
</div>
</Setting>
{/* Date Formatting Settings */}
<Setting mini title={t('date_format')} description={t('date_format_description')}>
<div className="flex h-[30px] gap-2">
<Select
value={dateFormat}
onChange={(e) => {
// add "dateFormat" key to localStorage and set it as default date format
localStorage.setItem('sd-date-format', e);
setDateFormat(e);
}}
containerClassName="h-[30px] whitespace-nowrap"
>
{dateFormats.map((format, key) => (
<SelectOption key={key} value={format.value}>
{format.label}
</SelectOption>
))}
</Select>
</div>
</Setting>
{/* Debug Mode */}
<Setting mini title={t('debug_mode')} description={t('debug_mode_description')}>
<Switch