From 47587812b809fee2a95c76266d9d0e42fc4ac1ca Mon Sep 17 00:00:00 2001
From: crupest <crupest@outlook.com>
Date: Tue, 15 Jun 2021 14:14:28 +0800
Subject: ...

---
 FrontEnd/src/views/common/Menu.tsx | 92 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 FrontEnd/src/views/common/Menu.tsx

(limited to 'FrontEnd/src/views/common/Menu.tsx')

diff --git a/FrontEnd/src/views/common/Menu.tsx b/FrontEnd/src/views/common/Menu.tsx
new file mode 100644
index 00000000..ae73a331
--- /dev/null
+++ b/FrontEnd/src/views/common/Menu.tsx
@@ -0,0 +1,92 @@
+import React from "react";
+import classnames from "classnames";
+import { OverlayTrigger, OverlayTriggerProps, Popover } from "react-bootstrap";
+import { useTranslation } from "react-i18next";
+
+import { BootstrapThemeColor, convertI18nText, I18nText } from "@/common";
+
+export type MenuItem =
+  | {
+      type: "divider";
+    }
+  | {
+      type: "button";
+      text: I18nText;
+      iconClassName?: string;
+      color?: BootstrapThemeColor;
+      onClick: () => void;
+    };
+
+export type MenuItems = MenuItem[];
+
+export interface MenuProps {
+  items: MenuItems;
+  className?: string;
+  onItemClicked?: () => void;
+}
+
+const Menu: React.FC<MenuProps> = ({ items, className, onItemClicked }) => {
+  const { t } = useTranslation();
+
+  return (
+    <div className={classnames("cru-menu", className)}>
+      {items.map((item, index) => {
+        if (item.type === "divider") {
+          return <div key={index} className="cru-menu-divider" />;
+        } else {
+          return (
+            <div
+              key={index}
+              className={classnames(
+                "cru-menu-item",
+                `color-${item.color ?? "primary"}`
+              )}
+              onClick={() => {
+                item.onClick();
+                onItemClicked?.();
+              }}
+            >
+              {item.iconClassName != null ? (
+                <i
+                  className={classnames(
+                    item.iconClassName,
+                    "cru-menu-item-icon"
+                  )}
+                />
+              ) : null}
+              {convertI18nText(item.text, t)}
+            </div>
+          );
+        }
+      })}
+    </div>
+  );
+};
+
+export default Menu;
+
+export interface PopupMenuProps {
+  items: MenuItems;
+  children: OverlayTriggerProps["children"];
+}
+
+export const PopupMenu: React.FC<PopupMenuProps> = ({ items, children }) => {
+  const [show, setShow] = React.useState<boolean>(false);
+  const toggle = (): void => setShow(!show);
+
+  return (
+    <OverlayTrigger
+      trigger="click"
+      rootClose
+      overlay={
+        <Popover id="menu-popover">
+          <Menu items={items} onItemClicked={() => setShow(false)} />
+        </Popover>
+      }
+      show={show}
+      onToggle={toggle}
+    >
+      {children}
+    </OverlayTrigger>
+  );
+};
-- 
cgit v1.2.3

