mirror of https://github.com/msgbyte/tailchat
refactor: move avatar into design
parent
a655a0d136
commit
5245c49635
@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import { Avatar } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Tailchat/Avatar',
|
||||
component: Avatar,
|
||||
argTypes: {
|
||||
name: {
|
||||
description: '显示名称,用于无图片下的展示',
|
||||
},
|
||||
isOnline: {
|
||||
description: '是否在线, 可不传',
|
||||
},
|
||||
size: {
|
||||
description: '图标大小',
|
||||
type: 'number',
|
||||
},
|
||||
src: {
|
||||
description: '头像图片地址',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof Avatar>;
|
||||
|
||||
const Template: ComponentStory<typeof Avatar> = (args) => <Avatar {...args} />;
|
||||
|
||||
export const normal = Template.bind({});
|
||||
normal.args = {
|
||||
name: 'Anonymous',
|
||||
};
|
||||
|
||||
export const withSize = Template.bind({});
|
||||
withSize.args = {
|
||||
name: 'Anonymous',
|
||||
size: 48,
|
||||
};
|
||||
|
||||
export const withOnline = Template.bind({});
|
||||
withOnline.args = {
|
||||
name: 'Anonymous',
|
||||
isOnline: true,
|
||||
};
|
||||
|
||||
export const withImage = Template.bind({});
|
||||
withImage.args = {
|
||||
name: 'Anonymous',
|
||||
src: 'http://dummyimage.com/50x50',
|
||||
};
|
@ -0,0 +1,76 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Avatar as AntdAvatar, Badge } from 'antd';
|
||||
import _head from 'lodash/head';
|
||||
import _upperCase from 'lodash/upperCase';
|
||||
import _isNil from 'lodash/isNil';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import _isNumber from 'lodash/isNumber';
|
||||
import type { AvatarProps as AntdAvatarProps } from 'antd/lib/avatar';
|
||||
import { getTextColorHex } from './utils';
|
||||
import { isValidStr } from '../utils';
|
||||
|
||||
interface AvatarProps extends AntdAvatarProps {
|
||||
name?: string;
|
||||
isOnline?: boolean;
|
||||
}
|
||||
export const Avatar: React.FC<AvatarProps> = React.memo((_props) => {
|
||||
const { isOnline, ...props } = _props;
|
||||
const src = isValidStr(props.src) ? props.src : undefined;
|
||||
|
||||
const name = useMemo(() => _upperCase(_head(props.name)), [props.name]);
|
||||
|
||||
const color = useMemo(
|
||||
() =>
|
||||
// 如果src为空 且 icon为空 则给个固定颜色
|
||||
_isEmpty(src) && _isNil(props.icon)
|
||||
? getTextColorHex(props.name)
|
||||
: undefined,
|
||||
[src, props.icon, props.name]
|
||||
);
|
||||
|
||||
const style: React.CSSProperties = useMemo(
|
||||
() => ({
|
||||
cursor: 'inherit',
|
||||
userSelect: 'none',
|
||||
...props.style,
|
||||
backgroundColor: color,
|
||||
}),
|
||||
[props.style, color]
|
||||
);
|
||||
|
||||
if (_isNumber(props.size) && typeof style.fontSize === 'undefined') {
|
||||
// 如果props.size是数字且没有指定文字大小
|
||||
// 则自动增加fontSize大小
|
||||
style.fontSize = props.size * 0.4;
|
||||
}
|
||||
|
||||
const inner = (
|
||||
<AntdAvatar {...props} src={src} style={style}>
|
||||
{name}
|
||||
</AntdAvatar>
|
||||
);
|
||||
|
||||
if (typeof isOnline === 'boolean') {
|
||||
const style = {
|
||||
bottom: 0,
|
||||
top: 'auto',
|
||||
};
|
||||
|
||||
if (isOnline === true) {
|
||||
return (
|
||||
<Badge dot={true} color="green" style={style}>
|
||||
{inner}
|
||||
</Badge>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Badge dot={true} color="#999" style={style}>
|
||||
{inner}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inner;
|
||||
});
|
||||
Avatar.displayName = 'Avatar';
|
@ -0,0 +1,34 @@
|
||||
import _isString from 'lodash/isString';
|
||||
import str2int from 'str2int';
|
||||
|
||||
const colors = [
|
||||
'#333333',
|
||||
'#2c3e50',
|
||||
'#8e44ad',
|
||||
'#2980b9',
|
||||
'#27ae60',
|
||||
'#16a085',
|
||||
'#f39c12',
|
||||
'#d35400',
|
||||
'#c0392b',
|
||||
'#3498db',
|
||||
'#9b59b6',
|
||||
'#2ecc71',
|
||||
'#1abc9c',
|
||||
'#f1c40f',
|
||||
'#e74c3c',
|
||||
'#e67e22',
|
||||
];
|
||||
|
||||
/**
|
||||
* 根据文本内容返回一个内置色卡的颜色
|
||||
* @param text 文本
|
||||
*/
|
||||
export function getTextColorHex(text: unknown): string {
|
||||
if (!text || !_isString(text)) {
|
||||
return '#ffffff'; // 如果获取不到文本,则返回白色
|
||||
}
|
||||
|
||||
const id = str2int(text);
|
||||
return colors[id % colors.length];
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 是否一个可用的字符串
|
||||
* 定义为有长度的字符串
|
||||
*/
|
||||
export function isValidStr(str: unknown): str is string {
|
||||
return typeof str == 'string' && str !== '';
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Tailchat 共享配置
|
||||
*/
|
||||
|
||||
export const config = {
|
||||
color: [
|
||||
'#333333',
|
||||
'#2c3e50',
|
||||
'#8e44ad',
|
||||
'#2980b9',
|
||||
'#27ae60',
|
||||
'#16a085',
|
||||
'#f39c12',
|
||||
'#d35400',
|
||||
'#c0392b',
|
||||
'#3498db',
|
||||
'#9b59b6',
|
||||
'#2ecc71',
|
||||
'#1abc9c',
|
||||
'#f1c40f',
|
||||
'#e74c3c',
|
||||
'#e67e22',
|
||||
],
|
||||
};
|
@ -1,75 +1 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Avatar as AntdAvatar, Badge } from 'antd';
|
||||
import _head from 'lodash/head';
|
||||
import _upperCase from 'lodash/upperCase';
|
||||
import _isNil from 'lodash/isNil';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import _isNumber from 'lodash/isNumber';
|
||||
import type { AvatarProps as AntdAvatarProps } from 'antd/lib/avatar';
|
||||
import { getTextColorHex, isValidStr } from 'tailchat-shared';
|
||||
|
||||
interface AvatarProps extends AntdAvatarProps {
|
||||
name?: string;
|
||||
isOnline?: boolean;
|
||||
}
|
||||
export const Avatar: React.FC<AvatarProps> = React.memo((_props) => {
|
||||
const { isOnline, ...props } = _props;
|
||||
const src = isValidStr(props.src) ? props.src : undefined;
|
||||
|
||||
const name = useMemo(() => _upperCase(_head(props.name)), [props.name]);
|
||||
|
||||
const color = useMemo(
|
||||
() =>
|
||||
// 如果src为空 且 icon为空 则给个固定颜色
|
||||
_isEmpty(src) && _isNil(props.icon)
|
||||
? getTextColorHex(props.name)
|
||||
: undefined,
|
||||
[src, props.icon, props.name]
|
||||
);
|
||||
|
||||
const style: React.CSSProperties = useMemo(
|
||||
() => ({
|
||||
cursor: 'inherit',
|
||||
userSelect: 'none',
|
||||
...props.style,
|
||||
backgroundColor: color,
|
||||
}),
|
||||
[props.style, color]
|
||||
);
|
||||
|
||||
if (_isNumber(props.size) && typeof style.fontSize === 'undefined') {
|
||||
// 如果props.size是数字且没有指定文字大小
|
||||
// 则自动增加fontSize大小
|
||||
style.fontSize = props.size * 0.4;
|
||||
}
|
||||
|
||||
const inner = (
|
||||
<AntdAvatar {...props} src={src} style={style}>
|
||||
{name}
|
||||
</AntdAvatar>
|
||||
);
|
||||
|
||||
if (typeof isOnline === 'boolean') {
|
||||
const style = {
|
||||
bottom: 0,
|
||||
top: 'auto',
|
||||
};
|
||||
|
||||
if (isOnline === true) {
|
||||
return (
|
||||
<Badge dot={true} color="green" style={style}>
|
||||
{inner}
|
||||
</Badge>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Badge dot={true} color="#999" style={style}>
|
||||
{inner}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inner;
|
||||
});
|
||||
Avatar.displayName = 'Avatar';
|
||||
export { Avatar } from 'tailchat-design';
|
||||
|
Loading…
Reference in New Issue