mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
made better profile menu
This commit is contained in:
parent
0564fe29e2
commit
efe7800743
9 changed files with 42 additions and 84 deletions
|
@ -20,7 +20,6 @@ const CommentAvatar: FC<Props> = ({ user, className }) => {
|
||||||
icon={
|
icon={
|
||||||
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
|
<Avatar url={path(['photo', 'url'], user)} username={user.username} className={className} />
|
||||||
}
|
}
|
||||||
translucentMenu
|
|
||||||
>
|
>
|
||||||
<ProfileQuickInfo user={user} />
|
<ProfileQuickInfo user={user} />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, { FC, useCallback } from 'react';
|
||||||
|
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
|
import { MenuButton, MenuItemWithIcon } from '~/components/menu';
|
||||||
import { ImagePresets } from '~/constants/urls';
|
import { ImagePresets } from '~/constants/urls';
|
||||||
import { IUser } from '~/types/auth';
|
import { IUser } from '~/types/auth';
|
||||||
import { getURL } from '~/utils/dom';
|
import { getURL } from '~/utils/dom';
|
||||||
|
@ -28,19 +29,23 @@ const UserButton: FC<IProps> = ({ user: { username, photo }, authOpenProfile, on
|
||||||
<Group horizontal className={styles.user_button}>
|
<Group horizontal className={styles.user_button}>
|
||||||
<div className={styles.username}>{username}</div>
|
<div className={styles.username}>{username}</div>
|
||||||
|
|
||||||
|
<MenuButton
|
||||||
|
position="bottom"
|
||||||
|
translucent={false}
|
||||||
|
icon={
|
||||||
<div
|
<div
|
||||||
className={styles.user_avatar}
|
className={styles.user_avatar}
|
||||||
style={{ backgroundImage: `url('${getURL(photo, ImagePresets.avatar)}')` }}
|
style={{ backgroundImage: `url('${getURL(photo, ImagePresets.avatar)}')` }}
|
||||||
>
|
>
|
||||||
{(!photo || !photo.id) && <Icon icon="profile" />}
|
{(!photo || !photo.id) && <Icon icon="profile" />}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuItemWithIcon onClick={onProfileOpen}>Профиль</MenuItemWithIcon>
|
||||||
|
<MenuItemWithIcon onClick={onSettingsOpen}>Настройки</MenuItemWithIcon>
|
||||||
|
<MenuItemWithIcon onClick={onLogout}>Выдох</MenuItemWithIcon>
|
||||||
|
</MenuButton>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<div className={styles.menu}>
|
|
||||||
<div onClick={onProfileOpen}>Профиль</div>
|
|
||||||
<div onClick={onSettingsOpen}>Настройки</div>
|
|
||||||
<div onClick={onLogout}>Выдох</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,63 +9,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
|
||||||
position: absolute;
|
|
||||||
right: -$gap;
|
|
||||||
top: 100%;
|
|
||||||
padding: $gap;
|
|
||||||
border-radius: $radius;
|
|
||||||
display: none;
|
|
||||||
z-index: 1;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: $gap;
|
|
||||||
display: none;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: ' ';
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 0 0 16px 16px;
|
|
||||||
border-color: transparent transparent $content_bg transparent;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: -4px;
|
|
||||||
transform: translate(-20px, 0);
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
background: $content_bg;
|
|
||||||
padding: $gap $gap * 2;
|
|
||||||
cursor: pointer;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: opacity 0.25s;
|
|
||||||
width: 100%;
|
|
||||||
padding-right: 40px;
|
|
||||||
transition: background-color 0.25s;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-top-left-radius: $radius;
|
|
||||||
border-top-right-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom-left-radius: $radius;
|
|
||||||
border-bottom-right-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > div {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user_button {
|
.user_button {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
|
|
|
@ -13,17 +13,19 @@ interface MenuButtonProps {
|
||||||
position?: Placement;
|
position?: Placement;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
translucentMenu?: boolean;
|
|
||||||
activate?: 'hover' | 'focus';
|
activate?: 'hover' | 'focus';
|
||||||
|
fixed?: boolean;
|
||||||
|
translucent?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuButton: FC<MenuButtonProps> = ({
|
const MenuButton: FC<MenuButtonProps> = ({
|
||||||
position = 'bottom-end',
|
position = 'auto',
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
icon = <Icon icon="dots-vertical" size={24} />,
|
icon = <Icon icon="dots-vertical" size={24} />,
|
||||||
translucentMenu,
|
translucent = true,
|
||||||
activate = 'focus',
|
activate = 'focus',
|
||||||
|
fixed,
|
||||||
}) => {
|
}) => {
|
||||||
const focus = useFocusEvent(false, 150);
|
const focus = useFocusEvent(false, 150);
|
||||||
const hover = useFocusEvent(false, 150);
|
const hover = useFocusEvent(false, 150);
|
||||||
|
@ -34,12 +36,13 @@ const MenuButton: FC<MenuButtonProps> = ({
|
||||||
|
|
||||||
const popper = usePopper(referenceElement, popperElement, {
|
const popper = usePopper(referenceElement, popperElement, {
|
||||||
placement: position,
|
placement: position,
|
||||||
|
strategy: fixed ? 'fixed' : 'absolute',
|
||||||
modifiers: [
|
modifiers: [
|
||||||
{ name: 'arrow', options: { element: arrowElement } },
|
{ name: 'arrow', options: { element: arrowElement } },
|
||||||
{
|
{
|
||||||
name: 'offset',
|
name: 'offset',
|
||||||
options: {
|
options: {
|
||||||
offset: [5, 10],
|
offset: [-10, 10],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -65,7 +68,8 @@ const MenuButton: FC<MenuButtonProps> = ({
|
||||||
ref={setPopperElement}
|
ref={setPopperElement}
|
||||||
{...popper.attributes.popper}
|
{...popper.attributes.popper}
|
||||||
className={classNames(styles.popper, {
|
className={classNames(styles.popper, {
|
||||||
[styles.translucent]: translucentMenu,
|
[styles.fixed]: fixed,
|
||||||
|
[styles.translucent]: translucent,
|
||||||
[styles.visible]: visible,
|
[styles.visible]: visible,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
.popper {
|
.popper {
|
||||||
@include outer_shadow;
|
@include outer_shadow;
|
||||||
@include blur($content_bg, 15px, 0.5);
|
|
||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 12;
|
z-index: 12;
|
||||||
|
@ -15,12 +14,21 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
background-color: transparentize($content_bg, 0.05);
|
||||||
|
|
||||||
&.visible {
|
&.visible {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
touch-action: initial;
|
touch-action: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.fixed {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.translucent {
|
||||||
|
@include blur($content_bg, 15px, 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
|
|
|
@ -6,15 +6,17 @@ import styles from './styles.module.scss';
|
||||||
|
|
||||||
interface MenuItemWithIconProps {
|
interface MenuItemWithIconProps {
|
||||||
children: string;
|
children: string;
|
||||||
icon: string;
|
icon?: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuItemWithIcon: FC<MenuItemWithIconProps> = ({ children, icon, onClick }) => (
|
const MenuItemWithIcon: FC<MenuItemWithIconProps> = ({ children, icon, onClick }) => (
|
||||||
<button className={styles.item} onClick={onClick}>
|
<button className={styles.item} onClick={onClick}>
|
||||||
|
{icon && (
|
||||||
<div className={styles.icon}>
|
<div className={styles.icon}>
|
||||||
<Icon icon={icon} size={20} />
|
<Icon icon={icon} size={20} />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.text}>{children}</div>
|
<div className={styles.text}>{children}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
flex: 0 0 20px;
|
flex: 0 0 20px;
|
||||||
margin-right: $gap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-right: $gap;
|
padding: 0 $gap;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
|
|
||||||
@keyframes appear {
|
@keyframes appear {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
|
||||||
transform: translate(0, -$header_height);
|
transform: translate(0, -$header_height);
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
|
||||||
transform: translate(0, 0);
|
transform: translate(0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue