1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

made better profile popups

This commit is contained in:
Fedor Katurov 2022-07-20 15:06:29 +07:00
parent 141b9c0d60
commit 0564fe29e2
5 changed files with 94 additions and 91 deletions

View file

@ -16,7 +16,7 @@ interface Props {
const CommentAvatar: FC<Props> = ({ user, className }) => { const CommentAvatar: FC<Props> = ({ user, className }) => {
return ( return (
<MenuButton <MenuButton
position="top-start" position="auto"
icon={ icon={
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} /> <Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
} }

View file

@ -1,7 +1,8 @@
import React, { FC, ReactNode } from 'react'; import React, { FC, ReactNode, useState } from 'react';
import { Placement } from '@popperjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { Manager, Popper, Reference } from 'react-popper'; import { usePopper } from 'react-popper';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { useFocusEvent } from '~/hooks/dom/useFocusEvent'; import { useFocusEvent } from '~/hooks/dom/useFocusEvent';
@ -9,61 +10,69 @@ import { useFocusEvent } from '~/hooks/dom/useFocusEvent';
import styles from './styles.module.scss'; import styles from './styles.module.scss';
interface MenuButtonProps { interface MenuButtonProps {
position?: 'top-end' | 'bottom-end' | 'top-start' | 'bottom-start' | 'top' | 'bottom'; position?: Placement;
icon?: ReactNode; icon?: ReactNode;
className?: string; className?: string;
translucentMenu?: boolean; translucentMenu?: boolean;
activate?: 'hover' | 'focus';
} }
const modifiers = [
{
name: 'offset',
options: {
offset: [5, 10],
},
},
];
const MenuButton: FC<MenuButtonProps> = ({ const MenuButton: FC<MenuButtonProps> = ({
position = 'bottom-end', position = 'bottom-end',
children, children,
className, className,
icon = <Icon icon="dots-vertical" size={24} />, icon = <Icon icon="dots-vertical" size={24} />,
translucentMenu, translucentMenu,
activate = 'focus',
}) => { }) => {
const { focused, onFocus, onBlur } = useFocusEvent(false, 150); const focus = useFocusEvent(false, 150);
const hover = useFocusEvent(false, 150);
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const [arrowElement, setArrowElement] = useState<HTMLDivElement | null>(null);
const popper = usePopper(referenceElement, popperElement, {
placement: position,
modifiers: [
{ name: 'arrow', options: { element: arrowElement } },
{
name: 'offset',
options: {
offset: [5, 10],
},
},
],
});
const visible = activate === 'focus' ? focus.focused : hover.focused;
return ( return (
<Manager> <>
<Reference> <button
{({ ref }) => ( className={classNames(styles.menu, className)}
<button ref={setReferenceElement}
className={classNames(styles.menu, className)} onFocus={focus.onFocus}
ref={ref} onBlur={focus.onBlur}
onFocus={onFocus} onMouseOver={hover.onFocus}
onBlur={onBlur} onMouseOut={hover.onBlur}
> >
{icon} {icon}
</button> </button>
)}
</Reference>
{focused && ( <div
<Popper placement={position} modifiers={modifiers}> style={popper.styles.popper}
{({ style, ref, placement }) => ( ref={setPopperElement}
<div {...popper.attributes.popper}
style={style} className={classNames(styles.popper, {
ref={ref} [styles.translucent]: translucentMenu,
className={classNames(styles.popper, styles[placement], { [styles.visible]: visible,
[styles.translucent]: translucentMenu, })}
})} >
> <div style={popper.styles.arrow} ref={setArrowElement} className={styles.arrow} />
{children} {children}
</div> </div>
)} </>
</Popper>
)}
</Manager>
); );
}; };

View file

@ -12,53 +12,44 @@
box-sizing: border-box; box-sizing: border-box;
z-index: 12; z-index: 12;
border-radius: $radius; border-radius: $radius;
visibility: hidden;
pointer-events: none;
touch-action: none;
&::after { &.visible {
content: ' '; visibility: visible;
width: 0; pointer-events: all;
height: 0; touch-action: initial;
border-style: solid; }
border-width: 0 10px 10px 10px; }
border-color: transparent transparent lighten($menu_bg, 6%) transparent;
position: absolute; .arrow {
} width: 0;
height: 0;
&.bottom-end::after { border-style: solid;
top: -11px; position: absolute;
right: 10px;
} [data-popper-placement*='bottom'] & {
border-width: 0 10px 10px 10px;
&.bottom-start::after { border-color: transparent transparent lighten($menu_bg, 6%) transparent;
top: -11px; top: -10px;
left: 10px; }
}
[data-popper-placement*='top'] & {
&.bottom::after { border-width: 10px 10px 0 10px;
top: -11px; border-color: lighten($menu_bg, 6%) transparent transparent transparent;
left: 50%; bottom: -10px;
margin-left: -15px; }
}
[data-popper-placement*='right'] & {
&.top-end::after { border-width: 10px 10px 10px 0;
border-width: 10px 10px 0 10px; border-color: transparent lighten($menu_bg, 6%) transparent transparent;
border-color: darken($menu_bg, 8%) transparent transparent transparent; left: -10px;
bottom: -11px; }
}
[data-popper-placement*='left'] & {
&.top-start::after { border-width: 10px 0 10px 10px;
border-width: 10px 10px 0 10px; border-color: transparent transparent transparent lighten($menu_bg, 6%);
border-color: darken($menu_bg, 8%) transparent transparent transparent; right: -10px;
top: auto;
bottom: -11px;
left: 10px;
}
&.top::after {
border-width: 10px 10px 0 10px;
border-color: darken($menu_bg, 8%) transparent transparent transparent;
top: auto;
bottom: -11px;
left: 50%;
margin-left: -15px;
} }
} }

View file

@ -29,7 +29,7 @@ const ProfileQuickInfo: FC<ProfileQuickInfoProps> = ({ user }) => {
<Avatar url={path(['photo', 'url'], user)} username={user.username} /> <Avatar url={path(['photo', 'url'], user)} username={user.username} />
</div> </div>
<Filler> <Filler className={styles.names}>
<h5 className={styles.fullname}>{user.fullname || user.username}</h5> <h5 className={styles.fullname}>{user.fullname || user.username}</h5>
<div className={styles.username}>~{user.username}</div> <div className={styles.username}>~{user.username}</div>

View file

@ -18,6 +18,9 @@ div.top.top {
justify-content: flex-start; justify-content: flex-start;
} }
.names {
}
.username { .username {
font: $font_12_regular; font: $font_12_regular;
opacity: 0.5; opacity: 0.5;