Skip to content

Commit 474e769

Browse files
committed
feat(components): badge
1 parent 38464fe commit 474e769

File tree

5 files changed

+259
-0
lines changed

5 files changed

+259
-0
lines changed

src/components/Badge/index.scss

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@import '../../styles/variables.scss';
2+
3+
.vant-badge {
4+
display: inline-block;
5+
box-sizing: border-box;
6+
min-width: $badge-size;
7+
padding: $badge-padding;
8+
color: $badge-color;
9+
font-weight: $badge-font-weight;
10+
font-size: $badge-font-size;
11+
font-family: $badge-font-family;
12+
line-height: 1.2;
13+
text-align: center;
14+
background-color: $badge-background-color;
15+
border: $badge-border-width solid $white;
16+
border-radius: $border-radius-max;
17+
18+
&__fixed {
19+
position: absolute;
20+
top: 0;
21+
right: 0;
22+
transform: translate(50%, -50%);
23+
transform-origin: 100%;
24+
}
25+
26+
&__dot {
27+
width: $badge-dot-size;
28+
min-width: 0;
29+
height: $badge-dot-size;
30+
background-color: $badge-dot-color;
31+
border-radius: 100%;
32+
}
33+
34+
&__wrapper {
35+
position: relative;
36+
display: inline-block;
37+
}
38+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React from 'react';
2+
import Badge from '.';
3+
import '../../styles/stories.scss';
4+
5+
export default {
6+
title: 'Badge',
7+
component: Badge
8+
};
9+
const style = {
10+
width: '50px',
11+
height: '50px',
12+
backgroundColor: '#f2f3f5',
13+
borderRadius: '8px'
14+
};
15+
const Child = () => {
16+
return <div style={style} />;
17+
};
18+
const Basic = () => {
19+
return (
20+
<Badge content={12} max={99}>
21+
<Child />
22+
</Badge>
23+
);
24+
};
25+
const BasicHigher = () => {
26+
return (
27+
<Badge content={120} max={99}>
28+
<Child />
29+
</Badge>
30+
);
31+
};
32+
const Color = () => {
33+
return (
34+
<Badge content='120' max='102' color='#1989FA'>
35+
<Child />
36+
</Badge>
37+
);
38+
};
39+
const Dot = () => {
40+
return (
41+
<Badge content={120} max={99} color='#1989FA' dot>
42+
<Child />
43+
</Badge>
44+
);
45+
};
46+
const FCContent = () => {
47+
return <div>FCContent</div>;
48+
};
49+
const WithFC = () => {
50+
// console.log(+FCContent)
51+
return (
52+
<Badge content={FCContent} max={99} color='#1989FA'>
53+
<Child />
54+
</Badge>
55+
);
56+
};
57+
class ClassContent extends React.Component {
58+
render() {
59+
return <div>ClassContent</div>;
60+
}
61+
}
62+
const WithClass = () => {
63+
return (
64+
<Badge content={ClassContent} max={99} color='#1989FA'>
65+
<Child />
66+
</Badge>
67+
);
68+
};
69+
export const All = () => {
70+
return (
71+
<div className='storybook__container badge'>
72+
<Basic />
73+
<BasicHigher />
74+
<Color />
75+
<Dot />
76+
<WithFC />
77+
<WithClass />
78+
</div>
79+
);
80+
};

src/components/Badge/index.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React, { FC, ReactNode } from 'react';
2+
import './index.scss';
3+
import classnames from '../../utils/classNames';
4+
export interface BadgeProps {
5+
content: string | number | ReactNode;
6+
color?: string;
7+
dot?: boolean;
8+
max: number | string;
9+
}
10+
const baseClass = 'vant-badge';
11+
const Badge: FC<BadgeProps> = ({
12+
content,
13+
color = '#ee0a24',
14+
dot = false,
15+
max,
16+
children
17+
}) => {
18+
const renderContent = () => {
19+
if (dot) return '';
20+
if (content) {
21+
if (!!max && Number.isInteger(+content) && +content > max) {
22+
return <>{`${max}+`}</>;
23+
} else {
24+
if (typeof content === 'string' || typeof content === 'number') {
25+
return <>{`${content}`}</>;
26+
} else {
27+
const ContentComponent = content as FC;
28+
return <>{ContentComponent ? <ContentComponent /> : null}</>;
29+
}
30+
}
31+
}
32+
return '';
33+
};
34+
const renderBadge = () => {
35+
if (content || dot) {
36+
return (
37+
<div
38+
className={classnames(baseClass, [{ dot }, { fixed: !!children }])}
39+
style={{ background: color }}
40+
>
41+
{renderContent()}
42+
</div>
43+
);
44+
}
45+
};
46+
if (children) {
47+
return (
48+
<div className='vant-badge__wrapper'>
49+
{children}
50+
{renderBadge()}
51+
</div>
52+
);
53+
}
54+
return <>{renderBadge()}</>;
55+
};
56+
export default Badge;

src/styles/stories.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,7 @@ body {
145145
font-weight: 100;
146146
}
147147
}
148+
.badge{
149+
display: flex;
150+
justify-content: space-around;
151+
}

