Browse Source

feat: storybook 处理less + css modules

pull/170/head
cp3hnu 1 year ago
parent
commit
be41b43f60
53 changed files with 760 additions and 172 deletions
  1. +21
    -2
      react-ui/.storybook/main.ts
  2. +61
    -5
      react-ui/.storybook/preview.tsx
  3. +2
    -2
      react-ui/src/app.tsx
  4. +18
    -4
      react-ui/src/components/BasicInfo/BasicInfoItem.tsx
  5. +7
    -1
      react-ui/src/components/BasicInfo/BasicInfoItemValue.tsx
  6. +24
    -6
      react-ui/src/components/BasicInfo/index.less
  7. +17
    -3
      react-ui/src/components/BasicInfo/index.tsx
  8. +8
    -1
      react-ui/src/components/BasicTableInfo/index.less
  9. +2
    -2
      react-ui/src/components/BasicTableInfo/index.tsx
  10. +10
    -5
      react-ui/src/components/FullScreenFrame/index.tsx
  11. +1
    -1
      react-ui/src/components/IFramePage/index.tsx
  12. +11
    -2
      react-ui/src/components/InfoGroup/index.tsx
  13. +3
    -1
      react-ui/src/components/InfoGroupTitle/index.less
  14. +6
    -0
      react-ui/src/components/InfoGroupTitle/index.tsx
  15. +1
    -1
      react-ui/src/components/KFEmpty/index.less
  16. +16
    -6
      react-ui/src/components/KFEmpty/index.tsx
  17. +8
    -2
      react-ui/src/components/KFIcon/index.tsx
  18. +0
    -0
      react-ui/src/components/KFModal/KFModalTitle.less
  19. +5
    -1
      react-ui/src/components/KFModal/KFModalTitle.tsx
  20. +5
    -3
      react-ui/src/components/KFModal/index.tsx
  21. +12
    -4
      react-ui/src/components/KFRadio/index.tsx
  22. +4
    -3
      react-ui/src/components/KFSpin/index.tsx
  23. +0
    -19
      react-ui/src/components/LabelValue/index.less
  24. +0
    -20
      react-ui/src/components/LabelValue/index.tsx
  25. +1
    -2
      react-ui/src/components/MenuIconSelector/index.less
  26. +3
    -0
      react-ui/src/components/MenuIconSelector/index.tsx
  27. +7
    -0
      react-ui/src/components/PageTitle/index.tsx
  28. +2
    -5
      react-ui/src/components/RightContent/index.tsx
  29. +9
    -2
      react-ui/src/components/SubAreaTitle/index.tsx
  30. +1
    -1
      react-ui/src/pages/404.tsx
  31. +1
    -1
      react-ui/src/pages/CodeConfig/List/index.tsx
  32. +1
    -1
      react-ui/src/pages/Dataset/components/ResourceList/index.tsx
  33. +2
    -2
      react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx
  34. +2
    -2
      react-ui/src/pages/Mirror/Create/index.tsx
  35. +6
    -1
      react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx
  36. +1
    -1
      react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx
  37. +0
    -0
      react-ui/src/pages/Workspace/components/RobotFrame/index.less
  38. +0
    -0
      react-ui/src/pages/Workspace/components/RobotFrame/index.tsx
  39. +1
    -1
      react-ui/src/pages/Workspace/index.tsx
  40. +1
    -1
      react-ui/src/pages/missingPage.jsx
  41. +19
    -3
      react-ui/src/stories/BasicInfo.stories.tsx
  42. +2
    -55
      react-ui/src/stories/BasicTableInfo.stories.tsx
  43. +31
    -0
      react-ui/src/stories/FullScreenFrame.stories.tsx
  44. +31
    -0
      react-ui/src/stories/InfoGroup.stories.tsx
  45. +30
    -0
      react-ui/src/stories/InfoGroupTitle.stories.tsx
  46. +53
    -0
      react-ui/src/stories/KFEmpty.stories.tsx
  47. +41
    -0
      react-ui/src/stories/KFIcon.stories.tsx
  48. +59
    -0
      react-ui/src/stories/KFModal.stories.tsx
  49. +52
    -0
      react-ui/src/stories/KFRadio.stories.tsx
  50. +35
    -0
      react-ui/src/stories/KFSpin.stories.tsx
  51. +65
    -0
      react-ui/src/stories/MenuIconSelector.stories.tsx
  52. +30
    -0
      react-ui/src/stories/PageTitle.stories.tsx
  53. +32
    -0
      react-ui/src/stories/SubAreaTitle.stories.tsx

+ 21
- 2
react-ui/.storybook/main.ts View File

