mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 04:46:40 +07:00
made better profile popups
This commit is contained in:
parent
141b9c0d60
commit
0564fe29e2
5 changed files with 94 additions and 91 deletions
|
@ -16,7 +16,7 @@ interface Props {
|
|||
const CommentAvatar: FC<Props> = ({ user, className }) => {
|
||||
return (
|
||||
<MenuButton
|
||||
position="top-start"
|
||||
position="auto"
|
||||
icon={
|
||||
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
|
||||
}
|
||||
|
|
|
@ -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 { Manager, Popper, Reference } from 'react-popper';
|
||||
import { usePopper } from 'react-popper';
|
||||
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { useFocusEvent } from '~/hooks/dom/useFocusEvent';
|
||||
|
@ -9,61 +10,69 @@ import { useFocusEvent } from '~/hooks/dom/useFocusEvent';
|
|||
import styles from './styles.module.scss';
|
||||
|
||||
interface MenuButtonProps {
|
||||
position?: 'top-end' | 'bottom-end' | 'top-start' | 'bottom-start' | 'top' | 'bottom';
|
||||
position?: Placement;
|
||||
icon?: ReactNode;
|
||||
className?: string;
|
||||
translucentMenu?: boolean;
|
||||
activate?: 'hover' | 'focus';
|
||||
}
|
||||
|
||||
const modifiers = [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [5, 10],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const MenuButton: FC<MenuButtonProps> = ({
|
||||
position = 'bottom-end',
|
||||
children,
|
||||
className,
|
||||
icon = <Icon icon="dots-vertical" size={24} />,
|
||||
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 (
|
||||
<Manager>
|
||||
<Reference>
|
||||
{({ ref }) => (
|
||||
<button
|
||||
className={classNames(styles.menu, className)}
|
||||
ref={ref}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
)}
|
||||
</Reference>
|
||||
<>
|
||||
<button
|
||||
className={classNames(styles.menu, className)}
|
||||
ref={setReferenceElement}
|
||||
onFocus={focus.onFocus}
|
||||
onBlur={focus.onBlur}
|
||||
onMouseOver={hover.onFocus}
|
||||
onMouseOut={hover.onBlur}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
|
||||
{focused && (
|
||||
<Popper placement={position} modifiers={modifiers}>
|
||||
{({ style, ref, placement }) => (
|
||||
<div
|
||||
style={style}
|
||||
ref={ref}
|
||||
className={classNames(styles.popper, styles[placement], {
|
||||
[styles.translucent]: translucentMenu,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</Popper>
|
||||
)}
|
||||
</Manager>
|
||||
<div
|
||||
style={popper.styles.popper}
|
||||
ref={setPopperElement}
|
||||
{...popper.attributes.popper}
|
||||
className={classNames(styles.popper, {
|
||||
[styles.translucent]: translucentMenu,
|
||||
[styles.visible]: visible,
|
||||
})}
|
||||
>
|
||||
<div style={popper.styles.arrow} ref={setArrowElement} className={styles.arrow} />
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -12,53 +12,44 @@
|
|||
box-sizing: border-box;
|
||||
z-index: 12;
|
||||
border-radius: $radius;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
touch-action: none;
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
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;
|
||||
bottom: -11px;
|
||||
}
|
||||
|
||||
&.top-start::after {
|
||||
border-width: 10px 10px 0 10px;
|
||||
border-color: darken($menu_bg, 8%) transparent transparent transparent;
|
||||
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;
|
||||
&.visible {
|
||||
visibility: visible;
|
||||
pointer-events: all;
|
||||
touch-action: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
|
||||
[data-popper-placement*='bottom'] & {
|
||||
border-width: 0 10px 10px 10px;
|
||||
border-color: transparent transparent lighten($menu_bg, 6%) transparent;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
[data-popper-placement*='top'] & {
|
||||
border-width: 10px 10px 0 10px;
|
||||
border-color: lighten($menu_bg, 6%) transparent transparent transparent;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
[data-popper-placement*='right'] & {
|
||||
border-width: 10px 10px 10px 0;
|
||||
border-color: transparent lighten($menu_bg, 6%) transparent transparent;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
[data-popper-placement*='left'] & {
|
||||
border-width: 10px 0 10px 10px;
|
||||
border-color: transparent transparent transparent lighten($menu_bg, 6%);
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue