mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
added node edit menu
This commit is contained in:
parent
f185914c7c
commit
74f4c7562b
16 changed files with 320 additions and 175 deletions
64
src/components/menu/MenuButton/index.tsx
Normal file
64
src/components/menu/MenuButton/index.tsx
Normal file
|
@ -0,0 +1,64 @@
|
|||
import React, { FC, ReactNode } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Manager, Popper, Reference } from 'react-popper';
|
||||
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { useFocusEvent } from '~/hooks/dom/useFocusEvent';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface MenuButtonProps {
|
||||
icon?: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const modifiers = [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [5, 10],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const MenuButton: FC<MenuButtonProps> = ({
|
||||
children,
|
||||
className,
|
||||
icon = <Icon icon="dots-vertical" size={24} />,
|
||||
}) => {
|
||||
const { focused, onFocus, onBlur } = useFocusEvent(false, 150);
|
||||
|
||||
return (
|
||||
<Manager>
|
||||
<Reference>
|
||||
{({ ref }) => (
|
||||
<button
|
||||
className={classNames(styles.menu, className)}
|
||||
ref={ref}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
)}
|
||||
</Reference>
|
||||
|
||||
{focused && (
|
||||
<Popper placement="bottom-end" modifiers={modifiers}>
|
||||
{({ style, ref, placement }) => (
|
||||
<div
|
||||
style={style}
|
||||
ref={ref}
|
||||
className={classNames(styles.popper, { [styles.top]: placement === 'top-end' })}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</Popper>
|
||||
)}
|
||||
</Manager>
|
||||
);
|
||||
};
|
||||
|
||||
export { MenuButton };
|
40
src/components/menu/MenuButton/styles.module.scss
Normal file
40
src/components/menu/MenuButton/styles.module.scss
Normal file
|
@ -0,0 +1,40 @@
|
|||
.menu {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@import "src/styles/variables.scss";
|
||||
|
||||
@keyframes appear {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
|
||||
.popper {
|
||||
@include outer_shadow;
|
||||
|
||||
background-color: $menu_bg;
|
||||
box-sizing: border-box;
|
||||
z-index: 12;
|
||||
border-radius: $radius;
|
||||
animation: appear forwards 250ms;
|
||||
|
||||
&::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;
|
||||
top: -11px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
&.top::after {
|
||||
border-width: 10px 10px 0 10px;
|
||||
border-color: darken($menu_bg, 8%) transparent transparent transparent;
|
||||
top: auto;
|
||||
bottom: -11px;
|
||||
}
|
||||
}
|
23
src/components/menu/MenuItemWithIcon/index.tsx
Normal file
23
src/components/menu/MenuItemWithIcon/index.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface MenuItemWithIconProps {
|
||||
children: string;
|
||||
icon: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const MenuItemWithIcon: FC<MenuItemWithIconProps> = ({ children, icon, onClick }) => (
|
||||
<button className={styles.item} onClick={onClick}>
|
||||
<div className={styles.icon}>
|
||||
<Icon icon={icon} size={20} />
|
||||
</div>
|
||||
|
||||
<div className={styles.text}>{children}</div>
|
||||
</button>
|
||||
);
|
||||
|
||||
export { MenuItemWithIcon };
|
29
src/components/menu/MenuItemWithIcon/styles.module.scss
Normal file
29
src/components/menu/MenuItemWithIcon/styles.module.scss
Normal file
|
@ -0,0 +1,29 @@
|
|||
@import "src/styles/variables";
|
||||
|
||||
.item {
|
||||
@include row_shadow;
|
||||
@include hover_opacity;
|
||||
|
||||
font: $font_14_medium;
|
||||
line-height: 20px;
|
||||
padding: $gap + 2px $gap $gap - 2px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: white;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex: 0 0 20px;
|
||||
margin-right: $gap;
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
padding-right: $gap;
|
||||
white-space: nowrap;
|
||||
}
|
31
src/components/menu/SeparatedMenu/index.tsx
Normal file
31
src/components/menu/SeparatedMenu/index.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import React, { FC, ReactNode, useMemo } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface SeparatedMenuProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SeparatedMenu: FC<SeparatedMenuProps> = ({ children, className }) => {
|
||||
const items = useMemo<ReactNode[]>(() => {
|
||||
if (!children) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (Array.isArray(children) ? children : [children]).filter(it => it);
|
||||
}, [children]);
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.menu, className)}>
|
||||
{items.map((item, index) => (
|
||||
<div className={styles.item} key={index}>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { SeparatedMenu };
|
29
src/components/menu/SeparatedMenu/styles.module.scss
Normal file
29
src/components/menu/SeparatedMenu/styles.module.scss
Normal file
|
@ -0,0 +1,29 @@
|
|||
@import "src/styles/mixins";
|
||||
@import "src/styles/variables";
|
||||
|
||||
.menu {
|
||||
flex: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-left: $gap * 4;
|
||||
position: relative;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
@include inner_shadow;
|
||||
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
height: 16px;
|
||||
background: darken($content_bg, 1%);
|
||||
display: flex;
|
||||
top: 5px;
|
||||
right: -$gap * 2 - 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
5
src/components/menu/index.ts
Normal file
5
src/components/menu/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export * from './VerticalMenu';
|
||||
export * from './HorizontalMenu';
|
||||
export * from './MenuButton';
|
||||
export * from './MenuItemWithIcon';
|
||||
export * from './SeparatedMenu';
|
Loading…
Add table
Add a link
Reference in a new issue