Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(result): add component result #2006

Merged
merged 3 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,22 @@
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
},

//eslint -----settings start-----

"eslint.packageManager": "yarn",
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],

"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
//eslint -----settings end-----

//prettier -----settings start-----

"prettier.useEditorConfig": false,
"prettier.requireConfig": true,

"prettier.configPath": "prettier.config.js",
//prettier -----settings end-----
//pretier -----settings end-----

//stylelint -----settings start-----

// 防止编辑器内置linter与插件冲突设置
"css.validate": false,
"less.validate": false,
Expand All @@ -46,6 +44,5 @@
"svelte"
],
"typescript.tsdk": "node_modules/typescript/lib"

//stylelint -----settings end-----
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export { default as List, ListProps } from './list';
export { default as Loading, LoadingProps } from './loading';
export { default as Menu, MenuProps, SubMenuProps, MenuItemProps, MenuMode } from './menu';
export { default as Modal, ModalProps } from './modal';
export { default as Page, PageProps } from './page';
export { default as Result, ResultProps } from './result';
export { default as Pagination, PaginationProps } from './pagination';
export { default as PopConfirm, PopConfirmProps } from './pop-confirm';
export { default as Popover, PopoverProps } from './popover';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import BasePicker from './components/base-picker';
import { PropertyPickerProps, PropertyTypes, PropertyItem, PropertyValue, PropertyInfo } from './interfaces';
import List from './components/list';
import { ListItemProps } from './components/list/interfaces';
import Page from '../../../../page'; // new
import Result from '../../../../result'; // new
import { renderExpandableItems } from './components/list/utils';
import PropertyCard from './PropertyCard';
import './style';
Expand Down Expand Up @@ -305,7 +305,7 @@ const PropertyPicker: React.FC<PropertyPickerProps> = (props: PropertyPickerProp
}
const renderItems = () => {
if (propertyItems?.length === 0) {
return <Page type="noData" size="small" />;
return <Result type="empty-result" size="small" />;
}
const recentlyNodes = recentlyPropertyItems?.length > 0 && (
<React.Fragment key="recentlyNodes">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import classnames from 'classnames';
import Page from '../../../../../../page';
import Result from '../../../../../../result';
import ItemGroup from './ItemGroup';
import ItemSubgroup from './ItemSubgroup';
import Item from './Item';
Expand All @@ -27,7 +27,7 @@ function InternalList({ className, style, children, items, expandable = false }:
} else if (children) {
content = children;
} else {
content = <Page size="small" type="noData" />;
content = <Result size="small" type="empty" />;
}

const cls = classnames(useRootPrefixCls(), className);
Expand Down
4 changes: 2 additions & 2 deletions src/list-picker/demos/List-picker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Tabs, { Tab } from '../../tabs';
import List from '../../list';
import Recent from '../Recent';
import Docs from './List-pickerPage';
import { Card, Divider, Popover, Skeleton, Table, Tag, Page } from '../..';
import { Card, Divider, Popover, Skeleton, Table, Tag, Result } from '../..';

interface Tmesurements {
id: string;
Expand Down Expand Up @@ -363,7 +363,7 @@ export const Default: Story<ListPickerProps> = (args: ListPickerProps) => {
<List
style={{ width: '240px' }}
options={[]}
empty={<Page type="noFind" description="暂无数据" size="small" />}
empty={<Result type="empty-data" description="暂无数据" size="small" />}
/>
</Tab>
</Tabs>
Expand Down
4 changes: 2 additions & 2 deletions src/list/Empty.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useLocale } from '@gio-design/utils';
import React from 'react';
import Page from '../page';
import Result from '../result';
import { collectOptions } from './util';
import defaultLocaleTextObject from './locales/zh-CN';

Expand All @@ -15,7 +15,7 @@ const Empty: React.FC<EmptyProps> = ({ children, emptyNode }) => {
if (options.length === 0) {
return (
<div style={{ width: '100%', padding: '30px 0' }}>
{emptyNode ?? <Page type="noData" description={localeTextObject.exptyText} size="small" />}
{emptyNode ?? <Result type="empty-data" title description={localeTextObject.exptyText} size="small" />}
</div>
);
}
Expand Down
4 changes: 4 additions & 0 deletions src/locales/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import listLocale from '../list/locales/en-US';
import basePickerLocale from '../legacy/filter-picker/components/property-selector/components/base-picker/locales/en-US';
import propertyPickerLocale from '../legacy/filter-picker/components/property-selector/locales/en-US';
import popConfirmLocale from '../pop-confirm/locales/en-US';
import resultLocale from '../result/locales/en-US';

export const locale: Locale = {
code: 'en-US',
Expand All @@ -29,6 +30,9 @@ export const locale: Locale = {
Page: {
...pageLocale,
},
Result: {
...resultLocale,
},
ListPicker: {
...listPickerLocale,
},
Expand Down
4 changes: 4 additions & 0 deletions src/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import listLocale from '../list/locales/zh-CN';
import basePicker from '../legacy/filter-picker/components/property-selector/components/base-picker/locales/zh-CN';
import propertyPickerLocale from '../legacy/filter-picker/components/property-selector/locales/zh-CN';
import popConfirmLocale from '../pop-confirm/locales/zh-CN';
import resultLocale from '../result/locales/en-US';

export const locale: Locale = {
code: 'zh-CN',
Expand All @@ -29,6 +30,9 @@ export const locale: Locale = {
Page: {
...pageLocale,
},
Result: {
...resultLocale,
},
ListPicker: {
...listPickerLocale,
},
Expand Down
123 changes: 123 additions & 0 deletions src/result/Result.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React from 'react';
import classnames from 'classnames';
import { useLocale, usePrefixCls } from '@gio-design/utils';
import { isUndefined } from 'lodash';
import { ResultProps } from './interfaces';
import {
Forbidden,
NotFound,
Deleted,
Locked,
InternalServerError,
EmptyChart,
Empty,
EmptyData,
EmptyResult,
} from './images';
import Button from '../button';
import defaultLocale from './locales/zh-CN';
import { SizeContextProvider, SizeType } from '../utils/SizeContext';


/**
* http status codes
*/
const ExceptionImageMap = {
'404': NotFound,
'403': Forbidden,
'500': InternalServerError,
'410': Deleted,
'423': Locked
}
/**
* empty states
*/
const EmptyImageMap = {
'empty': Empty,
'empty-chart': EmptyChart,
'empty-data': EmptyData,
'empty-result': EmptyResult,
}
const TYPE_IMAGE_MAP = {
...EmptyImageMap,
...ExceptionImageMap,
};
function Result({ className: customizeClassName, style, children, extra, type = '404', image, title: propsTitle, description, cta, size = 'normal' }: ResultProps) {
const locale = useLocale('Result');
const localeContent: { [key: string]: string } = {
...defaultLocale,
...locale,
};
type TypeMapKey = keyof typeof TYPE_IMAGE_MAP;
const defaultTypeDescription: Record<TypeMapKey, string> = {
'empty-chart': localeContent.emptyChart,
'empty': localeContent.empty,
'empty-data': localeContent.emptyData,
"empty-result": localeContent.emptyResult,
"403": localeContent['403'],
"404": localeContent['404'],
"410": localeContent['410'],
"423": localeContent['423'],
"500": localeContent['500'],
};
const prefixCls = usePrefixCls('result');
const cls = classnames(prefixCls, `${prefixCls}-${size}`, { [`${prefixCls}-empty`]: Object.keys(EmptyImageMap).includes(type) }, `${prefixCls}-${type}`, customizeClassName);
// description
const defaultDesc = Object.keys(EmptyImageMap).includes(type) ? defaultTypeDescription[type] : null
const desc = !isUndefined(description) ? description : defaultDesc;

const img = image || (TYPE_IMAGE_MAP[type] ? React.createElement(TYPE_IMAGE_MAP[type]) : React.createElement(TYPE_IMAGE_MAP.empty));
// title
const defaultTitle = Object.keys(EmptyImageMap).includes(type) ? null : defaultTypeDescription[type];
const title = !isUndefined(propsTitle) ? propsTitle : defaultTitle;
// extra
const renderExtra = () => {
if (cta) {
return (<Button size={size} onClick={cta.onClick}>
{cta.text}
</Button>)
}
if (extra) {

return extra;
}
return null
}
return (
<div className={cls} style={style}>
<SizeContextProvider size={size as SizeType}>
<div className={`${prefixCls}__image ${prefixCls}__image-${type}`}>{img}</div>
<div className={`${prefixCls}__title ${prefixCls}__title-${size}`}>{title}</div>
<div className={classnames(`${prefixCls}__description`, `${prefixCls}__description-${size}`)}>{desc}</div>
<div className={`${prefixCls}__extra`}>
{renderExtra()}
</div>
{children && <div className={`${prefixCls}__content`}>{children}</div>}
</SizeContextProvider>
</div>
);
}

const ResultImage: {
ImgForbidden: React.ReactNode;
ImgNotFound: React.ReactNode;
ImgInternalServerError: React.ReactNode;
ImgDeleted: React.ReactNode;
ImgLocked: React.ReactNode;
ImgEmpty: React.ReactNode;
ImgEmptyChart: React.ReactNode;
ImgEmptyData: React.ReactNode;
ImgEmptyResult: React.ReactNode;
} = {
ImgForbidden: TYPE_IMAGE_MAP['403'],
ImgNotFound: TYPE_IMAGE_MAP['404'],
ImgInternalServerError: TYPE_IMAGE_MAP['500'],
ImgDeleted: TYPE_IMAGE_MAP['410'],
ImgLocked: TYPE_IMAGE_MAP['423'],
ImgEmpty: TYPE_IMAGE_MAP.empty,
ImgEmptyChart: TYPE_IMAGE_MAP['empty-chart'],
ImgEmptyData: TYPE_IMAGE_MAP['empty-data'],
ImgEmptyResult: TYPE_IMAGE_MAP['empty-result']
};
export { Result, ResultImage };

89 changes: 89 additions & 0 deletions src/result/demos/Result.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Meta, Story } from "@storybook/react/types-6-0";
import { action } from '@storybook/addon-actions';
import React from "react";
import { ArrowsLeftOutlined, ErrorFilled, ErrorOutlined, ReloadOutlined } from "@gio-design/icons";
import Result, { ResultProps } from "..";
import { Button, Card, Link } from "../..";
import Docs from './ResultPage'
import '../style'

export default {
title: 'upgraded/Result',
component: Result,
parameters: {
docs: {
page: Docs,
},
argTypes: {
description: {
control: { type: 'text' },
},
},
design: {
type: 'figma',
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GIO-Design?node-id=4093%3A45839',
allowFullscreen: true,
},
},
} as Meta;
const DefaultTemplate: Story<ResultProps> = (args) => <Result {...args} />;
export const Default = DefaultTemplate.bind({});
Default.args = {
type: 'empty',
extra: <Button type="primary" >返回首页</Button>
}

export const NotFound = () => <Result type="404" extra={<Button prefix={<ArrowsLeftOutlined />} type="primary">Back Home</Button>} />;

export const Unauthorized = () => <Result type="403" extra={<Button type="primary" >返回首页</Button>} />;

export const ServerError = () => <Result type="500" title="Oooops!!!" description="Sorry, something went wrong." extra={<Button type="primary" prefix={<ArrowsLeftOutlined />}>返回首页</Button>} />;

export const Error = () => <Result

image={<ErrorFilled color="#ff688f" size="64" />}
title="Submission Failed"
description="Please check and modify the following information before resubmitting."
extra={<><Button type="primary" >Submit Again</Button><Button type="secondary">Back to list</Button></>}
>
<div className="error-list">
<div>
<h3 style={{ fontSize: '16px', lineHeight: '24px' }}>
The content you submitted has the following error:
</h3>
</div>
<p style={{ color: '#7b819c' }}>
<ErrorOutlined style={{ color: '#ff688f', marginRight: '8px' }} />
Verification fails and does not meet the template specifications. Please refill the template.
<Link href="#;">Reselect &gt;</Link>
</p>
<p style={{ color: '#7b819c' }}>
<ErrorOutlined style={{ color: '#ff688f', marginRight: '8px' }} />
Verification fails and does not meet the template specifications. Please refill the template.
<Link href="#;">Reselect &gt;</Link>
</p>
</div>
</Result>

export const Deleted: Story<ResultProps> = () => <Result type="410" title={<div>该单图已删除<Link style={{ marginLeft: '8px' }} href="#;" onClick={() => action('onClick:从当前看板中移除')}>从当前看板中移除</Link></div>} />;

export const Locked: Story<ResultProps> = () => <Result type="423" title="" extra={<div>此看板已取消与你共享<Link style={{ marginLeft: '8px' }} href="#;" onClick={() => action('onClick:取消订阅')}>取消订阅</Link></div>} />;

export const EmptyResult: Story<ResultProps> = () => <Result type="empty-result" description="没有搜索到相关结果" extra={<Button onClick={() => action('onClick:重新查询')}>重新查询</Button>} />;

export const Empty: Story<ResultProps> = () => <Result type="empty" description="你还没有创建内容,快去创建一个吧" extra={<Button onClick={() => action('onClick:新 建')}>新 建</Button>} />;

export const EmptyChart: Story<ResultProps> = () => <Result type="empty-chart" description="你还没有属于自己的看板,快去新建一个吧" extra={<Button onClick={() => action('onClick:新建看板')}>新建看板</Button>} />;

export const EmptyData: Story<ResultProps> = () => <Result type="empty-chart" description="当前查询条件下暂无数据" extra={<Button prefix={<ReloadOutlined />} onClick={() => action('onClick:刷新')}>刷新</Button>} />;

export const EmptySmallSize = () => <div>
<Card style={{ width: '320px' }}>
<Result type="empty" size="small" description="未创建相关内容" extra={<Button size="small" onClick={() => action('onClick:新 建')}>新 建</Button>} />
</Card>
</div>
export const ErrorPageSmallSize = () => <div>
<Card style={{ width: '320px' }}>
<Result type="410" size="small" title description extra={<div>该单图已删除<Link style={{ marginLeft: '8px' }} href="#;" onClick={() => action('onClick:从当前看板中移除')}>从当前看板中移除</Link></div>} />
</Card>
</div>
Loading