refactor: ui/ux

This commit is contained in:
jialin
2026-04-08 18:54:06 +08:00
committed by jialin
parent 06160546a6
commit 1c09cc6c8c
22 changed files with 325 additions and 167 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
export const HEADER_HEIGHT = 56;
export const HEADER_HEIGHT = 48;
export const DEFAULT_ENTER_PAGE = {
adminForNormal: '/dashboard',
+3
View File
@@ -4,6 +4,9 @@ export default {
'root-entry-name': 'variable',
hashed: false,
components: {
Layout: {
headerHeight: 48
},
Input: {
inputFontSize: 14,
inputFontSizeLG: 14
+12 -4
View File
@@ -4,6 +4,8 @@
@import url('./overrides.less');
html {
--page-header-height: 56px;
--page-content-padding: 8px;
--color-text-light-1: rgba(255, 255, 255, 90%);
--color-fill-1: var(--ant-color-bg-container);
--color-scrollbar-thumb: rgba(193, 193, 193, 80%);
@@ -22,8 +24,8 @@ html {
--color-fill-3: #f3f6fa;
--color-logs-bg: #1e1e1e;
--color-logs-text: #d4d4d4;
--layout-content-blockpadding: 32px;
--layout-content-inlinepadding: 32px;
--layout-content-blockpadding: 24px;
--layout-content-inlinepadding: 24px;
--layout-content-header-inlinepadding: 40px;
--border-radius-modal: 12px;
--menu-border-radius-base: 4px;
@@ -120,6 +122,8 @@ html[data-theme='light'] {
background-color: #fff !important;
transition: none !important;
}
background-color: #f5f5f5;
}
body {
@@ -275,7 +279,7 @@ body {
}
.ant-pro-sider .ant-layout-sider-children {
border-right: 1px solid var(--ant-color-split);
// border-right: 1px solid var(--ant-color-split);
}
}
@@ -336,7 +340,7 @@ body {
.ant-pro-layout-container {
overflow-x: auto;
min-height: 100vh;
background-color: var(--ant-color-bg-container);
// background-color: var(--ant-color-bg-container);
}
.ant-pro-sider {
@@ -819,3 +823,7 @@ body {
.ant-drawer .ant-drawer-mask.ant-drawer-mask-blur {
backdrop-filter: blur(2px);
}
.ant-pro-grid-content {
padding-right: 8px;
}
+1 -1
View File
@@ -60,7 +60,7 @@ const Wrapper = styled.div`
display: flex;
align-items: center;
gap: 24px;
height: 40px;
height: 32px;
`;
const DropdownWrapper = styled.div`
min-width: 160px;
+28 -6
View File
@@ -215,10 +215,28 @@ export default (props: any) => {
}, [matchedRoute]);
useEffect(() => {
const body = document.querySelector('body');
if (body) {
const ins = initialize(body);
window.__GPUSTACK_BODY_SCROLLER__ = ins;
const initializeScroller = () => {
// const body = document.querySelector('.ant-pro-grid-content-children');
// if (body) {
// const ins = initialize(body);
// window.__GPUSTACK_BODY_SCROLLER__ = ins;
// return true;
// }
// return false;
return true;
};
// Try to initialize immediately
if (!initializeScroller()) {
// If element not found, retry with requestAnimationFrame
const rafId = requestAnimationFrame(() => {
if (!initializeScroller()) {
// If still not found, retry after a short delay
const timeoutId = setTimeout(initializeScroller, 100);
return () => clearTimeout(timeoutId);
}
});
return () => cancelAnimationFrame(rafId);
}
}, [initialize]);
@@ -312,6 +330,8 @@ export default (props: any) => {
});
};
console.log('userConfig==========title', userConfig.title);
return (
<ConfigProvider
componentSize="large"
@@ -336,7 +356,7 @@ export default (props: any) => {
<DarkMask></DarkMask>
<ProLayout
fixSiderbar
fixedHeader={true}
fixedHeader={false}
breadcrumbRender={false}
route={route}
location={location}
@@ -384,7 +404,9 @@ export default (props: any) => {
<Outlet />
) : (
<PageContainerInner>
<Outlet />
<div>
<Outlet />
</div>
</PageContainerInner>
)}
</Exception>
+54 -31
View File
@@ -1,44 +1,67 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import {
PageContainer,
RouteContext,
type PageContainerProps
} from '@ant-design/pro-components';
import styled from 'styled-components';
import classNames from 'classnames';
import { useContext, useEffect, useRef } from 'react';
import pageBoxCss from './styles/page-box.less';
const paddingInlinePageContainerContent = 32;
const paddingInlinePageContainerContent = 24;
const StyledPageContainer = styled(PageContainer)`
.ant-affix {
top: 0 !important;
height: auto;
export const PageContainerInner: React.FC<
PageContainerProps & {
leftContent?: React.ReactNode;
rightContent?: React.ReactNode;
styles?: {
containerWrapper?: React.CSSProperties;
};
}
.ant-page-header {
padding-block-end: 8px;
.ant-page-header-heading {
padding-block-start: 0;
> = ({ children, styles, title, leftContent, rightContent, ...rest }) => {
const { initialize: initialize } = useOverlayScroller({
defer: false
});
const pageContext = useContext(RouteContext);
const contentWrapperRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (contentWrapperRef.current) {
const ins = initialize(contentWrapperRef.current);
window.__GPUSTACK_BODY_SCROLLER__ = ins;
}
}
.ant-pro-page-container-warp-page-header {
padding-inline: ${paddingInlinePageContainerContent}px;
}
.ant-page-header-heading-title {
font-size: 16px;
}
`;
}, [initialize, contentWrapperRef]);
export const PageContainerInner: React.FC<PageContainerProps> = ({
children,
...rest
}) => {
return (
<StyledPageContainer
{...rest}
fixedHeader={true}
token={{
paddingInlinePageContainerContent: paddingInlinePageContainerContent
}}
>
{children}
</StyledPageContainer>
<div className={pageBoxCss.containerWrapper}>
<PageContainer
{...rest}
fixedHeader={false}
title={false}
style={{
flex: 1
}}
token={{
paddingInlinePageContainerContent: paddingInlinePageContainerContent
}}
>
<div className={pageBoxCss.title}>
<div className={pageBoxCss.left}>
{leftContent || pageContext.title}
</div>
{rightContent && (
<div className={pageBoxCss.right}>{rightContent}</div>
)}
</div>
<div
className={classNames(pageBoxCss.contentWrapper)}
style={styles?.containerWrapper}
ref={contentWrapperRef}
>
{children}
</div>
</PageContainer>
</div>
);
};
@@ -0,0 +1,62 @@
.containerWrapper {
:global {
.ant-affix {
top: 0 !important;
height: auto;
}
.ant-page-header {
padding-block-end: 8px;
.ant-page-header-heading {
padding-block-start: 0;
}
}
.ant-page-header-heading-title {
font-size: 16px;
}
.ant-pro-page-container-children-container {
height: calc(100vh - 56px);
display: flex;
flex-direction: column;
border: 1px solid rgb(237, 237, 237);
border-radius: 8px;
overflow: hidden;
background-color: var(--ant-color-bg-container);
padding: 0;
}
}
.contentWrapper {
flex: 1;
overflow-y: auto;
padding-block: var(--layout-content-blockpadding);
padding-inline: var(--layout-content-inlinepadding);
}
.title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding-inline: var(--layout-content-inlinepadding);
font-size: 16px;
color: var(--ant-color-text);
font-weight: 600;
padding-block: 9px 8px;
height: 56px;
border-bottom: 1px solid var(--ant-color-split);
.left {
display: flex;
align-items: center;
}
.right {
display: flex;
align-items: center;
}
}
}
+31 -29
View File
@@ -46,34 +46,36 @@ const LLModels: React.FC = () => {
setActiveKey(key);
});
const header = useMemo(() => {
return {
title: (
<div className="flex items-center">
<span className="font-600">
{intl.formatMessage({ id: 'menu.models.deployment' })}
</span>
<Segmented
options={[
{
label: intl.formatMessage({ id: 'models.table.modelView' }),
value: TabsValueMap.ModelView,
icon: <IconFont type={'icon-models'}></IconFont>
},
{
label: intl.formatMessage({ id: 'models.table.instanceView' }),
value: TabsValueMap.InstanceView,
icon: <IconFont type={'icon-instance-outline'}></IconFont>
}
]}
size="middle"
className="m-l-24 font-600"
value={activeKey}
onChange={handleTabChange}
></Segmented>
</div>
)
};
const title = useMemo(() => {
return (
<div className="flex items-center">
<span className="font-600 flex-center">
{intl.formatMessage({ id: 'menu.models.deployment' })}
</span>
<Segmented
shape="round"
style={{
backgroundColor: 'var(--ant-color-fill-secondary)'
}}
size="middle"
className="m-l-24 font-400"
options={[
{
label: intl.formatMessage({ id: 'models.table.modelView' }),
value: TabsValueMap.ModelView,
icon: <IconFont type={'icon-models'}></IconFont>
},
{
label: intl.formatMessage({ id: 'models.table.instanceView' }),
value: TabsValueMap.InstanceView,
icon: <IconFont type={'icon-instance-outline'}></IconFont>
}
]}
value={activeKey}
onChange={handleTabChange}
></Segmented>
</div>
);
}, [activeKey, intl]);
useEffect(() => {
@@ -103,7 +105,7 @@ const LLModels: React.FC = () => {
}, [activeKey]);
return (
<PageContainerInner header={header}>
<PageContainerInner leftContent={title}>
<DeploymentsContext.Provider
value={{
generateFormValues,
@@ -131,7 +131,7 @@ const useProviderColumns = (options: {
{
title: intl.formatMessage({ id: 'clusters.title' }),
dataIndex: 'cluster_id',
minWidth: 200,
width: 200,
render: (text: number) => (
<AutoTooltip ghost>
{text
@@ -157,6 +157,7 @@ const useProviderColumns = (options: {
title: intl.formatMessage({ id: 'models.table.vram.allocated' }),
dataIndex: 'allocated_vram',
sorter: tableSorter(6),
width: 160,
render: (text, record) => (
<AutoTooltip ghost>
{convertFileSize(
+41 -22
View File
@@ -1,12 +1,11 @@
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { MessageOutlined, OneToOneOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import { Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
@@ -109,11 +108,11 @@ const Playground: React.FC = () => {
fetchData();
}, []);
const header = useMemo(() => {
return {
title: (
const title = useMemo(() => {
return (
<div className="flex justify-between items-center">
<div className="flex items-center">
<span className="font-600">
<span className="font-600 flex-center">
{intl.formatMessage({ id: 'menu.playground.chat' })}
</span>
{
@@ -126,8 +125,14 @@ const Playground: React.FC = () => {
></Segmented>
}
</div>
)
};
<ViewCodeButtons
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
activeKey={activeKey}
key="view-code-buttons"
/>
</div>
);
}, [activeKey, optionsList, intl]);
useHotkeys(
@@ -148,25 +153,39 @@ const Playground: React.FC = () => {
compare: activeKey === 'compare',
chat: activeKey !== 'compare'
})}
header={header}
extra={[
styles={{
containerWrapper: {
padding: 0
}
}}
leftContent={
<div className="flex items-center">
<span className="font-600 flex-center">
{intl.formatMessage({ id: 'menu.playground.chat' })}
</span>
{
<Segmented
shape="round"
style={{
backgroundColor: 'var(--ant-color-fill-secondary)'
}}
size="middle"
className="m-l-24 font-400"
options={optionsList}
value={activeKey}
onChange={(key) => setActiveKey(key)}
></Segmented>
}
</div>
}
rightContent={
<ViewCodeButtons
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
activeKey={activeKey}
key="view-code-buttons"
/>,
<div key="divider-wrapper">
{activeKey === 'chat' && (
<Divider
key="divider"
orientation="vertical"
style={{ height: 16, marginInline: 16 }}
/>
)}
</div>,
<ExtraContent key="extra-content" />
]}
/>
}
>
<div className="play-ground">
<div className="chat">
@@ -15,7 +15,7 @@ const ViewCodeButtons: React.FC<{
}
return (
<Space key="buttons" style={{ marginRight: 8 }}>
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
+8 -11
View File
@@ -1,9 +1,7 @@
import HotKeys from '@/config/hotkeys';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Divider } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useEffect, useRef, useState } from 'react';
@@ -81,20 +79,19 @@ const PlaygroundEmbedding: React.FC = () => {
return (
<PageContainerInner
className={classNames('playground-container chat')}
extra={[
styles={{
containerWrapper: {
padding: 0
}
}}
rightContent={
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
/>,
<Divider
key="divider"
orientation="vertical"
style={{ height: 16, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
/>
}
>
<div className="play-ground">
<div className="chat">
+1 -1
View File
@@ -622,7 +622,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
className="ground-left-footer"
style={{
width: '100%',
padding: '0 32px 16px'
padding: '0 var(--layout-content-inlinepadding) 16px'
}}
>
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-16">
+23 -12
View File
@@ -1,12 +1,11 @@
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { DiffOutlined, HighlightOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import { Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
@@ -156,21 +155,33 @@ const TextToImages: React.FC = () => {
return (
<PageContainerInner
header={header}
extra={[
leftContent={
<div className="flex items-center">
<span className="font-600 flex-center">
{intl.formatMessage({ id: 'menu.playground.text2images' })}
</span>
<Segmented
shape="round"
style={{
backgroundColor: 'var(--ant-color-fill-secondary)'
}}
size="middle"
className="m-l-24 font-400"
options={optionsList}
value={activeKey}
onChange={(key) => setActiveKey(key)}
></Segmented>
</div>
}
rightContent={
<ViewCodeButtons
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
activeKey={activeKey}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
orientation="vertical"
style={{ height: 16, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
></ViewCodeButtons>
}
styles={{ containerWrapper: { padding: 0 } }}
className={classNames('playground-container chat')}
>
<div className="play-ground">
+8 -11
View File
@@ -1,9 +1,7 @@
import HotKeys from '@/config/hotkeys';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { useIntl } from '@umijs/max';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Divider } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useEffect, useRef, useState } from 'react';
@@ -85,20 +83,19 @@ const PlaygroundRerank: React.FC = () => {
return (
<PageContainerInner
className={classNames('playground-container chat')}
extra={[
styles={{
containerWrapper: {
padding: 0
}
}}
rightContent={
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
orientation="vertical"
style={{ height: 16, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
></ViewCodeButtons>
}
>
<div className="play-ground">
<div className="chat">
+5 -2
View File
@@ -41,7 +41,7 @@ import { fieldConfig } from './params-config';
const { Text } = Typography;
const SearchInputWrapper = styled.div`
margin: 16px 32px 10px;
margin: 16px var(--layout-content-inlinepadding) 10px;
position: relative;
`;
@@ -477,7 +477,10 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
<div className="ground-left-footer">
<h3
className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0"
style={{ padding: '0 32px', marginTop: 16 }}
style={{
padding: '0 var(--layout-content-inlinepadding)',
marginTop: 16
}}
>
<span>{intl.formatMessage({ id: 'playground.rerank.query' })}</span>
</h3>
+24 -12
View File
@@ -2,12 +2,11 @@ import IconFont from '@/components/icon-font';
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { AudioOutlined } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import { Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
@@ -196,21 +195,34 @@ const Playground: React.FC = () => {
return (
<PageContainerInner
header={header}
extra={[
leftContent={
<div className="flex items-center">
<span className="font-600 flex-center">
{intl.formatMessage({ id: 'menu.playground.speech' })}
</span>
{
<Segmented
shape="round"
style={{
backgroundColor: 'var(--ant-color-fill-secondary)'
}}
size="middle"
className="m-l-24 font-400"
options={optionsList}
value={activeKey}
onChange={(key) => setActiveKey(key)}
></Segmented>
}
</div>
}
rightContent={
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
orientation="vertical"
style={{ height: 16, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
></ViewCodeButtons>
}
className={classNames('playground-container', {
compare: activeKey === 'compare',
chat: activeKey !== 'compare'
+4 -1
View File
@@ -9,7 +9,10 @@
justify-content: space-between;
flex-direction: column;
position: relative;
height: calc(100vh - @HEADER_HEIGHT);
height: calc(
100vh - @HEADER_HEIGHT - var(--page-content-padding) -
var(--page-header-height)
);
width: calc(100% - 390px);
.message-list-wrap {
@@ -5,7 +5,10 @@
width: 390px;
border-left: 1px solid var(--ant-color-split);
transition: width 0.3s ease;
height: calc(100vh - @HEADER_HEIGHT);
height: calc(
100vh - @HEADER_HEIGHT - var(--page-content-padding) -
var(--page-header-height)
);
padding-top: 16px;
display: flex;
flex-direction: column;
+10 -18
View File
@@ -1,4 +1,4 @@
@HEADER_HEIGHT: 56px;
@HEADER_HEIGHT: 48px;
.play-ground {
display: flex;
@@ -39,7 +39,10 @@
.params {
overflow: hidden;
height: calc(100vh - @HEADER_HEIGHT);
height: calc(
100vh - var(--page-header-height) - var(--page-content-padding) -
@HEADER_HEIGHT
);
.collapse {
width: 0;
@@ -48,7 +51,7 @@
}
.params-box {
padding-inline: 32px;
padding-inline: var(--layout-content-inlinepadding);
height: 100%;
width: 390px;
overflow-y: auto;
@@ -70,7 +73,10 @@
.ant-divider {
margin: 0;
height: calc(100vh - 136px);
height: calc(
100vh - var(--page-header-height) - var(--page-content-padding) -
@HEADER_HEIGHT
);
}
}
}
@@ -85,20 +91,6 @@
position: relative;
}
&.chat {
.ant-page-header {
// &::after {
// position: absolute;
// content: '';
// left: 32px;
// right: 32px;
// bottom: 0;
// height: 1px;
// border-bottom: 1px solid var(--ant-color-split);
// }
}
}
&.compare {
.ant-pro-page-container-children-container {
padding-inline: 0;
+1 -1
View File
@@ -3,7 +3,7 @@
display: flex;
flex-direction: column;
height: 100%;
padding-inline: 32px;
padding-inline: var(--layout-content-inlinepadding);
padding-bottom: 16px;
.documents {
@@ -1,5 +1,5 @@
.speech-to-text {
padding: 32px;
padding: var(--layout-content-inlinepadding);
height: 100%;
display: flex;
gap: 30px;