mirror of https://github.com/msgbyte/tailchat
refactor: avatar and move main
parent
b34fa903d5
commit
0cdd7a10bb
@ -0,0 +1,31 @@
|
|||||||
|
import { isAvailableString, isUrl } from '../string-helper';
|
||||||
|
|
||||||
|
describe('string-helper', () => {
|
||||||
|
describe('isAvailableString', () => {
|
||||||
|
test.each<[any, boolean]>([
|
||||||
|
['any string', true],
|
||||||
|
['', false],
|
||||||
|
[1, false],
|
||||||
|
[() => {}, false],
|
||||||
|
[{}, false],
|
||||||
|
[[], false],
|
||||||
|
[undefined, false],
|
||||||
|
[null, false],
|
||||||
|
])('%p => %p', (url, res) => {
|
||||||
|
expect(isAvailableString(url)).toBe(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isUrl', () => {
|
||||||
|
test.each<[string, boolean]>([
|
||||||
|
['http://baidu.com', true],
|
||||||
|
['https://baidu.com', true],
|
||||||
|
['ws://baidu.com', true],
|
||||||
|
['wss://baidu.com', true],
|
||||||
|
['baidu.com', false],
|
||||||
|
['baidu', false],
|
||||||
|
])('%s => %p', (url, res) => {
|
||||||
|
expect(isUrl(url)).toBe(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,57 @@
|
|||||||
|
import _isString from 'lodash/isString';
|
||||||
|
import str2int from 'str2int';
|
||||||
|
import urlRegex from 'url-regex';
|
||||||
|
import { config } from '../config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个字符串是否可用()
|
||||||
|
* @param str 要判断的字符串
|
||||||
|
*/
|
||||||
|
export function isAvailableString(str: any): boolean {
|
||||||
|
return typeof str === 'string' && str.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个字符串是否是url
|
||||||
|
* @param str 要判断的字符串
|
||||||
|
*/
|
||||||
|
export function isUrl(str: string) {
|
||||||
|
return urlRegex({ exact: true }).test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否是一个blobUrl
|
||||||
|
* @param str url字符串
|
||||||
|
*/
|
||||||
|
export const isBlobUrl = (str: string) => {
|
||||||
|
return _isString(str) && str.startsWith('blob:');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一段字符串中的所有url
|
||||||
|
* @param str 字符串
|
||||||
|
*/
|
||||||
|
export const getUrls = (str: string): string[] => {
|
||||||
|
return str.match(urlRegex()) ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于判定环境变量的值
|
||||||
|
*/
|
||||||
|
export function is(it: string) {
|
||||||
|
return !!it && it !== '0' && it !== 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文本内容返回一个内置色卡的颜色
|
||||||
|
* @param text 文本
|
||||||
|
*/
|
||||||
|
export function getTextColorHex(text: string): string {
|
||||||
|
if (!text || !_isString(text)) {
|
||||||
|
return '#ffffff'; // 如果获取不到文本,则返回白色
|
||||||
|
}
|
||||||
|
|
||||||
|
const color = config.color;
|
||||||
|
const id = str2int(text);
|
||||||
|
return color[id % color.length];
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { Avatar as AntdAvatar } 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 'pawchat-shared';
|
||||||
|
|
||||||
|
interface AvatarProps extends AntdAvatarProps {
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
export const Avatar: React.FC<AvatarProps> = React.memo((props) => {
|
||||||
|
const src = typeof props.src !== 'string' ? 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AntdAvatar {...props} src={src} style={style}>
|
||||||
|
{name}
|
||||||
|
</AntdAvatar>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Avatar.displayName = 'Avatar';
|
||||||
|
|
||||||
|
export default Avatar;
|
Loading…
Reference in New Issue