From c75c45c1ab42975d869d7fedf9adf80e9f1e7dcc Mon Sep 17 00:00:00 2001 From: wujingquan Date: Mon, 21 Dec 2020 23:23:17 +0800 Subject: [PATCH 1/3] add --- src/components/Empty/Network.tsx | 110 +++++++++++++++++++++++++ src/components/Empty/helper.tsx | 53 ++++++++++++ src/components/Empty/index.scss | 39 +++++++++ src/components/Empty/index.stories.tsx | 91 ++++++++++++++++++++ src/components/Empty/index.tsx | 64 ++++++++++++++ src/components/Empty/types.ts | 8 ++ src/index.tsx | 5 +- src/styles/variables.scss | 17 ++++ 8 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 src/components/Empty/Network.tsx create mode 100644 src/components/Empty/helper.tsx create mode 100644 src/components/Empty/index.scss create mode 100644 src/components/Empty/index.stories.tsx create mode 100644 src/components/Empty/index.tsx create mode 100644 src/components/Empty/types.ts diff --git a/src/components/Empty/Network.tsx b/src/components/Empty/Network.tsx new file mode 100644 index 000000000..aa9e225f4 --- /dev/null +++ b/src/components/Empty/Network.tsx @@ -0,0 +1,110 @@ +import React from 'react'; + +const renderStop = (color: string, offset: number, opacity?: number) => ( + +); + +export const Network = ( + + + + {renderStop('#FFF', 0, 0.5)} + {renderStop('#F2F3F5', 100)} + + + {renderStop('#F2F3F5', 0, 0.3)} + {renderStop('#F2F3F5', 100)} + + + {renderStop('#EBEDF0', 0)} + {renderStop('#DCDEE0', 100, 0)} + + + {renderStop('#EAEDF0', 0)} + {renderStop('#DCDEE0', 100)} + + + {renderStop('#EAEDF0', 0)} + {renderStop('#DCDEE0', 100)} + + + {renderStop('#EAEDF0', 0)} + {renderStop('#DCDEE0', 100)} + + + {renderStop('#EAEDF0', 0)} + {renderStop('#DCDEE0', 100)} + + + {renderStop('#EBEDF0', 0)} + {renderStop('#FFF', 100, 0)} + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/src/components/Empty/helper.tsx b/src/components/Empty/helper.tsx new file mode 100644 index 000000000..1ab60a5aa --- /dev/null +++ b/src/components/Empty/helper.tsx @@ -0,0 +1,53 @@ +// import React, { ReactElement } from 'react'; + +// import SpinnerLoading from '../../assets/icons/loaders/Spinner'; +// import CircularLoading from '../../assets/icons/loaders/Circular'; + +// import { LoadingIconProps } from './types'; + +// export const renderLoadingIcon = ({ +// className, +// loadingType = 'circular', +// loadingText, +// loadingSize +// }: LoadingIconProps): ReactElement => { +// return ( +// +// {loadingType === 'spinner' ? ( +// +// ) : ( +// +// )} +// {loadingText && {loadingText}} +// +// ); +// }; + +// export const getContrastTextColor = (colorHex: string): string => { +// let r, g, b; +// if (colorHex.length !== 6 && colorHex.slice(0, 3) !== 'rgb') { +// return 'black'; +// } // return black if color is not supplied +// else if (colorHex.length === 6) { +// r = parseInt(colorHex[0] + colorHex[1], 16); +// g = parseInt(colorHex[2] + colorHex[3], 16); +// b = parseInt(colorHex[4] + colorHex[5], 16); +// } else if (colorHex.length !== 6 && colorHex.slice(0, 3) === 'rgb') { +// const startIndex = colorHex.indexOf('('); +// const endIndex = colorHex.indexOf(')'); +// const rgb = colorHex +// .slice(startIndex + 1, endIndex - startIndex) +// .split(','); +// r = rgb[0]; +// g = rgb[1]; +// b = rgb[2]; +// } +// const brightness = (r * 299 + g * 587 + b * 114) / 1000; +// return brightness > 125 ? 'black' : 'white'; +// }; + +// export const colorType = (colorHex: string): string => { +// if (colorHex.length !== 6 && colorHex.slice(0, 3) === 'rgb') return colorHex; +// const result = '#' + colorHex; +// return result; +// }; diff --git a/src/components/Empty/index.scss b/src/components/Empty/index.scss new file mode 100644 index 000000000..7bb17674c --- /dev/null +++ b/src/components/Empty/index.scss @@ -0,0 +1,39 @@ +// @import '../../styles/colors.scss'; +// @import '../../styles/spacing.scss'; +// @import '../../styles/typography.scss'; +// @import '../../styles/opacity.scss'; +@import '../../styles/variables.scss'; + +$baseClass: 'vant-button'; + + +.#{$baseClass} { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: $empty-padding; + + &__image { + width: $empty-image-size; + height: $empty-image-size; + + img { + width: 100%; + height: 100%; + } + } + + &__description { + margin-top: $empty-description-margin-top; + padding: $empty-description-padding; + color: $empty-description-color; + font-size: $empty-description-font-size; + line-height: $empty-description-line-height; + } + + &__bottom { + margin-top: $empty-bottom-margin-top; + } +} diff --git a/src/components/Empty/index.stories.tsx b/src/components/Empty/index.stories.tsx new file mode 100644 index 000000000..4306190f8 --- /dev/null +++ b/src/components/Empty/index.stories.tsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import Empty from '.'; +import Button from '../Button'; +import Image from '../Image'; + +export default { + title: 'Empty', + component: Empty +}; + +export const BasicUsage = () => ( +
+ +
+); + +export const Description = () => ( +
+ +
+); + +export const ImageType = () => { + const [showType, setShowType] = useState('error'); + + return ( +
+
+ ); +}; + +export const CustomImage = () => ( +
+ +
+); + +export const BottomContent = () => ( +
+ + Button + + } + /> +
+); diff --git a/src/components/Empty/index.tsx b/src/components/Empty/index.tsx new file mode 100644 index 000000000..9774d9576 --- /dev/null +++ b/src/components/Empty/index.tsx @@ -0,0 +1,64 @@ +import React from 'react'; + +import classnames from '../../utils/classNames'; + +import { Props } from './types'; + +import './index.scss'; +import { Network } from './Network'; + +const baseClass = 'vant-button'; +const PRESET_IMAGES = ['error', 'search', 'default']; + +export default function Empty({ + imageSize, + description, + image = 'default', + bottom +}: Props) { + console.log(imageSize); + console.log(description); + console.log(image); + + const containerProps = { + className: classnames(`${baseClass}`, []), + style: {} + }; + + const imageProps = { + className: classnames(`${baseClass}__image`, []), + style: {} + }; + + const bottomProps = { + className: classnames(`${baseClass}__bottom`, []), + style: {} + }; + + const descriptionProps = { + className: classnames(`${baseClass}__description`, []), + style: {} + }; + + const renderImage = () => { + if (image === 'network') { + return Network; + } + if (typeof image === 'string') { + if (PRESET_IMAGES.includes(image)) { + image = `https://img.yzcdn.cn/vant/empty-image-${image}.png`; + } + return ; + } else { + return image; + } + }; + + return ( +
+
{renderImage()}
+ {description &&

{description}

} + {bottom &&
{bottom}
} +
+ ); +} diff --git a/src/components/Empty/types.ts b/src/components/Empty/types.ts new file mode 100644 index 000000000..34e605cdd --- /dev/null +++ b/src/components/Empty/types.ts @@ -0,0 +1,8 @@ +import { ReactElement } from 'react'; + +export interface Props { + imageSize?: number | string; + description?: string | ReactElement; + image?: string | ReactElement; + bottom?: ReactElement; +} diff --git a/src/index.tsx b/src/index.tsx index 62b093c1a..0da5f3270 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -12,6 +12,7 @@ import Slider from './components/Slider'; import Checkbox from './components/Checkbox'; import Radio from './components/Radio'; import Stepper from './components/Stepper'; +import Empty from './components/Empty'; export { default as Button } from './components/Button'; export { default as Icon } from './components/Icons'; @@ -27,6 +28,7 @@ export { default as Slider } from './components/Slider'; export { default as Checkbox } from './components/Checkbox'; export { default as Radio } from './components/Radio'; export { default as Stepper } from './components/Stepper'; +export { default as Empty } from './components/Empty'; const Vant = { Button, @@ -42,7 +44,8 @@ const Vant = { Slider, Checkbox, Radio, - Stepper + Stepper, + Empty }; export default Vant; diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 89bf0f928..774599e84 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -16,3 +16,20 @@ $icon-dot-size: 8px; // popups $popup-alpha: 0.5; $popup-background-color: #000; + +// Empty +$gray-6: #969799; +$font-size-md: 14px; +$line-height-md: 20px; + +// $empty-padding: @padding-xl 0; +$empty-padding: 32px; +$empty-image-size: 160px; +// $empty-description-margin-top: @padding-md; +$empty-description-margin-top: 16px; +$empty-description-padding: 0 60px; +$empty-description-color: $gray-6; +$empty-description-font-size: $font-size-md; +$empty-description-line-height: $line-height-md; +$empty-bottom-margin-top: 24px; + From 76ea9d67178d895b54cac180e724e46f17e4535b Mon Sep 17 00:00:00 2001 From: wujingquan Date: Wed, 23 Dec 2020 23:33:04 +0800 Subject: [PATCH 2/3] empty complete. --- src/components/Empty/helper.tsx | 53 -------------------------- src/components/Empty/index.stories.tsx | 8 ++-- src/components/Empty/index.tsx | 7 +--- src/styles/variables.scss | 12 +++--- 4 files changed, 13 insertions(+), 67 deletions(-) delete mode 100644 src/components/Empty/helper.tsx diff --git a/src/components/Empty/helper.tsx b/src/components/Empty/helper.tsx deleted file mode 100644 index 1ab60a5aa..000000000 --- a/src/components/Empty/helper.tsx +++ /dev/null @@ -1,53 +0,0 @@ -// import React, { ReactElement } from 'react'; - -// import SpinnerLoading from '../../assets/icons/loaders/Spinner'; -// import CircularLoading from '../../assets/icons/loaders/Circular'; - -// import { LoadingIconProps } from './types'; - -// export const renderLoadingIcon = ({ -// className, -// loadingType = 'circular', -// loadingText, -// loadingSize -// }: LoadingIconProps): ReactElement => { -// return ( -// -// {loadingType === 'spinner' ? ( -// -// ) : ( -// -// )} -// {loadingText && {loadingText}} -// -// ); -// }; - -// export const getContrastTextColor = (colorHex: string): string => { -// let r, g, b; -// if (colorHex.length !== 6 && colorHex.slice(0, 3) !== 'rgb') { -// return 'black'; -// } // return black if color is not supplied -// else if (colorHex.length === 6) { -// r = parseInt(colorHex[0] + colorHex[1], 16); -// g = parseInt(colorHex[2] + colorHex[3], 16); -// b = parseInt(colorHex[4] + colorHex[5], 16); -// } else if (colorHex.length !== 6 && colorHex.slice(0, 3) === 'rgb') { -// const startIndex = colorHex.indexOf('('); -// const endIndex = colorHex.indexOf(')'); -// const rgb = colorHex -// .slice(startIndex + 1, endIndex - startIndex) -// .split(','); -// r = rgb[0]; -// g = rgb[1]; -// b = rgb[2]; -// } -// const brightness = (r * 299 + g * 587 + b * 114) / 1000; -// return brightness > 125 ? 'black' : 'white'; -// }; - -// export const colorType = (colorHex: string): string => { -// if (colorHex.length !== 6 && colorHex.slice(0, 3) === 'rgb') return colorHex; -// const result = '#' + colorHex; -// return result; -// }; diff --git a/src/components/Empty/index.stories.tsx b/src/components/Empty/index.stories.tsx index 4306190f8..af730e595 100644 --- a/src/components/Empty/index.stories.tsx +++ b/src/components/Empty/index.stories.tsx @@ -26,28 +26,28 @@ export const ImageType = () => { return (
{showType === 'error' && ( )} @@ -78,7 +80,7 @@ export const CustomImage = () => ( ); -export const BottomContent = () => ( +export const CustomBottomContent = () => (