src/styles/variables.scss

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,72 @@
1+
// Color Palette
2+
$black: #000;
3+
$white: #fff;
4+
$gray-1: #f7f8fa;
5+
$gray-2: #f2f3f5;
6+
$gray-3: #ebedf0;
7+
$gray-4: #dcdee0;
8+
$gray-5: #c8c9cc;
9+
$gray-6: #969799;
10+
$gray-7: #646566;
11+
$gray-8: #323233;
12+
$red: #ee0a24;
13+
$blue: #1989fa;
14+
$orange: #ff976a;
15+
$orange-dark: #ed6a0c;
16+
$orange-light: #fffbe8;
17+
$green: #07c160;
18+
19+
// Gradient Colors
20+
$gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
21+
$gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);
22+
23+
// Component Colors
24+
$text-color: $gray-8;
25+
$active-color: $gray-2;
26+
$active-opacity: 0.7;
27+
$disabled-opacity: 0.5;
28+
$background-color: $gray-1;
29+
$background-color-light: #fafafa;
30+
$text-link-color: #576b95;
31+
32+
// Padding
33+
$padding-base: 4px;
34+
$padding-xs: $padding-base * 2;
35+
$padding-sm: $padding-base * 3;
36+
$padding-md: $padding-base * 4;
37+
$padding-lg: $padding-base * 6;
38+
$padding-xl: $padding-base * 8;
39+
40+
// Font
41+
$font-size-xs: 10px;
42+
$font-size-sm: 12px;
43+
$font-size-md: 14px;
44+
$font-size-lg: 16px;
45+
$font-weight-bold: 500;
46+
$line-height-xs: 14px;
47+
$line-height-sm: 18px;
48+
$line-height-md: 20px;
49+
$line-height-lg: 22px;
50+
$base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
51+
Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB',
52+
'Microsoft Yahei', sans-serif;
53+
$price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,
54+
sans-serif;
55+
56+
// Animation
57+
$animation-duration-base: 0.3s;
58+
$animation-duration-fast: 0.2s;
59+
$animation-timing-function-enter: ease-out;
60+
$animation-timing-function-leave: ease-in;
61+
62+
// Border
63+
$border-color: $gray-3;
64+
$border-width-base: 1px;
65+
$border-radius-sm: 2px;
66+
$border-radius-md: 4px;
67+
$border-radius-lg: 8px;
68+
$border-radius-max: 999px;
69+
170
// loaders
271
$loader-size: 20px;
372
$loader-animation-duration: 2s;
@@ -16,3 +85,15 @@ $icon-dot-size: 8px;
1685
// popups
1786
$popup-alpha: 0.5;
1887
$popup-background-color: #000;
88+
89+
// badge
90+
$badge-size: 16px;
91+
$badge-color: $white;
92+
$badge-padding: 0 3px;
93+
$badge-font-size: $font-size-sm;
94+
$badge-font-weight: $font-weight-bold;
95+
$badge-border-width: $border-width-base;
96+
$badge-background-color: $red;
97+
$badge-dot-color: $red;
98+
$badge-dot-size: 8px;
99+
$badge-font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif

0 commit comments

Comments
 (0)