refactor(perferences): use center wrapper layout
This commit is contained in:
@@ -1,92 +1,150 @@
|
||||
import useUserSettings from '@/hooks/use-user-settings';
|
||||
import langConfigMap from '@/locales/lang-config-map';
|
||||
import { MoonOutlined, SunOutlined } from '@ant-design/icons';
|
||||
import { CheckCircleFilled } from '@ant-design/icons';
|
||||
import { BaseSelect } from '@gpustack/core-ui';
|
||||
import { getAllLocales, setLocale, useIntl } from '@umijs/max';
|
||||
import { createStyles } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 16px 0;
|
||||
`;
|
||||
import { SettingRow, SettingsGroup } from './settings-group';
|
||||
import ThemePreview, { PreviewMode } from './theme-preview';
|
||||
|
||||
const SettingsItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
max-width: 300px;
|
||||
.label {
|
||||
const useStyles = createStyles(({ token, css }) => ({
|
||||
cards: css`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
`,
|
||||
card: css`
|
||||
padding: 8px;
|
||||
border: 1px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadiusLG + 2}px;
|
||||
background: ${token.colorBgContainer};
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: ${token.colorPrimaryBorderHover};
|
||||
}
|
||||
`,
|
||||
cardActive: css`
|
||||
border-color: ${token.colorPrimary};
|
||||
box-shadow: 0 0 0 1px ${token.colorPrimary};
|
||||
`,
|
||||
meta: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 8px 6px;
|
||||
`,
|
||||
label: css`
|
||||
font-size: 14px;
|
||||
font-weight: var(--font-weight-500);
|
||||
}
|
||||
`;
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: ${token.colorText};
|
||||
`,
|
||||
check: css`
|
||||
font-size: 18px;
|
||||
color: ${token.colorPrimary};
|
||||
`,
|
||||
radio: css`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid ${token.colorBorder};
|
||||
`
|
||||
}));
|
||||
|
||||
const Appearance: React.FC = () => {
|
||||
const { setTheme, userSettings } = useUserSettings();
|
||||
|
||||
const intl = useIntl();
|
||||
const { styles } = useStyles();
|
||||
const allLocals = getAllLocales();
|
||||
|
||||
const ThemeOptions = [
|
||||
const themeOptions: { value: PreviewMode; label: string }[] = [
|
||||
{
|
||||
value: 'light',
|
||||
label: intl.formatMessage({ id: 'common.appearance.light' }),
|
||||
icon: <SunOutlined />
|
||||
label: intl.formatMessage({ id: 'common.appearance.lightmode' })
|
||||
},
|
||||
{
|
||||
value: 'realDark',
|
||||
label: intl.formatMessage({ id: 'common.appearance.dark' }),
|
||||
icon: <MoonOutlined />
|
||||
label: intl.formatMessage({ id: 'common.appearance.darkmode' })
|
||||
},
|
||||
{
|
||||
value: 'auto',
|
||||
label: intl.formatMessage({ id: 'common.appearance.system' }),
|
||||
icon: <SunOutlined />
|
||||
label: intl.formatMessage({ id: 'common.appearance.system' })
|
||||
}
|
||||
];
|
||||
|
||||
const handleOnChange = (value: 'light' | 'realDark' | 'auto') => {
|
||||
setTheme(value);
|
||||
};
|
||||
|
||||
const languageOptions = allLocals.map((locale) => ({
|
||||
value: locale,
|
||||
label: _.get(langConfigMap, [locale, 'label'])
|
||||
}));
|
||||
|
||||
const handleSelectTheme = (value: PreviewMode) => {
|
||||
setTheme(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<SettingsItem>
|
||||
<span className="label">
|
||||
<span>{intl.formatMessage({ id: 'common.appearance.theme' })}</span>
|
||||
</span>
|
||||
<BaseSelect
|
||||
defaultValue={'light'}
|
||||
value={userSettings.mode}
|
||||
options={ThemeOptions}
|
||||
onChange={handleOnChange}
|
||||
style={{ width: 200 }}
|
||||
></BaseSelect>
|
||||
</SettingsItem>
|
||||
<SettingsItem>
|
||||
<span className="label">
|
||||
<span>{intl.formatMessage({ id: 'common.settings.language' })}</span>
|
||||
</span>
|
||||
<BaseSelect
|
||||
value={intl.locale}
|
||||
options={languageOptions}
|
||||
onChange={(value) => {
|
||||
setLocale(value, false);
|
||||
}}
|
||||
style={{ width: 200 }}
|
||||
></BaseSelect>
|
||||
</SettingsItem>
|
||||
</Wrapper>
|
||||
<SettingsGroup>
|
||||
<SettingRow
|
||||
title={intl.formatMessage({ id: 'common.appearance.theme' })}
|
||||
description={intl.formatMessage({ id: 'common.appearance.tips' })}
|
||||
>
|
||||
<div className={styles.cards}>
|
||||
{themeOptions.map((option) => {
|
||||
const active = userSettings.mode === option.value;
|
||||
return (
|
||||
<div
|
||||
key={option.value}
|
||||
role="radio"
|
||||
aria-checked={active}
|
||||
tabIndex={0}
|
||||
className={classNames(styles.card, {
|
||||
[styles.cardActive]: active
|
||||
})}
|
||||
onClick={() => handleSelectTheme(option.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
handleSelectTheme(option.value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ThemePreview mode={option.value} />
|
||||
<div className={styles.meta}>
|
||||
<span className={styles.label}>{option.label}</span>
|
||||
{active ? (
|
||||
<CheckCircleFilled className={styles.check} />
|
||||
) : (
|
||||
<span className={styles.radio} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
title={intl.formatMessage({ id: 'common.settings.language' })}
|
||||
description={intl.formatMessage({
|
||||
id: 'common.settings.language.tips'
|
||||
})}
|
||||
extra={
|
||||
<BaseSelect
|
||||
value={intl.locale}
|
||||
options={languageOptions}
|
||||
onChange={(value: string) => {
|
||||
setLocale(value, false);
|
||||
}}
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsGroup>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user