feat: 增加用户信息banner设计

仿discord
pull/81/head
moonrailgun 3 years ago
parent 96ddcb312a
commit 944d7a7c72

@ -9,6 +9,8 @@ import type { AvatarProps as AntdAvatarProps } from 'antd/lib/avatar';
import { getTextColorHex } from './utils';
import { isValidStr } from '../utils';
export { getTextColorHex };
export interface AvatarProps extends AntdAvatarProps {
name?: string;
isOnline?: boolean;

@ -1,5 +1,5 @@
export { AutoFolder } from './AutoFolder';
export { Avatar } from './Avatar';
export { Avatar, getTextColorHex } from './Avatar';
export { AvatarWithPreview } from './AvatarWithPreview';
export { CombinedAvatar } from './Avatar/combined';
export { DelayTip } from './DelayTip';

@ -0,0 +1,42 @@
import { fetchImagePrimaryColor } from '@/utils/image-helper';
import React from 'react';
import { AvatarWithPreview, getTextColorHex } from 'tailchat-design';
import { useAsync, UserBaseInfo } from 'tailchat-shared';
/**
*
*/
export const UserProfileContainer: React.FC<{ userInfo: UserBaseInfo }> =
React.memo((props) => {
const { userInfo } = props;
const { value: bannerColor } = useAsync(async () => {
if (!userInfo.avatar) {
return getTextColorHex(userInfo.nickname);
}
const rgba = await fetchImagePrimaryColor(userInfo.avatar);
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
}, [userInfo.avatar]);
return (
<div className="relative bg-inherit">
<div
style={{
width: '100%',
height: 60,
backgroundColor: bannerColor,
}}
/>
<div className="absolute p-1 rounded-1/2 -mt-11 ml-3 bg-inherit">
<AvatarWithPreview
size={80}
src={userInfo.avatar}
name={userInfo.nickname}
/>
</div>
<div className="p-2 mt-10">{props.children}</div>
</div>
);
});
UserProfileContainer.displayName = 'UserProfileContainer';

@ -1,28 +1,34 @@
import { fetchImagePrimaryColor } from '@/utils/image-helper';
import { Tag } from 'antd';
import React from 'react';
import { AvatarWithPreview } from 'tailchat-design';
import React, { useEffect } from 'react';
import { t, UserBaseInfo } from 'tailchat-shared';
import { UserProfileContainer } from '../UserProfileContainer';
export const GroupUserPopover: React.FC<{
userInfo: UserBaseInfo;
}> = React.memo((props) => {
const { userInfo } = props;
useEffect(() => {
if (userInfo.avatar) {
fetchImagePrimaryColor(userInfo.avatar).then((rgba) => {
console.log('fetchImagePrimaryColor', rgba);
});
}
}, [userInfo.avatar]);
return (
<div className="w-80">
<AvatarWithPreview
size={80}
src={userInfo.avatar}
name={userInfo.nickname}
/>
<div className="text-xl mt-2">
<span className="font-semibold">{userInfo.nickname}</span>
<span className="opacity-60 ml-1">#{userInfo.discriminator}</span>
</div>
<div className="w-80 -mx-4 -my-3 bg-inherit">
<UserProfileContainer userInfo={userInfo}>
<div className="text-xl">
<span className="font-semibold">{userInfo.nickname}</span>
<span className="opacity-60 ml-1">#{userInfo.discriminator}</span>
</div>
<div>
{userInfo.temporary && <Tag color="processing">{t('游客')}</Tag>}
</div>
<div>
{userInfo.temporary && <Tag color="processing">{t('游客')}</Tag>}
</div>
</UserProfileContainer>
</div>
);
});

@ -57,3 +57,9 @@
vertical-align: text-top;
}
}
.ant-popover {
.ant-popover-inner-content {
background-color: inherit;
}
}

@ -0,0 +1,57 @@
/**
*
*/
async function loadImage(url: string): Promise<HTMLImageElement> {
const el = document.createElement('img');
return new Promise((resolve, reject) => {
el.onload = () => resolve(el);
el.onerror = reject;
el.src = url;
el.crossOrigin = 'Anonymous';
});
}
/**
*
*/
export async function fetchImagePrimaryColor(imageUrl: string) {
const img = await loadImage(imageUrl);
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
if (!ctx) {
return { r: 0, g: 0, b: 0, a: 0 };
}
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let r = 0;
let g = 0;
let b = 0;
let a = 0;
for (let row = 0; row < imageData.height; row++) {
for (let col = 0; col < imageData.width; col++) {
r += imageData.data[(imageData.width * row + col) * 4];
g += imageData.data[(imageData.width * row + col) * 4 + 1];
b += imageData.data[(imageData.width * row + col) * 4 + 2];
a += imageData.data[(imageData.width * row + col) * 4 + 3];
}
}
const sum = imageData.width * imageData.height;
r = Math.round(r / sum);
g = Math.round(g / sum);
b = Math.round(b / sum);
a = Math.round(a / sum);
return {
r,
g,
b,
a,
};
}

@ -55,6 +55,9 @@ module.exports = {
},
extend: {
colors: {
inherit: {
DEFAULT: 'inherit',
},
navbar: {
light: colors.coolGray[300],
dark: colors.coolGray[900],

Loading…
Cancel
Save