mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 04:46:40 +07:00
added profile quick info
This commit is contained in:
parent
1241d2c784
commit
141b9c0d60
8 changed files with 84 additions and 32 deletions
|
@ -16,10 +16,11 @@ interface Props {
|
|||
const CommentAvatar: FC<Props> = ({ user, className }) => {
|
||||
return (
|
||||
<MenuButton
|
||||
position="top"
|
||||
position="top-start"
|
||||
icon={
|
||||
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
|
||||
}
|
||||
translucentMenu
|
||||
>
|
||||
<ProfileQuickInfo user={user} />
|
||||
</MenuButton>
|
||||
|
|
|
@ -12,6 +12,7 @@ interface MenuButtonProps {
|
|||
position?: 'top-end' | 'bottom-end' | 'top-start' | 'bottom-start' | 'top' | 'bottom';
|
||||
icon?: ReactNode;
|
||||
className?: string;
|
||||
translucentMenu?: boolean;
|
||||
}
|
||||
|
||||
const modifiers = [
|
||||
|
@ -28,8 +29,9 @@ const MenuButton: FC<MenuButtonProps> = ({
|
|||
children,
|
||||
className,
|
||||
icon = <Icon icon="dots-vertical" size={24} />,
|
||||
translucentMenu,
|
||||
}) => {
|
||||
const { focused, onFocus, onBlur } = useFocusEvent(true, 150);
|
||||
const { focused, onFocus, onBlur } = useFocusEvent(false, 150);
|
||||
|
||||
return (
|
||||
<Manager>
|
||||
|
@ -49,7 +51,13 @@ const MenuButton: FC<MenuButtonProps> = ({
|
|||
{focused && (
|
||||
<Popper placement={position} modifiers={modifiers}>
|
||||
{({ style, ref, placement }) => (
|
||||
<div style={style} ref={ref} className={classNames(styles.popper, styles[placement])}>
|
||||
<div
|
||||
style={style}
|
||||
ref={ref}
|
||||
className={classNames(styles.popper, styles[placement], {
|
||||
[styles.translucent]: translucentMenu,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -5,19 +5,13 @@
|
|||
|
||||
@import "src/styles/variables.scss";
|
||||
|
||||
@keyframes appear {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
|
||||
.popper {
|
||||
@include outer_shadow;
|
||||
@include blur($content_bg, 15px, 0.5);
|
||||
|
||||
background-color: $menu_bg;
|
||||
box-sizing: border-box;
|
||||
z-index: 12;
|
||||
border-radius: $radius;
|
||||
animation: appear forwards 250ms;
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
|
@ -27,14 +21,27 @@
|
|||
border-width: 0 10px 10px 10px;
|
||||
border-color: transparent transparent lighten($menu_bg, 6%) transparent;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&.bottom-end::after {
|
||||
top: -11px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
&.bottom-start::after {
|
||||
top: -11px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
&.bottom::after {
|
||||
top: -11px;
|
||||
left: 50%;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
&.top-end::after {
|
||||
border-width: 10px 10px 0 10px;
|
||||
border-color: darken($menu_bg, 8%) transparent transparent transparent;
|
||||
top: auto;
|
||||
bottom: -11px;
|
||||
}
|
||||
|
||||
|
@ -43,7 +50,6 @@
|
|||
border-color: darken($menu_bg, 8%) transparent transparent transparent;
|
||||
top: auto;
|
||||
bottom: -11px;
|
||||
right: auto;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
|
@ -52,8 +58,7 @@
|
|||
border-color: darken($menu_bg, 8%) transparent transparent transparent;
|
||||
top: auto;
|
||||
bottom: -11px;
|
||||
right: auto;
|
||||
left: 50%;
|
||||
margin-left: -10px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import React, { FC, useMemo } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Avatar } from '~/components/common/Avatar';
|
||||
import { Filler } from '~/components/containers/Filler';
|
||||
import { Group } from '~/components/containers/Group';
|
||||
import { useRandomPhrase } from '~/constants/phrases';
|
||||
import { useUserActiveStatus } from '~/hooks/auth/useUserActiveStatus';
|
||||
import { useUserDescription } from '~/hooks/auth/useUserDescription';
|
||||
import { useColorGradientFromString } from '~/hooks/color/useColorGradientFromString';
|
||||
import { IUser } from '~/types/auth';
|
||||
import { generateGradientFromColor } from '~/utils/color';
|
||||
|
@ -16,15 +20,10 @@ interface ProfileQuickInfoProps {
|
|||
}
|
||||
|
||||
const ProfileQuickInfo: FC<ProfileQuickInfoProps> = ({ user }) => {
|
||||
const style = useMemo(() => {
|
||||
const color = user.photo?.metadata?.dominant_color;
|
||||
const gradient = color && generateGradientFromColor(color);
|
||||
|
||||
return gradient ? { background: gradient } : undefined;
|
||||
}, [user]);
|
||||
const isActive = useUserActiveStatus(user.last_seen);
|
||||
|
||||
return (
|
||||
<Group className={styles.wrapper} style={style}>
|
||||
<Group className={styles.wrapper}>
|
||||
<Group className={styles.top} horizontal>
|
||||
<div>
|
||||
<Avatar url={path(['photo', 'url'], user)} username={user.username} />
|
||||
|
@ -33,6 +32,10 @@ const ProfileQuickInfo: FC<ProfileQuickInfoProps> = ({ user }) => {
|
|||
<Filler>
|
||||
<h5 className={styles.fullname}>{user.fullname || user.username}</h5>
|
||||
<div className={styles.username}>~{user.username}</div>
|
||||
|
||||
<div className={classNames(styles.status, { [styles.active]: isActive })}>
|
||||
{isActive ? 'в сознании' : 'деактивирован'}
|
||||
</div>
|
||||
</Filler>
|
||||
</Group>
|
||||
</Group>
|
||||
|
|
|
@ -26,3 +26,19 @@ div.top.top {
|
|||
.fullname {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.status {
|
||||
font: $font_12_regular;
|
||||
margin-top: $gap;
|
||||
|
||||
&.active {
|
||||
color: $olive;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '●';
|
||||
margin-right: 5px;
|
||||
padding-top: 1px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
|
14
src/hooks/auth/useUserActiveStatus.ts
Normal file
14
src/hooks/auth/useUserActiveStatus.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { differenceInDays, parseISO } from 'date-fns';
|
||||
|
||||
import { INACTIVE_ACCOUNT_DAYS } from '~/constants/user';
|
||||
|
||||
const today = new Date();
|
||||
|
||||
export const useUserActiveStatus = (lastSeen?: string) => {
|
||||
try {
|
||||
const lastSeenDate = lastSeen ? parseISO(lastSeen) : undefined;
|
||||
return lastSeenDate && differenceInDays(today, lastSeenDate) < INACTIVE_ACCOUNT_DAYS;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
|
@ -1,11 +1,7 @@
|
|||
import { differenceInDays, parseISO } from 'date-fns';
|
||||
|
||||
import { useRandomPhrase } from '~/constants/phrases';
|
||||
import { INACTIVE_ACCOUNT_DAYS } from '~/constants/user';
|
||||
import { useUserActiveStatus } from '~/hooks/auth/useUserActiveStatus';
|
||||
import { IUser } from '~/types/auth';
|
||||
|
||||
const today = new Date();
|
||||
|
||||
export const useUserDescription = (user?: Partial<IUser>) => {
|
||||
const randomPhrase = useRandomPhrase('USER_DESCRIPTION');
|
||||
|
||||
|
@ -13,8 +9,9 @@ export const useUserDescription = (user?: Partial<IUser>) => {
|
|||
return '';
|
||||
}
|
||||
|
||||
const lastSeen = user.last_seen ? parseISO(user.last_seen) : undefined;
|
||||
if (!lastSeen || differenceInDays(today, lastSeen) > INACTIVE_ACCOUNT_DAYS) {
|
||||
const isActive = useUserActiveStatus(user.last_seen);
|
||||
|
||||
if (!isActive) {
|
||||
return 'Юнит деактивирован';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { adjustHue, darken, desaturate, parseToHsla } from 'color2k';
|
||||
import { adjustHue, darken, desaturate, parseToHsla, transparentize } from 'color2k';
|
||||
|
||||
import { DEFAULT_DOMINANT_COLOR } from '~/constants/node';
|
||||
import { stringToColour } from '~/utils/dom';
|
||||
|
@ -30,8 +30,16 @@ export const generateGradientFromColor = (
|
|||
val: string,
|
||||
saturation = 3,
|
||||
lightness = 3,
|
||||
angle = 155
|
||||
angle = 155,
|
||||
opacity = 1
|
||||
) => {
|
||||
const [color, second, third] = generateColorTriplet(val, saturation, lightness);
|
||||
return `linear-gradient(${angle}deg, ${color}, ${second}, ${third})`;
|
||||
const [first, second, third] = generateColorTriplet(val, saturation, lightness).map(it => {
|
||||
if (opacity > 1 || opacity < 0) {
|
||||
return it;
|
||||
}
|
||||
|
||||
return transparentize(it, 1 - opacity);
|
||||
});
|
||||
|
||||
return `linear-gradient(${angle}deg, ${first}, ${second}, ${third})`;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue