fix(style): language menu

This commit is contained in:
jialin
2024-07-08 14:46:33 +08:00
parent 01e9b70f6d
commit 9ad9539b51
13 changed files with 521 additions and 180 deletions
+4 -1
View File
@@ -14,7 +14,10 @@ export default {
Menu: {
iconSize: 16,
iconMarginInlineEnd: 12,
itemHeight: 44
itemHeight: 44,
// itemColor: 'rgba(0,0,0,.88)',
itemHoverBg: 'rgba(0,0,0,0.04)',
itemActiveBg: 'rgba(0,0,0,0.04)'
},
Progress: {
lineBorderRadius: 4
+2 -2
View File
@@ -3,7 +3,7 @@ import useContainerScroll from '@/hooks/use-container-scorll';
import Convert from 'ansi-to-html';
import classNames from 'classnames';
import hasAnsi from 'has-ansi';
import { useEffect, useRef, useState } from 'react';
import { memo, useEffect, useRef, useState } from 'react';
import './index.less';
interface LogsViewerProps {
@@ -75,4 +75,4 @@ const LogsViewer: React.FC<LogsViewerProps> = (props) => {
);
};
export default LogsViewer;
export default memo(LogsViewer);
+4 -1
View File
@@ -17,6 +17,7 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
isInFormItems = true,
variant,
addAfter,
trim = true,
...rest
} = props;
const [isFocus, setIsFocus] = useState(false);
@@ -43,7 +44,9 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
};
const handleChange = (e: any) => {
e.target.value = e.target.value?.trim?.();
if (trim) {
e.target.value = e.target.value?.trim?.();
}
props.onChange?.(e);
};
+1
View File
@@ -8,4 +8,5 @@ export interface SealFormItemProps {
extra?: React.ReactNode;
addAfter?: React.ReactNode;
loading?: React.ReactNode;
trim?: boolean;
}
+45 -5
View File
@@ -49,6 +49,7 @@ html {
--ant-input-active-border-color: #007bff;
--ant-input-hover-border-color: #2997ff;
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
--ant-border-radius-lg: 8px;
// --box-shadow-base: none;
.css-var-rf {
@@ -64,12 +65,14 @@ html {
// --ant-menu-item-selected-bg: var(--color-white-1);
--ant-menu-item-border-radius: 8px;
--ant-menu-item-selected-color: var(--ant-color-primary);
--ant-menu-item-hover-bg: var(--color-white-1);
--ant-menu-item-color: var(--color-text-1);
--ant-menu-item-active-bg: var(--color-white-1);
}
}
.css-var-rj.ant-menu-css-var {
--ant-menu-item-color: var(--color-text-1);
}
.css-var-r0 {
// --ant-control-height: 36px;
--ant-font-size-sm: var(--font-size-base);
@@ -109,12 +112,10 @@ html {
.css-var-ri.ant-menu-css-var,
.css-var-rh.ant-menu-css-var {
--ant-menu-item-height: 46px;
// --ant-menu-item-selected-bg: var(--color-white-1);
--ant-menu-item-border-radius: 8px;
--ant-menu-item-selected-color: var(--ant-color-primary);
--ant-menu-item-hover-bg: var(--color-white-1);
--ant-menu-item-color: var(--color-text-1);
--ant-menu-item-active-bg: var(--color-white-1);
--ant-menu-item-active-bg: rgba(0, 0, 0, 4%);
}
.css-var-r0.ant-input-css-var {
@@ -263,6 +264,14 @@ body {
background-color: var(--color-fill-1);
height: 100%;
.ant-pro-sider-actions-list-item {
padding: 0;
&:hover {
background-color: unset;
}
}
.ant-pro-sider-logo {
padding-left: 20px;
}
@@ -374,6 +383,37 @@ body {
}
// ======== menu style end ============
.user-menu-container {
.user-avatar.ant-menu-submenu {
.ant-menu-submenu-title {
padding-left: 8px;
}
}
&.user-menu-collapsed {
.user-avatar.ant-menu-submenu {
.ant-menu-submenu-title {
padding: 0 !important;
display: flex;
justify-content: center;
.ant-menu-title-content {
display: none;
}
}
}
}
.ant-menu-submenu-title {
display: flex;
justify-content: flex-start;
align-items: center;
}
}
.ant-menu-submenu-popup > .ant-menu {
border-radius: var(--menu-border-radius-base);
}
// ======== monaco editor style ============
.monaco-editor {
border-radius: 16px;
+13 -24
View File
@@ -216,30 +216,19 @@ export default (props: any) => {
fixSiderbar
fixedHeader
{...runtimeConfig}
rightContentRender={
runtimeConfig.rightContentRender !== false &&
((layoutProps) => {
const dom = getRightRenderContent({
runtimeConfig,
loading,
initialState,
setInitialState,
intl
});
if (runtimeConfig.rightContentRender) {
return runtimeConfig.rightContentRender(layoutProps, dom, {
// BREAK CHANGE userConfig > runtimeConfig
userConfig,
runtimeConfig,
loading,
initialState,
setInitialState,
intl
});
}
return dom;
})
}
actionsRender={(layoutProps) => {
const dom = getRightRenderContent({
runtimeConfig,
loading,
initialState,
setInitialState,
intl,
siderWidth: layoutProps.siderWidth,
collapsed: layoutProps.collapsed
});
return dom;
}}
>
<Exception
route={matchedRoute}
+3 -41
View File
@@ -1,8 +1,4 @@
import {
AppstoreOutlined,
MailOutlined,
SettingOutlined
} from '@ant-design/icons';
import { MailOutlined } from '@ant-design/icons';
import { Menu, type MenuProps } from 'antd';
import React from 'react';
@@ -15,47 +11,13 @@ const items: MenuItem[] = [
children: [
{
key: '1-1',
label: 'Item 1',
type: 'group',
children: [
{ key: '1', label: 'Option 1' },
{ key: '2', label: 'Option 2' }
]
label: 'Item 1'
},
{
key: '1-2',
label: 'Item 2',
type: 'group',
children: [
{ key: '3', label: 'Option 3' },
{ key: '4', label: 'Option 4' }
]
label: 'Item 2'
}
]
},
{
key: 'sub2',
icon: <AppstoreOutlined />,
label: 'Navigation Two',
children: [
{ key: '5', label: 'Option 5' },
{ key: '6', label: 'Option 6' },
{
key: 'sub3',
label: 'Submenu'
}
]
},
{
key: 'sub4',
label: 'Navigation Three',
icon: <SettingOutlined />,
children: [
{ key: '9', label: 'Option 9' },
{ key: '10', label: 'Option 10' },
{ key: '11', label: 'Option 11' },
{ key: '12', label: 'Option 12' }
]
}
];
+115 -103
View File
@@ -1,22 +1,27 @@
// @ts-nocheck
import avatarImg from '@/assets/images/avatar.png';
import langConfigMap from '@/locales/lang-config-map';
import {
GlobalOutlined,
LogoutOutlined,
SettingOutlined
} from '@ant-design/icons';
import { SelectLang, history } from '@umijs/max';
import { Avatar, Dropdown, Menu, Spin, version } from 'antd';
import { getAllLocales, history, setLocale } from '@umijs/max';
import { Avatar, Menu, Spin } from 'antd';
import _ from 'lodash';
export function getRightRenderContent(opts: {
runtimeConfig: any;
loading: boolean;
initialState: any;
collapsed: boolean;
setInitialState: any;
siderWidth: number;
intl: any;
}) {
const { intl } = opts;
const { intl, collapsed, siderWidth } = opts;
const allLocals = getAllLocales();
if (opts.runtimeConfig.rightRender) {
return opts.runtimeConfig.rightRender(
opts.initialState,
@@ -57,118 +62,125 @@ export function getRightRenderContent(opts: {
);
}
const renderExtraActions = () => {
return (
<SelectLang
style={{ padding: '10px 18px', marginBottom: '20px' }}
reload={false}
mode="vertical"
icon={
<span style={{ fontSize: '12px' }}>
<GlobalOutlined />
<span className="m-l-8">
{intl?.formatMessage?.({ id: 'common.settings.language' })}
</span>
</span>
}
></SelectLang>
);
};
// 如果没有打开Locale,并且头像为空就取消掉这个返回的内容
if (!avatar) return null;
const renderMenu = () => {
return (
<Menu triggerSubMenuAction="hover">
<Menu.Item title="admin" key="avatar">
<ul>
<Menu.SubMenu
key="settings"
icon={<SettingOutlined />}
title={intl?.formatMessage?.({ id: 'common.button.settings' })}
></Menu.SubMenu>
<Menu.SubMenu
key="logout"
icon={<LogoutOutlined />}
title={intl?.formatMessage?.({ id: 'common.button.logout' })}
></Menu.SubMenu>
</ul>
</Menu.Item>
</Menu>
);
};
const langMenu = {
className: 'umi-plugin-layout-menu',
selectedKeys: [],
className: collapsed
? 'user-menu-container user-menu-collapsed'
: 'user-menu-container',
mode: 'vertical',
expandIcon: false,
inlineCollapsed: collapsed,
triggerSubMenuAction: 'hover',
items: [
{
key: 'settings',
key: 'lang',
icon: <GlobalOutlined />,
label: (
<>
<SettingOutlined />
{intl?.formatMessage?.({ id: 'common.button.settings' })}
</>
<span>
{intl?.formatMessage?.({ id: 'common.settings.language' })}
</span>
),
onClick: () => {
history.push('/profile');
}
},
{
key: 'logout',
label: (
<>
<LogoutOutlined />
{intl?.formatMessage?.({ id: 'common.button.logout' })}
</>
),
onClick: () => {
opts?.runtimeConfig?.logout?.(opts.initialState.currentUser);
}
children: allLocals.map((key) => ({
key,
label: (
<span className="flex flex-center">
<span>{_.get(langConfigMap, [key, 'icon'])}</span>
<span className="m-l-8">
{_.get(langConfigMap, [key, 'label'])}
</span>
</span>
),
onClick: () => {
setLocale(key, false);
}
}))
}
]
};
// antd@5 和 4.24 之后推荐使用 menu,性能更好
let dropdownProps;
if (version.startsWith('5.') || version.startsWith('4.24.')) {
dropdownProps = { menu: langMenu, mode: 'vertical' };
} else if (version.startsWith('3.')) {
dropdownProps = {
overlay: (
<Menu>
{langMenu.items.map((item) => (
<Menu.Item key={item.key} onClick={item.onClick}>
{item.label}
</Menu.Item>
))}
</Menu>
)
};
} else {
// 需要 antd 4.20.0 以上版本
dropdownProps = {
overlay: <Menu {...langMenu} mode="vertical" />
};
}
const userMenu = {
selectedKeys: [],
className: collapsed
? 'user-menu-container user-menu-collapsed'
: 'user-menu-container',
mode: 'vertical',
expandIcon: false,
inlineCollapsed: collapsed,
triggerSubMenuAction: 'hover',
items: [
{
label: '',
key: 'user',
className: 'user-avatar',
icon: (
<span>
<Avatar
size={28}
style={{
color: 'var(--ant-color-text)'
}}
>
{_.toUpper(opts.initialState?.currentUser?.username?.charAt(0))}
</Avatar>
{!collapsed && (
<span
className="m-l-8 font-size-14"
style={{ fontWeight: 'var(--font-weight-normal)' }}
>
{opts.initialState?.currentUser?.username}
</span>
)}
</span>
),
children: [
{
key: 'settings',
label: (
<span className="flex flex-center">
<SettingOutlined />
<span>
{intl?.formatMessage?.({ id: 'common.button.settings' })}
</span>
</span>
),
onClick: () => {
history.push('/profile');
}
},
{
key: 'logout',
label: (
<span className="flex flex-center">
<LogoutOutlined />
<span>
{intl?.formatMessage?.({ id: 'common.button.logout' })}
</span>
</span>
),
onClick: () => {
opts?.runtimeConfig?.logout?.(opts.initialState.currentUser);
}
}
]
}
]
};
return (
<div style={{ width: '100%' }}>
{renderExtraActions()}
<div className="umi-plugin-layout-right anticon">
{opts.runtimeConfig.logout ? (
<>
<Dropdown
{...dropdownProps}
overlayClassName="umi-plugin-layout-container"
>
{avatar}
</Dropdown>
</>
) : (
avatar
)}
</div>
<div>
<Menu
{...langMenu}
style={{
width: collapsed ? 64 : `calc(${siderWidth}px - 16px)`
}}
></Menu>
<Menu
{...userMenu}
style={{
width: collapsed ? 64 : `calc(${siderWidth}px - 16px)`,
marginTop: 20
}}
></Menu>
</div>
);
}
+326
View File
@@ -0,0 +1,326 @@
export default {
'ar-EG': {
lang: 'ar-EG',
label: 'العربية',
icon: '🇪🇬',
title: 'لغة'
},
'az-AZ': {
lang: 'az-AZ',
label: 'Azərbaycan dili',
icon: '🇦🇿',
title: 'Dil'
},
'bg-BG': {
lang: 'bg-BG',
label: 'Български език',
icon: '🇧🇬',
title: 'език'
},
'bn-BD': {
lang: 'bn-BD',
label: 'বাংলা',
icon: '🇧🇩',
title: 'ভাষা'
},
'ca-ES': {
lang: 'ca-ES',
label: 'Catalá',
icon: '🇨🇦',
title: 'llengua'
},
'cs-CZ': {
lang: 'cs-CZ',
label: 'Čeština',
icon: '🇨🇿',
title: 'Jazyk'
},
'da-DK': {
lang: 'da-DK',
label: 'Dansk',
icon: '🇩🇰',
title: 'Sprog'
},
'de-DE': {
lang: 'de-DE',
label: 'Deutsch',
icon: '🇩🇪',
title: 'Sprache'
},
'el-GR': {
lang: 'el-GR',
label: 'Ελληνικά',
icon: '🇬🇷',
title: 'Γλώσσα'
},
'en-GB': {
lang: 'en-GB',
label: 'English',
icon: '🇬🇧',
title: 'Language'
},
'en-US': {
lang: 'en-US',
label: 'English',
icon: '🇺🇸',
title: 'Language'
},
'es-ES': {
lang: 'es-ES',
label: 'Español',
icon: '🇪🇸',
title: 'Idioma'
},
'et-EE': {
lang: 'et-EE',
label: 'Eesti',
icon: '🇪🇪',
title: 'Keel'
},
'fa-IR': {
lang: 'fa-IR',
label: 'فارسی',
icon: '🇮🇷',
title: 'زبان'
},
'fi-FI': {
lang: 'fi-FI',
label: 'Suomi',
icon: '🇫🇮',
title: 'Kieli'
},
'fr-BE': {
lang: 'fr-BE',
label: 'Français',
icon: '🇧🇪',
title: 'Langue'
},
'fr-FR': {
lang: 'fr-FR',
label: 'Français',
icon: '🇫🇷',
title: 'Langue'
},
'ga-IE': {
lang: 'ga-IE',
label: 'Gaeilge',
icon: '🇮🇪',
title: 'Teanga'
},
'he-IL': {
lang: 'he-IL',
label: 'עברית',
icon: '🇮🇱',
title: 'שפה'
},
'hi-IN': {
lang: 'hi-IN',
label: 'हिन्दी, हिंदी',
icon: '🇮🇳',
title: 'भाषा: हिन्दी'
},
'hr-HR': {
lang: 'hr-HR',
label: 'Hrvatski jezik',
icon: '🇭🇷',
title: 'Jezik'
},
'hu-HU': {
lang: 'hu-HU',
label: 'Magyar',
icon: '🇭🇺',
title: 'Nyelv'
},
'hy-AM': {
lang: 'hu-HU',
label: 'Հայերեն',
icon: '🇦🇲',
title: 'Լեզու'
},
'id-ID': {
lang: 'id-ID',
label: 'Bahasa Indonesia',
icon: '🇮🇩',
title: 'Bahasa'
},
'it-IT': {
lang: 'it-IT',
label: 'Italiano',
icon: '🇮🇹',
title: 'Linguaggio'
},
'is-IS': {
lang: 'is-IS',
label: 'Íslenska',
icon: '🇮🇸',
title: 'Tungumál'
},
'ja-JP': {
lang: 'ja-JP',
label: '日本語',
icon: '🇯🇵',
title: '言語'
},
'ku-IQ': {
lang: 'ku-IQ',
label: 'کوردی',
icon: '🇮🇶',
title: 'Ziman'
},
'kn-IN': {
lang: 'kn-IN',
label: 'ಕನ್ನಡ',
icon: '🇮🇳',
title: 'ಭಾಷೆ'
},
'ko-KR': {
lang: 'ko-KR',
label: '한국어',
icon: '🇰🇷',
title: '언어'
},
'lv-LV': {
lang: 'lv-LV',
label: 'Latviešu valoda',
icon: '🇱🇮',
title: 'Kalba'
},
'mk-MK': {
lang: 'mk-MK',
label: 'македонски јазик',
icon: '🇲🇰',
title: 'Јазик'
},
'mn-MN': {
lang: 'mn-MN',
label: 'Монгол хэл',
icon: '🇲🇳',
title: 'Хэл'
},
'ms-MY': {
lang: 'ms-MY',
label: 'بهاس ملايو‎',
icon: '🇲🇾',
title: 'Bahasa'
},
'nb-NO': {
lang: 'nb-NO',
label: 'Norsk',
icon: '🇳🇴',
title: 'Språk'
},
'ne-NP': {
lang: 'ne-NP',
label: 'नेपाली',
icon: '🇳🇵',
title: 'भाषा'
},
'nl-BE': {
lang: 'nl-BE',
label: 'Vlaams',
icon: '🇧🇪',
title: 'Taal'
},
'nl-NL': {
lang: 'nl-NL',
label: 'Nederlands',
icon: '🇳🇱',
title: 'Taal'
},
'pl-PL': {
lang: 'pl-PL',
label: 'Polski',
icon: '🇵🇱',
title: 'Język'
},
'pt-BR': {
lang: 'pt-BR',
label: 'Português',
icon: '🇧🇷',
title: 'Idiomas'
},
'pt-PT': {
lang: 'pt-PT',
label: 'Português',
icon: '🇵🇹',
title: 'Idiomas'
},
'ro-RO': {
lang: 'ro-RO',
label: 'Română',
icon: '🇷🇴',
title: 'Limba'
},
'ru-RU': {
lang: 'ru-RU',
label: 'Русский',
icon: '🇷🇺',
title: 'язык'
},
'sk-SK': {
lang: 'sk-SK',
label: 'Slovenčina',
icon: '🇸🇰',
title: 'Jazyk'
},
'sr-RS': {
lang: 'sr-RS',
label: 'српски језик',
icon: '🇸🇷',
title: 'Језик'
},
'sl-SI': {
lang: 'sl-SI',
label: 'Slovenščina',
icon: '🇸🇱',
title: 'Jezik'
},
'sv-SE': {
lang: 'sv-SE',
label: 'Svenska',
icon: '🇸🇪',
title: 'Språk'
},
'ta-IN': {
lang: 'ta-IN',
label: 'தமிழ்',
icon: '🇮🇳',
title: 'மொழி'
},
'th-TH': {
lang: 'th-TH',
label: 'ไทย',
icon: '🇹🇭',
title: 'ภาษา'
},
'tr-TR': {
lang: 'tr-TR',
label: 'Türkçe',
icon: '🇹🇷',
title: 'Dil'
},
'uk-UA': {
lang: 'uk-UA',
label: 'Українська',
icon: '🇺🇰',
title: 'Мова'
},
'vi-VN': {
lang: 'vi-VN',
label: 'Tiếng Việt',
icon: '🇻🇳',
title: 'Ngôn ngữ'
},
'zh-CN': {
lang: 'zh-CN',
label: '简体中文',
icon: '🇨🇳',
title: '语言'
},
'zh-TW': {
lang: 'zh-TW',
label: '繁體中文',
icon: '🇭🇰',
title: '語言'
}
};
+4
View File
@@ -9,6 +9,10 @@
:global(.field-wrapper) {
background-color: transparent !important;
}
:global(.ant-input-outlined.ant-input-status-error:not(.ant-input-disabled)) {
background-color: transparent !important;
}
}
:local(.box) {
@@ -7,7 +7,7 @@ interface ReferenceParamsProps {
completion_tokens: number;
prompt_tokens: number;
total_tokens: number;
time_per_output_token_ms: number;
tokens_per_second: number;
};
}
@@ -43,7 +43,7 @@ const ReferenceParams = (props: ReferenceParamsProps) => {
<span>
{intl.formatMessage({ id: 'playground.tokenoutput' })}:{' '}
{usage.time_per_output_token_ms * 1000} Tokens/s
{usage.tokens_per_second * 1000} Tokens/s
</span>
</div>
);
@@ -53,7 +53,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const systemList = systemMessage
? [{ role: 'system', content: systemMessage }]
: [];
const code = `curl ${window.location.origin}/v1-openai/chat/completions \\ \n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
const code = `curl ${window.location.origin}/v1-openai/chat/completions \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
{
...parameters,
messages: [...systemList, ...messageList]
+1
View File
@@ -88,6 +88,7 @@ const AddModal: React.FC<AddModalProps> = ({
</Form.Item>
<Form.Item<FormData> name="full_name" rules={[{ required: false }]}>
<SealInput.Input
trim={false}
label={intl.formatMessage({ id: 'users.form.fullname' })}
></SealInput.Input>
</Form.Item>