@@ -10,7 +10,6 @@ const config: StorybookConfig = {
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
'@storybook/addon-styling-webpack',
],
framework: {
name: '@storybook/react-webpack5',
@@ -31,7 +30,27 @@ const config: StorybookConfig = {
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
import: true,
esModule: true,
modules: {
auto: (resourcePath: string) => {
if (
resourcePath.endsWith('MenuIconSelector/index.less') ||
resourcePath.endsWith('theme.less')
) {
return true;
} else {
return false;
}
},
localIdentName: '[local]___[hash:base64:5]',
},
},
},
{
loader: 'less-loader',
options: {


+ 61
- 5
react-ui/.storybook/preview.tsx View File

@@ -1,7 +1,8 @@
import '@/global.less';
import '@/overrides.less';
import themes from '@/styles/theme.less';
import type { Preview } from '@storybook/react';
import { ConfigProvider } from 'antd';
import { App, ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
@@ -15,14 +16,69 @@ const preview: Preview = {
date: /Date$/i,
},
},
actions: { argTypesRegex: '^on.*' },
},
decorators: [
(Story) => (
<React.Fragment>
<ConfigProvider locale={zhCN}>
<Router>
<Story />
</Router>
<ConfigProvider
locale={zhCN}
theme={{
token: {
colorPrimary: themes['primaryColor'],
colorSuccess: themes['successColor'],
colorError: themes['errorColor'],
colorWarning: themes['warningColor'],
colorLink: themes['primaryColor'],
colorText: themes['textColor'],
controlHeightLG: 46,
},
components: {
Button: {
defaultBg: 'rgba(22, 100, 255, 0.06)',
defaultBorderColor: 'rgba(22, 100, 255, 0.11)',
defaultColor: themes['textColor'],
defaultHoverBg: 'rgba(22, 100, 255, 0.06)',
defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)',
defaultHoverColor: '#3F7FFF ',
defaultActiveBg: 'rgba(22, 100, 255, 0.12)',
defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)',
defaultActiveColor: themes['primaryColor'],
contentFontSize: parseInt(themes['fontSize']),
},
Input: {
inputFontSize: parseInt(themes['fontSizeInput']),
inputFontSizeLG: parseInt(themes['fontSizeInputLg']),
paddingBlockLG: 10,
},
Select: {
singleItemHeightLG: 46,
optionSelectedColor: themes['primaryColor'],
},
Table: {
headerBg: 'rgba(242, 244, 247, 0.36)',
headerBorderRadius: 4,
rowSelectedBg: 'rgba(22, 100, 255, 0.05)',
},
Tabs: {
titleFontSize: 16,
},
Form: {
labelColor: 'rgba(29, 29, 32, 0.8);',
},
Breadcrumb: {
iconFontSize: parseInt(themes['fontSize']),
linkColor: 'rgba(29, 29, 32, 0.7)',
separatorColor: 'rgba(29, 29, 32, 0.7)',
},
},
}}
>
<App message={{ maxCount: 3 }}>
<Router>
<Story />
</Router>
</App>
</ConfigProvider>
</React.Fragment>
),


+ 2
- 2
react-ui/src/app.tsx View File

@@ -41,7 +41,7 @@ export async function getInitialState(): Promise<GlobalInitialState> {
roleNames: response.user.roles,
} as API.CurrentUser;
} catch (error) {
console.error('1111', error);
console.error('getInitialState', error);
gotoLoginPage();
}
return undefined;
@@ -215,7 +215,7 @@ export const antd: RuntimeAntdConfig = (memo) => {
defaultColor: themes['textColor'],
defaultHoverBg: 'rgba(22, 100, 255, 0.06)',
defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)',
defaultHoverColor: '#3F7FFF ',
defaultHoverColor: '#3F7FFF',
defaultActiveBg: 'rgba(22, 100, 255, 0.12)',
defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)',
defaultActiveColor: themes['primaryColor'],


+ 18
- 4
react-ui/src/components/BasicInfo/BasicInfoItem.tsx View File

@@ -18,15 +18,23 @@ type BasicInfoItemProps = {
classPrefix: string;
/** 标题是否显示省略号 */
labelEllipsis?: boolean;
/** 标签对齐方式 */
labelAlign?: 'start' | 'end' | 'justify';
};

