feat: sub menu
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"remove_account": "Remove account",
|
||||
"remove_account_desc": "Are you sure remove this account?",
|
||||
"remove_from_channel": "Remove from channel",
|
||||
"roles": "Roles",
|
||||
"set_admin": "Set as admin",
|
||||
"set_normal": "Set as normal user",
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"remove_account": "注销账号",
|
||||
"remove_account_desc": "确定永久注销该账号?",
|
||||
"remove_from_channel": "从频道移除",
|
||||
"roles": "设置角色",
|
||||
"set_admin": "设置为管理员",
|
||||
"set_normal": "设置为普通用户",
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="#475467" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_18505_74130" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
|
||||
<rect width="16" height="16" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_18505_74130)">
|
||||
<path d="M4.76666 14.0667C4.6 13.9 4.51666 13.7028 4.51666 13.475C4.51666 13.2472 4.6 13.05 4.76666 12.8834L9.65 8.00002L4.75 3.10002C4.59444 2.94446 4.51666 2.75002 4.51666 2.51669C4.51666 2.28335 4.6 2.08335 4.76666 1.91669C4.93333 1.75002 5.13055 1.66669 5.35833 1.66669C5.58611 1.66669 5.78333 1.75002 5.95 1.91669L11.55 7.53335C11.6167 7.60002 11.6639 7.67224 11.6917 7.75002C11.7194 7.8278 11.7333 7.91113 11.7333 8.00002C11.7333 8.08891 11.7194 8.17224 11.6917 8.25002C11.6639 8.3278 11.6167 8.40002 11.55 8.46669L5.93333 14.0834C5.77777 14.2389 5.58611 14.3167 5.35833 14.3167C5.13055 14.3167 4.93333 14.2334 4.76666 14.0667Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 953 B |
@@ -1,18 +1,82 @@
|
||||
import { FC, ReactElement } from "react";
|
||||
import Tippy from "@tippyjs/react";
|
||||
|
||||
import IconArrow from "@/assets/icons/arrow.right.svg";
|
||||
import IconChecked from "@/assets/icons/check.sign.svg";
|
||||
|
||||
export interface Item {
|
||||
title: string;
|
||||
icon?: string | ReactElement;
|
||||
handler: (param: any) => void;
|
||||
handler?: (param: any) => void;
|
||||
underline?: boolean;
|
||||
danger?: boolean;
|
||||
checked?: boolean;
|
||||
subs?: Item[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
items: Item[];
|
||||
hideMenu?: () => void;
|
||||
}
|
||||
|
||||
const WrapWithSubmenu = ({
|
||||
items,
|
||||
hideMenu,
|
||||
child
|
||||
}: {
|
||||
items: Item[];
|
||||
hideMenu: () => void | null;
|
||||
child: ReactElement;
|
||||
}) => {
|
||||
return (
|
||||
<Tippy
|
||||
interactive
|
||||
placement="right-start"
|
||||
trigger="mouseenter focus"
|
||||
content={
|
||||
<ul className="context-menu">
|
||||
{items.map((sub) => {
|
||||
const {
|
||||
title,
|
||||
icon = null,
|
||||
handler = (evt) => {
|
||||
evt.preventDefault();
|
||||
if (hideMenu) {
|
||||
hideMenu();
|
||||
}
|
||||
},
|
||||
underline = false,
|
||||
danger = false,
|
||||
checked = false
|
||||
} = sub;
|
||||
return (
|
||||
<li
|
||||
className={`item ${underline ? "bottom_line" : ""} ${danger ? "danger" : ""}`}
|
||||
key={title}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
if (checked) return;
|
||||
handler(evt);
|
||||
if (hideMenu) {
|
||||
hideMenu();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
{title}
|
||||
{checked && (
|
||||
<IconChecked className="group-hover:fill-white dark:fill-gray-300 absolute right-2 top-2" />
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
>
|
||||
{child}
|
||||
</Tippy>
|
||||
);
|
||||
};
|
||||
const ContextMenu: FC<Props> = ({ items = [], hideMenu = null }) => {
|
||||
return (
|
||||
<ul className="context-menu">
|
||||
@@ -28,8 +92,33 @@ const ContextMenu: FC<Props> = ({ items = [], hideMenu = null }) => {
|
||||
}
|
||||
},
|
||||
underline = false,
|
||||
danger = false
|
||||
danger = false,
|
||||
subs = []
|
||||
} = item;
|
||||
if (subs.length > 0)
|
||||
return (
|
||||
<WrapWithSubmenu
|
||||
items={subs}
|
||||
hideMenu={hideMenu}
|
||||
child={
|
||||
<li
|
||||
className={`item group ${underline ? "bottom_line" : ""} ${
|
||||
danger ? "danger" : ""
|
||||
}`}
|
||||
key={title}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
{title}
|
||||
<IconArrow className="group-hover:fill-white dark:fill-gray-300 absolute right-2 top-2" />
|
||||
</li>
|
||||
}
|
||||
></WrapWithSubmenu>
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
className={`item ${underline ? "bottom_line" : ""} ${danger ? "danger" : ""}`}
|
||||
|
||||
@@ -60,8 +60,20 @@ const UserContextMenu: FC<Props> = ({ enable = false, uid, cid, visible, hide, c
|
||||
handler: copyEmail
|
||||
},
|
||||
canUpdateRole && {
|
||||
title: isAdmin ? t("set_normal") : t("set_admin"),
|
||||
handler: updateRole
|
||||
title: t("roles"),
|
||||
handler: updateRole,
|
||||
subs: [
|
||||
{
|
||||
title: t("set_normal"),
|
||||
checked: !isAdmin,
|
||||
handler: updateRole
|
||||
},
|
||||
{
|
||||
title: t("set_admin"),
|
||||
checked: isAdmin,
|
||||
handler: updateRole
|
||||
}
|
||||
]
|
||||
},
|
||||
canRemoveFromChannel && {
|
||||
danger: true,
|
||||
|
||||
Reference in New Issue
Block a user