function BasicInfoItem({ data, labelWidth, classPrefix, labelEllipsis }: BasicInfoItemProps) {
function BasicInfoItem({
data,
labelWidth,
classPrefix,
labelEllipsis = true,
labelAlign = 'start',
}: BasicInfoItemProps) {
const { label, value, format, ellipsis } = data;
const formatValue = format ? format(value) : value;
const myClassName = `${classPrefix}__item`;
let valueComponent = undefined;
if (React.isValidElement(formatValue)) {
valueComponent = formatValue;
valueComponent = <div className={`${myClassName}__node`}>{formatValue}</div>;
} else if (Array.isArray(formatValue)) {
valueComponent = (
<div className={`${myClassName}__value-container`}>
@@ -59,8 +67,14 @@ function BasicInfoItem({ data, labelWidth, classPrefix, labelEllipsis }: BasicIn
}
return (
<div className={myClassName} key={label}>
<div className={`${myClassName}__label`} style={{ width: labelWidth }}>
<Typography.Text ellipsis={labelEllipsis !== false ? { tooltip: label } : false}>
<div
className={`${myClassName}__label`}
style={{ width: labelWidth, textAlign: labelAlign, textAlignLast: labelAlign }}
>
<Typography.Text
ellipsis={labelEllipsis !== false ? { tooltip: label } : false}
style={{ width: labelAlign === 'justify' ? '100%' : 'auto' }}
>
{label}
</Typography.Text>
</div>


+ 7
- 1
react-ui/src/components/BasicInfo/BasicInfoItemValue.tsx View File

@@ -21,7 +21,13 @@ type BasicInfoItemValueProps = {
url?: string;
};

function BasicInfoItemValue({ value, link, url, ellipsis, classPrefix }: BasicInfoItemValueProps) {
function BasicInfoItemValue({
value,
link,
url,
classPrefix,
ellipsis = true,
}: BasicInfoItemValueProps) {
const myClassName = `${classPrefix}__item__value`;
let component = undefined;
if (url && value) {


+ 24
- 6
react-ui/src/components/BasicInfo/index.less View File

@@ -17,12 +17,6 @@
color: @text-color-secondary;
font-size: @font-size-content;
line-height: 1.6;
text-align: justify;
text-align-last: justify;

.ant-typography {
width: 100% !important;
}

&::after {
position: absolute;
@@ -55,5 +49,29 @@
text-underline-offset: 3px;
}
}

&__node {
flex: 1;
min-width: 0;
margin-left: 16px;
font-size: @font-size-content;
line-height: 1.6;
word-break: break-all;
}
}
}

.kf-basic-info--three-columns {
width: 100%;

.kf-basic-info__item {
width: calc((100% - 80px) / 3);

&__label {
font-size: @font-size;
}
&__value {
font-size: @font-size;
}
}
}

+ 17
- 3
react-ui/src/components/BasicInfo/index.tsx View File

@@ -12,6 +12,10 @@ export type BasicInfoProps = {
labelWidth: number;
/** 标题是否显示省略号 */
labelEllipsis?: boolean;
/** 是否一行三列 */
threeColumns?: boolean;
/** 标签对齐方式 */
labelAlign?: 'start' | 'end' | 'justify';
/** 自定义类名 */
className?: string;
/** 自定义样式 */
@@ -19,17 +23,26 @@ export type BasicInfoProps = {
};

/**
* 基础信息展示组件,用于展示基础信息,一行两列,支持格式化数据
* 基础信息展示组件,用于展示基础信息,支持一行两列或一行三列,支持数据格式化
*/
export default function BasicInfo({
datas,
className,
labelEllipsis,
style,
labelWidth,
labelEllipsis = true,
threeColumns = false,
labelAlign = 'start',
}: BasicInfoProps) {
return (
<div className={classNames('kf-basic-info', className)} style={style}>
<div
className={classNames(
'kf-basic-info',
{ 'kf-basic-info--three-columns': threeColumns },
className,
)}
style={style}
>
{datas.map((item) => (
<BasicInfoItem
key={item.label}
@@ -37,6 +50,7 @@ export default function BasicInfo({
labelWidth={labelWidth}
classPrefix="kf-basic-info"
labelEllipsis={labelEllipsis}
labelAlign={labelAlign}
/>
))}
</div>


+ 8
- 1
react-ui/src/components/BasicTableInfo/index.less View File

@@ -34,7 +34,6 @@
&__value {
flex: 1;
min-width: 0;
margin: 0 !important;
padding: 12px 20px 4px;
font-size: @font-size;
word-break: break-all;
@@ -56,5 +55,13 @@
text-underline-offset: 3px;
}
}

&__node {
flex: 1;
min-width: 0;
padding: 12px 20px;
font-size: @font-size;
word-break: break-all;
}
}
}

+ 2
- 2
react-ui/src/components/BasicTableInfo/index.tsx View File

@@ -6,7 +6,7 @@ import './index.less';
export type { BasicInfoData, BasicInfoLink };

/**
* 表格基础信息展示组件,用于展示基础信息,一行四列,支持格式化数据
* 表格基础信息展示组件,用于展示基础信息,一行四列,支持数据格式化
*/
export default function BasicTableInfo({
datas,
@@ -21,7 +21,7 @@ export default function BasicTableInfo({
for (let i = 0; i < 4 - remainder; i++) {
array.push({
label: '',
value: '',
value: false, // 用于区分是否是空数据,不能是空字符串、null、undefined
});
}
}


+ 10
- 5
react-ui/src/components/FullScreenFrame/index.tsx View File

@@ -2,22 +2,27 @@ import classNames from 'classnames';
import './index.less';

type FullScreenFrameProps = {
/** URL */
url: string;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
onload?: (e?: React.SyntheticEvent<HTMLIFrameElement, Event>) => void;
onerror?: (e?: React.SyntheticEvent<HTMLIFrameElement, Event>) => void;
/** 加载完成回调 */
onLoad?: (e?: React.SyntheticEvent<HTMLIFrameElement, Event>) => void;
/** 加载失败回调 */
onError?: (e?: React.SyntheticEvent<HTMLIFrameElement, Event>) => void;
};

function FullScreenFrame({ url, className, style, onload, onerror }: FullScreenFrameProps) {
function FullScreenFrame({ url, className, style, onLoad, onError }: FullScreenFrameProps) {
return (
<div className={classNames('kf-full-screen-frame', className ?? '')} style={style}>
{url && (
<iframe
src={url}
className="kf-full-screen-frame__iframe"
onLoad={onload}
onError={onerror}
onLoad={onLoad}
onError={onError}
></iframe>
)}
</div>


+ 1
- 1
react-ui/src/components/IFramePage/index.tsx View File

@@ -66,7 +66,7 @@ function IframePage({ type, className, style }: IframePageProps) {
return (
<div className={classNames('kf-iframe-page', className)} style={style}>
{loading && createPortal(<KFSpin size="large" />, document.body)}
<FullScreenFrame url={iframeUrl} onload={hideLoading} onerror={hideLoading} />
<FullScreenFrame url={iframeUrl} onLoad={hideLoading} onError={hideLoading} />
</div>
);
}


+ 11
- 2
react-ui/src/components/InfoGroup/index.tsx View File

@@ -3,14 +3,23 @@ import InfoGroupTitle from '../InfoGroupTitle';
import './index.less';

type InfoGroupProps = {
/** 标题 */
title: string;
height?: string | number; // 如果要纵向滚动,需要设置高度
width?: string | number; // 如果要横向滚动,需要设置宽度
/** 高度, 如果要纵向滚动,需要设置高度 */
height?: string | number;
/** 宽度, 如果要横向滚动,需要设置宽度 */
width?: string | number;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
/** 子元素 */
children?: React.ReactNode;
};

/**
* 信息组,用于展示基本信息,支持横向、纵向滚动。自动机器学习、超参数寻优都是使用这个组件
*/
function InfoGroup({ title, height, width, className, style, children }: InfoGroupProps) {
const contentStyle: React.CSSProperties = {};
if (height) {


+ 3
- 1
react-ui/src/components/InfoGroupTitle/index.less View File

@@ -1,7 +1,8 @@
.kf-info-group-title {
box-sizing: border-box;
width: 100%;
height: 56px;
padding-left: @content-padding;
padding: 0 @content-padding;
background: linear-gradient(
179.03deg,
rgba(199, 223, 255, 0.12) 0%,
@@ -21,6 +22,7 @@
color: @text-color;
font-weight: 500;
font-size: @font-size-title;
.singleLine();

&::after {
position: absolute;


+ 6
- 0
react-ui/src/components/InfoGroupTitle/index.tsx View File

@@ -3,11 +3,17 @@ import classNames from 'classnames';
import './index.less';

type InfoGroupTitleProps = {
/** 标题 */
title: string;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
};

/**
* 信息组标题
*/
function InfoGroupTitle({ title, style, className }: InfoGroupTitleProps) {
return (
<Flex align="center" className={classNames('kf-info-group-title', className)} style={style}>


+ 1
- 1
react-ui/src/components/KFEmpty/index.less View File

@@ -33,7 +33,7 @@
margin-top: 20px;
margin-bottom: 30px;

&__back-btn {
&__button {
height: 32px;
}
}


+ 16
- 6
react-ui/src/components/KFEmpty/index.tsx View File

@@ -9,15 +9,24 @@ export enum EmptyType {
}

type EmptyProps = {
className?: string;
style?: React.CSSProperties;
/** 类型 */
type: EmptyType;
/** 标题 */
title?: string;
/** 内容 */
content?: string;
/** 是否有页脚,如果有默认是一个按钮 */
hasFooter?: boolean;
footer?: () => React.ReactNode;
/** 按钮标题,默认是"刷新" */
buttonTitle?: string;
onRefresh?: () => void;
/** 按钮点击回调 */
onButtonClick?: () => void;
/** 自定义页脚内容 */
footer?: () => React.ReactNode;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
};

function getEmptyImage(type: EmptyType) {
@@ -31,6 +40,7 @@ function getEmptyImage(type: EmptyType) {
}
}

/** 空状态 */
function KFEmpty({
className,
style,
@@ -40,7 +50,7 @@ function KFEmpty({
hasFooter = true,
footer,
buttonTitle = '刷新',
onRefresh,
onButtonClick,
}: EmptyProps) {
const image = getEmptyImage(type);

@@ -54,7 +64,7 @@ function KFEmpty({
{footer ? (
footer()
) : (
<Button className="kf-empty__footer__back-btn" type="primary" onClick={onRefresh}>
<Button className="kf-empty__footer__button" type="primary" onClick={onButtonClick}>
{buttonTitle}
</Button>
)}


+ 8
- 2
react-ui/src/components/KFIcon/index.tsx View File

@@ -14,14 +14,20 @@ const Icon = createFromIconfontCN({
type IconFontProps = Parameters<typeof Icon>[0];

interface KFIconProps extends IconFontProps {
/** 图标 */
type: string;
/** 字体大小 */
font?: number;
/** 字体颜色 */
color?: string;
style?: React.CSSProperties;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
}

function KFIcon({ type, font = 15, color = '', style = {}, className, ...rest }: KFIconProps) {
/** 封装 iconfont 图标 */
function KFIcon({ type, font = 15, color, className, style, ...rest }: KFIconProps) {
const iconStyle = {
...style,
fontSize: font,


react-ui/src/components/ModalTitle/index.less → react-ui/src/components/KFModal/KFModalTitle.less View File


react-ui/src/components/ModalTitle/index.tsx → react-ui/src/components/KFModal/KFModalTitle.tsx View File

@@ -6,12 +6,16 @@

import classNames from 'classnames';
import React from 'react';
import './index.less';
import './KFModalTitle.less';

type ModalTitleProps = {
/** 标题 */
title: React.ReactNode;
/** 图片 */
image?: string;
/** 自定义样式 */
style?: React.CSSProperties;
/** 自定义类名 */
className?: string;
};


+ 5
- 3
react-ui/src/components/KFModal/index.tsx View File

@@ -4,19 +4,21 @@
* @Description: 自定义 Modal
*/

import ModalTitle from '@/components/ModalTitle';
import { Modal, type ModalProps } from 'antd';
import classNames from 'classnames';
import KFModalTitle from './KFModalTitle';
import './index.less';

export interface KFModalProps extends ModalProps {
image?: string;
}

/** 自定义 Modal */
function KFModal({
title,
image,
children,
className = '',
className,
centered,
maskClosable,
...rest
@@ -27,7 +29,7 @@ function KFModal({
{...rest}
centered={centered ?? true}
maskClosable={maskClosable ?? false}
title={<ModalTitle title={title} image={image}></ModalTitle>}
title={<KFModalTitle title={title} image={image} />}
>
{children}
</Modal>


+ 12
- 4
react-ui/src/components/KFRadio/index.tsx View File

@@ -8,32 +8,40 @@ import classNames from 'classnames';
import './index.less';

export type KFRadioItem = {
key: string;
title: string;
value: string;
icon?: React.ReactNode;
};

type KFRadioProps = {
/** 选项 */
items: KFRadioItem[];
/** 当前选中项 */
value?: string;
/** 自定义样式 */
style?: React.CSSProperties;
/** 自定义类名 */
className?: string;
/** 选中回调 */
onChange?: (value: string) => void;
};

/**
* 自定义 Radio
*/
function KFRadio({ items, value, style, className, onChange }: KFRadioProps) {
return (
<span className={classNames('kf-radio', className)} style={style}>
{items.map((item) => {
return (
<span
key={item.key}
key={item.value}
className={
value === item.key
value === item.value
? classNames('kf-radio__item', 'kf-radio__item--active')
: 'kf-radio__item'
}
onClick={() => onChange?.(item.key)}
onClick={() => onChange?.(item.value)}
>
{item.icon}
<span style={{ marginLeft: '5px' }}>{item.title}</span>


+ 4
- 3
react-ui/src/components/KFSpin/index.tsx View File

@@ -5,13 +5,14 @@
*/

import { Spin, SpinProps } from 'antd';
import styles from './index.less';
import './index.less';

/** 自定义 Spin */
function KFSpin(props: SpinProps) {
return (
<div className={styles['kf-spin']}>
<div className={'kf-spin'}>
<Spin {...props} />
<div className={styles['kf-spin__label']}>加载中</div>
<div className={'kf-spin__label'}>加载中</div>
</div>
);
}


+ 0
- 19
react-ui/src/components/LabelValue/index.less View File

@@ -1,19 +0,0 @@
.kf-label-value {
display: flex;
align-items: flex-start;
font-size: 16px;
line-height: 1.6;

&__label {
flex: none;
width: 80px;
color: @text-color-secondary;
}

&__value {
flex: 1;
color: @text-color;
white-space: pre-line;
word-break: break-all;
}
}

+ 0
- 20
react-ui/src/components/LabelValue/index.tsx View File

@@ -1,20 +0,0 @@
import classNames from 'classnames';
import './index.less';

type labelValueProps = {
label: string;
value?: any;
className?: string;
style?: React.CSSProperties;
};

function LabelValue({ label, value, className, style }: labelValueProps) {
return (
<div className={classNames('kf-label-value', className)} style={style}>
<div className="kf-label-value__label">{label}</div>
<div className="kf-label-value__value">{value ?? '--'}</div>
</div>
);
}

export default LabelValue;

+ 1
- 2
react-ui/src/components/MenuIconSelector/index.less View File

@@ -1,5 +1,4 @@
.menu-icon-selector {
// grid 布局,每行显示 8 个图标
display: grid;
grid-template-columns: repeat(4, 80px);
gap: 20px;
@@ -10,7 +9,7 @@
display: flex;
align-items: center;
justify-content: center;
width: 80x;
width: 80px;
height: 80px;
border: 1px solid transparent;
border-radius: 4px;


+ 3
- 0
react-ui/src/components/MenuIconSelector/index.tsx View File

@@ -12,7 +12,9 @@ import { useEffect, useState } from 'react';
import styles from './index.less';

interface MenuIconSelectorProps extends Omit<ModalProps, 'onOk'> {
/** 选中的图标 */
selectedIcon?: string;
/** 选择回调 */
onOk: (param: string) => void;
}

@@ -21,6 +23,7 @@ type IconObject = {
font_class: string;
};

/** 菜单图标选择器 */
function MenuIconSelector({ open, selectedIcon, onOk, ...rest }: MenuIconSelectorProps) {
const [icons, setIcons] = useState<IconObject[]>([]);
useEffect(() => {


+ 7
- 0
react-ui/src/components/PageTitle/index.tsx View File

@@ -8,10 +8,17 @@ import React from 'react';
import './index.less';

type PageTitleProps = {
/** 标题 */
title: string;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
};

/**
* 页面标题
*/
function PageTitle({ title, style, className = '' }: PageTitleProps) {
return (
<div className={classNames('kf-page-title', className)} style={style}>


+ 2
- 5
react-ui/src/components/RightContent/index.tsx View File

@@ -1,9 +1,8 @@
import { useModel } from '@umijs/max';
import React from 'react';
// import KFBreadcrumb from '../KFBreadcrumb';
import KFIcon from '@/components/KFIcon';
import { ProBreadcrumb } from '@ant-design/pro-components';
import { useModel } from '@umijs/max';
import { Button } from 'antd';
import React from 'react';
import Avatar from './AvatarDropdown';
import styles from './index.less';
// import { SelectLang } from '@umijs/max';
@@ -44,8 +43,6 @@ const GlobalHeaderRight: React.FC = () => {

<ProBreadcrumb></ProBreadcrumb>

{/* <KFBreadcrumb /> */}

<Avatar menu={true} />
{/* <SelectLang className={actionClassName} /> */}
</div>


+ 9
- 2
react-ui/src/components/SubAreaTitle/index.tsx View File

@@ -8,13 +8,20 @@ import classNames from 'classnames';
import './index.less';

type SubAreaTitleProps = {
/** 标题 */
title: string;
/** 图片 */
image?: string;
style?: React.CSSProperties;
/** 自定义类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
};

function SubAreaTitle({ title, image, style, className }: SubAreaTitleProps) {
/**
* 表单或者详情页的分区标题
*/
function SubAreaTitle({ title, image, className, style }: SubAreaTitleProps) {
return (
<div className={classNames('kf-subarea-title', className)} style={style}>
{image && (


+ 1
- 1
react-ui/src/pages/404.tsx View File

@@ -12,7 +12,7 @@ const NoFoundPage = () => {
content={'很抱歉,您访问的页面地址有误,\n或者该页面不存在。'}
hasFooter={true}
buttonTitle="返回首页"
onRefresh={() => navigate('/')}
onButtonClick={() => navigate('/')}
></KFEmpty>
);
};


+ 1
- 1
react-ui/src/pages/CodeConfig/List/index.tsx View File

@@ -197,7 +197,7 @@ function CodeConfigList() {
title="暂无数据"
content={'很抱歉,没有搜索到您想要的内容\n建议刷新试试'}
hasFooter={true}
onRefresh={getDataList}
onButtonClick={getDataList}
/>
)}
</div>


+ 1
- 1
react-ui/src/pages/Dataset/components/ResourceList/index.tsx View File

@@ -226,7 +226,7 @@ function ResourceList(
title="暂无数据"
content={'很抱歉,没有搜索到您想要的内容\n建议刷新试试'}
hasFooter={true}
onRefresh={getDataList}
onButtonClick={getDataList}
/>
)}
</div>


+ 2
- 2
react-ui/src/pages/DevelopmentEnvironment/Create/index.tsx View File

@@ -36,13 +36,13 @@ enum ComputingResourceType {

const EditorRadioItems: KFRadioItem[] = [
{
key: ComputingResourceType.GPU,
title: '英伟达GPU',
value: ComputingResourceType.GPU,
icon: <KFIcon type="icon-jiyugongwangjingxiang" />,
},
{
key: ComputingResourceType.NPU,
title: '昇腾NPU',
value: ComputingResourceType.NPU,
icon: <KFIcon type="icon-bendishangchuan" />,
},
];


+ 2
- 2
react-ui/src/pages/Mirror/Create/index.tsx View File

@@ -30,13 +30,13 @@ type FormData = {

const mirrorRadioItems: KFRadioItem[] = [
{
key: CommonTabKeys.Public,
title: '基于公网镜像',
value: CommonTabKeys.Public,
icon: <KFIcon type="icon-jiyugongwangjingxiang" />,
},
{
key: CommonTabKeys.Private,
title: '本地上传',
value: CommonTabKeys.Private,
icon: <KFIcon type="icon-bendishangchuan" />,
},
];


+ 6
- 1
react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx View File

@@ -401,7 +401,12 @@ function ServiceInfo() {
image={require('@/assets/img/mirror-basic.png')}
style={{ marginBottom: '26px', flex: 'none' }}
></SubAreaTitle>
<BasicInfo datas={basicInfo} labelWidth={66} style={{ flex: 'none' }}></BasicInfo>
<BasicInfo
datas={basicInfo}
labelWidth={66}
labelAlign="justify"
style={{ flex: 'none' }}
></BasicInfo>
<SubAreaTitle
title="服务版本"
image={require('@/assets/img/service-version.png')}


+ 1
- 1
react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx View File

@@ -113,7 +113,7 @@ function VersionBasicInfo({ info }: BasicInfoProps) {
},
];

return <BasicInfo datas={datas} labelWidth={66}></BasicInfo>;
return <BasicInfo datas={datas} labelWidth={66} labelAlign="justify"></BasicInfo>;
}

export default VersionBasicInfo;

react-ui/src/components/RobotFrame/index.less → react-ui/src/pages/Workspace/components/RobotFrame/index.less View File


react-ui/src/components/RobotFrame/index.tsx → react-ui/src/pages/Workspace/components/RobotFrame/index.tsx View File


+ 1
- 1
react-ui/src/pages/Workspace/index.tsx View File

@@ -1,4 +1,3 @@
import RobotFrame from '@/components/RobotFrame';
import { useDraggable } from '@/hooks/draggable';
import { getWorkspaceOverviewReq } from '@/services/workspace';
import { ExperimentInstance } from '@/types';
@@ -9,6 +8,7 @@ import AssetsManagement from './components/AssetsManagement';
import ExperimentChart, { type ExperimentStatistics } from './components/ExperimentChart';
import ExperitableTable from './components/ExperimentTable';
import QuickStart from './components/QuickStart';
import RobotFrame from './components/RobotFrame';
import TotalStatistics from './components/TotalStatistics';
import UserSpace from './components/UserSpace';
import WorkspaceIntro from './components/WorkspaceIntro';


+ 1
- 1
react-ui/src/pages/missingPage.jsx View File

@@ -12,7 +12,7 @@ const MissingPage = () => {
content={'很抱歉,您访问的正在开发中,\n请耐心等待。'}
hasFooter={true}
buttonTitle="返回首页"
onRefresh={() => navigate('/')}
onButtonClick={() => navigate('/')}
></KFEmpty>
);
};


+ 19
- 3
react-ui/src/stories/BasicInfo.stories.tsx View File

@@ -66,16 +66,32 @@ export const Primary: Story = {
},
},
{ label: '日期', value: new Date(), format: formatDate },
{ label: '数组', value: ['a', 'b'], format: formatList },
{ label: '数组', value: ['a', 'b', 'c'], format: formatList },
{
label: '带省略号',
value: '这是一个很长的字符串这是一个很长的字符串这是一个很长的字符串这是一个很长的字符串',
},

{
label: '多行',
value: [
{
label: '服务名称',
value: '手写体识别',
},
{
label: '服务名称',
value: '人脸识别',
},
],
format: (value: any) =>
value.map((item: any) => ({
value: item.label + ':' + item.value,
})),
},
{
label: '自定义组件',
value: (
<Button type="primary" style={{ marginLeft: 16, height: 26 }}>
<Button type="primary" style={{ height: 26 }}>
click
</Button>
),


+ 2
- 55
react-ui/src/stories/BasicTableInfo.stories.tsx View File

@@ -1,19 +1,6 @@
import BasicTableInfo from '@/components/BasicTableInfo';
import { formatDate } from '@/utils/date';
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from 'antd';

const formatList = (value: string[] | null | undefined): string => {
if (
value === undefined ||
value === null ||
Array.isArray(value) === false ||
value.length === 0
) {
return '--';
}
return value.join(',');
};
import * as BasicInfoStories from './BasicInfo.stories';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
@@ -39,47 +26,7 @@ type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
datas: [
{ label: '服务名称', value: '手写体识别' },
{
label: '无数据',
value: '',
},
{
label: '外部链接',
value: 'https://www.baidu.com/',
format: (value: string) => {
return {
value: '百度',
url: value,
};
},
},
{
label: '内部链接',
value: 'https://www.baidu.com/',
format: () => {
return {
value: '实验',
link: '/pipeline/experiment/instance/1/1',
};
},
},
{ label: '日期', value: new Date(), format: formatDate },
{ label: '数组', value: ['a', 'b'], format: formatList },
{
label: '带省略号',
value: '这是一个很长的字符串这是一个很长的字符串这是一个很长的字符串这是一个很长的字符串',
},
{
label: '自定义组件',
value: (
<div style={{ padding: '12px 20px 4px' }}>
<Button type="primary">click</Button>
</div>
),
},
],
...BasicInfoStories.Primary.args,
labelWidth: 70,
},
};

+ 31
- 0
react-ui/src/stories/FullScreenFrame.stories.tsx View File

@@ -0,0 +1,31 @@
import FullScreenFrame from '@/components/FullScreenFrame';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/FullScreenFrame',
component: FullScreenFrame,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof FullScreenFrame>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
url: 'https://www.hao123.com/',
style: { height: '500px' },
},
};

+ 31
- 0
react-ui/src/stories/InfoGroup.stories.tsx View File

@@ -0,0 +1,31 @@
import InfoGroup from '@/components/InfoGroup';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/InfoGroup',
component: InfoGroup,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof InfoGroup>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
title: '基本信息',
children: <div>I am a child element </div>,
},
};

+ 30
- 0
react-ui/src/stories/InfoGroupTitle.stories.tsx View File

@@ -0,0 +1,30 @@
import InfoGroupTitle from '@/components/InfoGroupTitle';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/InfoGroupTitle',
component: InfoGroupTitle,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof InfoGroupTitle>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
title: '基本信息',
},
};

+ 53
- 0
react-ui/src/stories/KFEmpty.stories.tsx View File

@@ -0,0 +1,53 @@
import KFEmpty, { EmptyType } from '@/components/KFEmpty';
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/KFEmpty',
component: KFEmpty,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
type: { control: 'select', options: Object.values(EmptyType) },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onButtonClick: fn() },
} satisfies Meta<typeof KFEmpty>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Developing: Story = {
args: {
type: EmptyType.Developing,
title: '敬请期待~',
content: '很抱歉,您访问的正在开发中,\n请耐心等待。',
hasFooter: true,
buttonTitle: '返回首页',
},
};

export const NoData: Story = {
args: {
type: EmptyType.NoData,
title: '暂无数据',
content: '很抱歉,没有搜索到您想要的内容\n建议刷新试试',
hasFooter: true,
},
};

export const NotFound: Story = {
args: {
type: EmptyType.NotFound,
title: '404',
content: '很抱歉,您访问的页面地址有误,\n或者该页面不存在。',
hasFooter: true,
buttonTitle: '返回首页',
},
};

+ 41
- 0
react-ui/src/stories/KFIcon.stories.tsx View File

@@ -0,0 +1,41 @@
import KFIcon from '@/components/KFIcon';
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from 'antd';
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/KFIcon',
component: KFIcon,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: {},
} satisfies Meta<typeof KFIcon>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
type: 'icon-xiazai',
},
};

export const InButton: Story = {
args: {
type: 'icon-xiazai',
},
render: function Render(args) {
return (
<Button icon={<KFIcon {...args} />} type="primary">
下载
</Button>
);
},
};

+ 59
- 0
react-ui/src/stories/KFModal.stories.tsx View File

@@ -0,0 +1,59 @@
import CreateExperiment from '@/assets/img/create-experiment.png';
import KFModal from '@/components/KFModal';
import { useArgs } from '@storybook/preview-api';
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Button } from 'antd';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/KFModal',
component: KFModal,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onCancel: fn(), onOk: fn() },
} satisfies Meta<typeof KFModal>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
title: '创建实验',
image: CreateExperiment,
open: false,
children: '这是一个模态框',
},
render: function Render(args) {
const [{ open }, updateArgs] = useArgs();
function onClick() {
updateArgs({ open: true });
}
function onOk() {
updateArgs({ open: false });
}

function onCancel() {
updateArgs({ open: false });
}

return (
<>
<Button type="primary" onClick={onClick}>
打开 KFModal
</Button>
<KFModal {...args} open={open} onOk={onOk} onCancel={onCancel} />
</>
);
},
};

+ 52
- 0
react-ui/src/stories/KFRadio.stories.tsx View File

@@ -0,0 +1,52 @@
import KFIcon from '@/components/KFIcon';
import KFRadio from '@/components/KFRadio';
import { useArgs } from '@storybook/preview-api';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/KFRadio',
component: KFRadio,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof KFRadio>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
items: [
{
title: '英伟达GPU',
value: 'GPU',
icon: <KFIcon type="icon-jiyugongwangjingxiang" />,
},
{
title: '昇腾NPU',
value: 'NPU',
icon: <KFIcon type="icon-bendishangchuan" />,
},
],
value: 'GPU',
},
render: function Render(args) {
const [{ value }, updateArgs] = useArgs();
function onChange(value: string) {
updateArgs({ value: value });
}

return <KFRadio {...args} value={value} onChange={onChange} />;
},
};

+ 35
- 0
react-ui/src/stories/KFSpin.stories.tsx View File

@@ -0,0 +1,35 @@
import KFSpin from '@/components/KFSpin';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/KFSpin',
component: KFSpin,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
decorators: [
(Story) => (
<div style={{ height: '200px' }}>
<Story />
</div>
),
],
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof KFSpin>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {},
};

+ 65
- 0
react-ui/src/stories/MenuIconSelector.stories.tsx View File

@@ -0,0 +1,65 @@
import MenuIconSelector from '@/components/MenuIconSelector';
import { useArgs } from '@storybook/preview-api';
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Button } from 'antd';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/MenuIconSelector',
component: MenuIconSelector,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
open: {
control: 'boolean',
description: '对话框是否可见',
},
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onCancel: fn(), onOk: fn() },
} satisfies Meta<typeof MenuIconSelector>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
selectedIcon: 'manual-icon',
open: false,
},
render: function Render(args) {
const [{ open, selectedIcon }, updateArgs] = useArgs();
function onClick() {
updateArgs({ open: true });
}
function onOk(value: string) {
updateArgs({ selectedIcon: value, open: false });
}

function onCancel() {
updateArgs({ open: false });
}

return (
<>
<Button type="primary" onClick={onClick}>
打开 MenuIconSelector
</Button>
<MenuIconSelector
{...args}
open={open}
selectedIcon={selectedIcon}
onOk={onOk}
onCancel={onCancel}
/>
</>
);
},
};

+ 30
- 0
react-ui/src/stories/PageTitle.stories.tsx View File

@@ -0,0 +1,30 @@
import PageTitle from '@/components/PageTitle';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/PageTitle',
component: PageTitle,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof PageTitle>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
title: '数据集列表',
},
};

+ 32
- 0
react-ui/src/stories/SubAreaTitle.stories.tsx View File

@@ -0,0 +1,32 @@
import MirrorBasic from '@/assets/img/mirror-basic.png';
import SubAreaTitle from '@/components/SubAreaTitle';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/SubAreaTitle',
component: SubAreaTitle,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof SubAreaTitle>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
title: '基本信息',
image: MirrorBasic,
},
};

Loading…
Cancel
Save