diff --git a/web/package.json b/web/package.json
index 6a522be..5b8e7eb 100644
--- a/web/package.json
+++ b/web/package.json
@@ -8,6 +8,9 @@
     "lint": "eslint --ext .js,.ts,.tsx, src"
   },
   "dependencies": {
+    "@emotion/react": "^11.10.4",
+    "@emotion/styled": "^11.10.4",
+    "@mui/material": "^5.10.7",
     "@reduxjs/toolkit": "^1.8.1",
     "axios": "^0.27.2",
     "copy-to-clipboard": "^3.3.2",
diff --git a/web/src/components/Alert.tsx b/web/src/components/Alert.tsx
new file mode 100644
index 0000000..81b6f58
--- /dev/null
+++ b/web/src/components/Alert.tsx
@@ -0,0 +1,94 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
+import { createRoot } from "react-dom/client";
+import Icon from "./Icon";
+
+type DialogStyle = "info" | "warning";
+
+interface Props {
+  title: string;
+  content: string;
+  style?: DialogStyle;
+  closeBtnText?: string;
+  confirmBtnText?: string;
+  onClose?: () => void;
+  onConfirm?: () => void;
+}
+
+const defaultProps = {
+  title: "",
+  content: "",
+  style: "info",
+  closeBtnText: "Close",
+  confirmBtnText: "Confirm",
+  onClose: () => null,
+  onConfirm: () => null,
+};
+
+const Alert: React.FC<Props> = (props: Props) => {
+  const { title, content, closeBtnText, confirmBtnText, onClose, onConfirm, style } = {
+    ...defaultProps,
+    ...props,
+  };
+
+  const handleCloseBtnClick = () => {
+    onClose();
+  };
+
+  const handleConfirmBtnClick = async () => {
+    onConfirm();
+  };
+
+  return (
+    <Dialog open={true}>
+      <DialogTitle className="flex flex-row justify-between items-center w-80">
+        <p className="text-base">{title}</p>
+        <button className="rounded p-1 hover:bg-gray-100" onClick={handleCloseBtnClick}>
+          <Icon.X className="w-5 h-auto text-gray-600" />
+        </button>
+      </DialogTitle>
+      <DialogContent className="w-80">
+        <p className="content-text mb-4">{content}</p>
+        <div className="w-full flex flex-row justify-end items-center">
+          <button className="rounded px-3 py-2 mr-2 hover:opacity-80" onClick={handleCloseBtnClick}>
+            {closeBtnText}
+          </button>
+          <button
+            className={`rounded px-3 py-2 shadow bg-green-600 text-white hover:opacity-80 ${
+              style === "warning" ? "border-red-600 text-red-600 bg-red-100" : ""
+            }`}
+            onClick={handleConfirmBtnClick}
+          >
+            {confirmBtnText}
+          </button>
+        </div>
+      </DialogContent>
+    </Dialog>
+  );
+};
+
+export const showCommonDialog = (props: Props) => {
+  const tempDiv = document.createElement("div");
+  const dialog = createRoot(tempDiv);
+  document.body.append(tempDiv);
+
+  const destory = () => {
+    dialog.unmount();
+    tempDiv.remove();
+  };
+
+  const onClose = () => {
+    if (props.onClose) {
+      props.onClose();
+    }
+    destory();
+  };
+
+  const onConfirm = () => {
+    if (props.onConfirm) {
+      props.onConfirm();
+    }
+    destory();
+  };
+
+  dialog.render(<Alert {...props} onClose={onClose} onConfirm={onConfirm} />);
+};
diff --git a/web/src/components/ChangePasswordDialog.tsx b/web/src/components/ChangePasswordDialog.tsx
index 4ade93f..e72e6f3 100644
--- a/web/src/components/ChangePasswordDialog.tsx
+++ b/web/src/components/ChangePasswordDialog.tsx
@@ -1,9 +1,9 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
 import { useState } from "react";
 import { validate, ValidatorConfig } from "../helpers/validator";
 import useLoading from "../hooks/useLoading";
 import { userService } from "../services";
 import Icon from "./Icon";
-import { generateDialog } from "./Dialog";
 import toastHelper from "./Toast";
 
 const validateConfig: ValidatorConfig = {
@@ -13,15 +13,18 @@ const validateConfig: ValidatorConfig = {
   noChinese: true,
 };
 
-type Props = DialogProps;
+interface Props {
+  onClose: () => void;
+}
 
-const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
+const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
+  const { onClose } = props;
   const [newPassword, setNewPassword] = useState("");
   const [newPasswordAgain, setNewPasswordAgain] = useState("");
   const requestState = useLoading(false);
 
   const handleCloseBtnClick = () => {
-    destroy();
+    onClose();
   };
 
   const handleNewPasswordChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -59,8 +62,8 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
         id: user.id,
         password: newPassword,
       });
+      onClose();
       toastHelper.info("Password changed");
-      handleCloseBtnClick();
     } catch (error: any) {
       console.error(error);
       toastHelper.error(error.response.data.message);
@@ -69,14 +72,14 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
   };
 
   return (
-    <>
-      <div className="max-w-full w-80 flex flex-row justify-between items-center mb-4">
+    <Dialog open={true}>
+      <DialogTitle className="flex flex-row justify-between items-center w-80">
         <p className="text-base">Change Password</p>
-        <button className="rounded p-1 hover:bg-gray-100" onClick={destroy}>
+        <button className="rounded p-1 hover:bg-gray-100" onClick={handleCloseBtnClick}>
           <Icon.X className="w-5 h-auto text-gray-600" />
         </button>
-      </div>
-      <div className="w-full flex flex-col justify-start items-start">
+      </DialogTitle>
+      <DialogContent>
         <div className="w-full flex flex-col justify-start items-start mb-3">
           <span className="mb-2">New Password</span>
           <input
@@ -98,8 +101,8 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
         <div className="w-full flex flex-row justify-end items-center">
           <button
             disabled={requestState.isLoading}
-            className={`rounded px-3 py-2 ${requestState.isLoading ? "opacity-80" : ""}`}
-            onClick={destroy}
+            className={`rounded px-3 py-2 mr-2 hover:opacity-80 ${requestState.isLoading ? "opacity-80" : ""}`}
+            onClick={handleCloseBtnClick}
           >
             Cancel
           </button>
@@ -111,13 +114,9 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
             Save
           </button>
         </div>
-      </div>
-    </>
+      </DialogContent>
+    </Dialog>
   );
 };
 
-function showChangePasswordDialog() {
-  generateDialog({}, ChangePasswordDialog);
-}
-
-export default showChangePasswordDialog;
+export default ChangePasswordDialog;
diff --git a/web/src/components/CreateShortcutDialog.tsx b/web/src/components/CreateShortcutDialog.tsx
index 49a79c1..0c405cc 100644
--- a/web/src/components/CreateShortcutDialog.tsx
+++ b/web/src/components/CreateShortcutDialog.tsx
@@ -1,13 +1,15 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
 import { useEffect, useState } from "react";
 import { shortcutService } from "../services";
 import useLoading from "../hooks/useLoading";
 import Icon from "./Icon";
-import { generateDialog } from "./Dialog";
 import toastHelper from "./Toast";
 
-interface Props extends DialogProps {
+interface Props {
   workspaceId: WorkspaceId;
   shortcutId?: ShortcutId;
+  onClose: () => void;
+  onConfirm?: () => void;
 }
 
 interface State {
@@ -15,7 +17,7 @@ interface State {
 }
 
 const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
-  const { destroy, workspaceId, shortcutId } = props;
+  const { onClose, onConfirm, workspaceId, shortcutId } = props;
   const [state, setState] = useState<State>({
     shortcutCreate: {
       workspaceId: workspaceId,
@@ -90,7 +92,12 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
       } else {
         await shortcutService.createShortcut(state.shortcutCreate);
       }
-      destroy();
+
+      if (onConfirm) {
+        onConfirm();
+      } else {
+        onClose();
+      }
     } catch (error: any) {
       console.error(error);
       toastHelper.error(error.response.data.error || error.response.data.message);
@@ -98,14 +105,14 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <>
-      <div className="max-w-full w-80 sm:w-96 flex flex-row justify-between items-center mb-4">
+    <Dialog open={true}>
+      <DialogTitle className="flex flex-row justify-between items-center w-80 sm:w-96">
         <p className="text-base">{shortcutId ? "Edit Shortcut" : "Create Shortcut"}</p>
-        <button className="rounded p-1 hover:bg-gray-100" onClick={destroy}>
+        <button className="rounded p-1 hover:bg-gray-100" onClick={onClose}>
           <Icon.X className="w-5 h-auto text-gray-600" />
         </button>
-      </div>
-      <div className="w-full flex flex-col justify-start items-start">
+      </DialogTitle>
+      <DialogContent>
         <div className="w-full flex flex-col justify-start items-start mb-3">
           <span className="mb-2">Name</span>
           <input
@@ -184,20 +191,9 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
             Save
           </button>
         </div>
-      </div>
-    </>
+      </DialogContent>
+    </Dialog>
   );
 };
 
-export default function showCreateShortcutDialog(workspaceId: WorkspaceId, shortcutId?: ShortcutId, onDestory?: () => void): void {
-  generateDialog(
-    {
-      onDestory,
-    },
-    CreateShortcutDialog,
-    {
-      workspaceId,
-      shortcutId,
-    }
-  );
-}
+export default CreateShortcutDialog;
diff --git a/web/src/components/CreateWorkspaceDialog.tsx b/web/src/components/CreateWorkspaceDialog.tsx
index dd0def7..44ea268 100644
--- a/web/src/components/CreateWorkspaceDialog.tsx
+++ b/web/src/components/CreateWorkspaceDialog.tsx
@@ -1,12 +1,14 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
 import { useEffect, useState } from "react";
 import { workspaceService } from "../services";
 import useLoading from "../hooks/useLoading";
 import Icon from "./Icon";
-import { generateDialog } from "./Dialog";
 import toastHelper from "./Toast";
 
-interface Props extends DialogProps {
+interface Props {
   workspaceId?: WorkspaceId;
+  onClose: () => void;
+  onConfirm?: () => void;
 }
 
 interface State {
@@ -14,7 +16,7 @@ interface State {
 }
 
 const CreateWorkspaceDialog: React.FC<Props> = (props: Props) => {
-  const { destroy, workspaceId } = props;
+  const { onClose, onConfirm, workspaceId } = props;
   const [state, setState] = useState<State>({
     workspaceCreate: {
       name: "",
@@ -75,7 +77,12 @@ const CreateWorkspaceDialog: React.FC<Props> = (props: Props) => {
           ...state.workspaceCreate,
         });
       }
-      destroy();
+
+      if (onConfirm) {
+        onConfirm();
+      } else {
+        onClose();
+      }
     } catch (error: any) {
       console.error(error);
       toastHelper.error(error.response.data.error || error.response.data.message);
@@ -84,14 +91,14 @@ const CreateWorkspaceDialog: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <>
-      <div className="max-w-full w-80 flex flex-row justify-between items-center mb-4">
+    <Dialog open={true}>
+      <DialogTitle className="flex flex-row justify-between items-center w-80">
         <p className="text-base">{workspaceId ? "Edit Workspace" : "Create Workspace"}</p>
-        <button className="rounded p-1 hover:bg-gray-100" onClick={destroy}>
+        <button className="rounded p-1 hover:bg-gray-100" onClick={onClose}>
           <Icon.X className="w-5 h-auto text-gray-600" />
         </button>
-      </div>
-      <div className="w-full flex flex-col justify-start items-start">
+      </DialogTitle>
+      <DialogContent>
         <div className="w-full flex flex-col justify-start items-start mb-3">
           <span className="mb-2">Name</span>
           <input
@@ -121,13 +128,9 @@ const CreateWorkspaceDialog: React.FC<Props> = (props: Props) => {
             Save
           </button>
         </div>
-      </div>
-    </>
+      </DialogContent>
+    </Dialog>
   );
 };
 
-export default function showCreateWorkspaceDialog(workspaceId?: WorkspaceId): void {
-  generateDialog({}, CreateWorkspaceDialog, {
-    workspaceId,
-  });
-}
+export default CreateWorkspaceDialog;
diff --git a/web/src/components/Dialog/BaseDialog.tsx b/web/src/components/Dialog/BaseDialog.tsx
deleted file mode 100644
index 9f44eb1..0000000
--- a/web/src/components/Dialog/BaseDialog.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { useEffect } from "react";
-import { createRoot } from "react-dom/client";
-import { Provider } from "react-redux";
-import { ANIMATION_DURATION } from "../../helpers/consts";
-import store from "../../store";
-import "../../less/base-dialog.less";
-
-interface DialogConfig {
-  className?: string;
-  clickSpaceDestroy?: boolean;
-  onDestory?: () => void;
-}
-
-interface Props extends DialogConfig, DialogProps {
-  children: React.ReactNode;
-}
-
-const BaseDialog: React.FC<Props> = (props: Props) => {
-  const { children, className, clickSpaceDestroy, destroy } = props;
-
-  useEffect(() => {
-    const handleKeyDown = (event: KeyboardEvent) => {
-      if (event.code === "Escape") {
-        destroy();
-      }
-    };
-
-    document.body.addEventListener("keydown", handleKeyDown);
-
-    return () => {
-      document.body.removeEventListener("keydown", handleKeyDown);
-    };
-  }, []);
-
-  const handleSpaceClicked = () => {
-    if (clickSpaceDestroy) {
-      destroy();
-    }
-  };
-
-  return (
-    <div className={`dialog-wrapper px-2 sm:px-0 ${className}`} onClick={handleSpaceClicked}>
-      <div className="dialog-container" onClick={(e) => e.stopPropagation()}>
-        {children}
-      </div>
-    </div>
-  );
-};
-
-export function generateDialog<T extends DialogProps>(
-  config: DialogConfig,
-  DialogComponent: React.FC<T>,
-  props?: Omit<T, "destroy">
-): DialogCallback {
-  const tempDiv = document.createElement("div");
-  const dialog = createRoot(tempDiv);
-  document.body.append(tempDiv);
-
-  setTimeout(() => {
-    tempDiv.firstElementChild?.classList.add("showup");
-  }, 0);
-
-  const cbs: DialogCallback = {
-    destroy: () => {
-      tempDiv.firstElementChild?.classList.remove("showup");
-      tempDiv.firstElementChild?.classList.add("showoff");
-      setTimeout(() => {
-        dialog.unmount();
-        tempDiv.remove();
-      }, ANIMATION_DURATION);
-
-      if (config.onDestory) {
-        config.onDestory();
-      }
-    },
-  };
-
-  const dialogProps = {
-    ...props,
-    destroy: cbs.destroy,
-  } as T;
-
-  const Fragment = (
-    <Provider store={store}>
-      <BaseDialog destroy={cbs.destroy} clickSpaceDestroy={true} {...config}>
-        <DialogComponent {...dialogProps} />
-      </BaseDialog>
-    </Provider>
-  );
-
-  dialog.render(Fragment);
-
-  return cbs;
-}
diff --git a/web/src/components/Dialog/CommonDialog.tsx b/web/src/components/Dialog/CommonDialog.tsx
deleted file mode 100644
index 3975fc5..0000000
--- a/web/src/components/Dialog/CommonDialog.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import Icon from "../Icon";
-import { generateDialog } from "./BaseDialog";
-import "../../less/common-dialog.less";
-
-type DialogStyle = "info" | "warning";
-
-interface Props extends DialogProps {
-  title: string;
-  content: string;
-  style?: DialogStyle;
-  closeBtnText?: string;
-  confirmBtnText?: string;
-  onClose?: () => void;
-  onConfirm?: () => void;
-}
-
-const defaultProps = {
-  title: "",
-  content: "",
-  style: "info",
-  closeBtnText: "Close",
-  confirmBtnText: "Confirm",
-  onClose: () => null,
-  onConfirm: () => null,
-};
-
-const CommonDialog: React.FC<Props> = (props: Props) => {
-  const { title, content, destroy, closeBtnText, confirmBtnText, onClose, onConfirm, style } = {
-    ...defaultProps,
-    ...props,
-  };
-
-  const handleCloseBtnClick = () => {
-    onClose();
-    destroy();
-  };
-
-  const handleConfirmBtnClick = async () => {
-    onConfirm();
-    destroy();
-  };
-
-  return (
-    <>
-      <div className="dialog-header-container">
-        <p className="title-text">{title}</p>
-        <button className="btn close-btn" onClick={handleCloseBtnClick}>
-          <Icon.X />
-        </button>
-      </div>
-      <div className="dialog-content-container">
-        <p className="content-text">{content}</p>
-        <div className="btns-container">
-          <span className="btn cancel-btn" onClick={handleCloseBtnClick}>
-            {closeBtnText}
-          </span>
-          <span className={`btn confirm-btn ${style}`} onClick={handleConfirmBtnClick}>
-            {confirmBtnText}
-          </span>
-        </div>
-      </div>
-    </>
-  );
-};
-
-interface CommonDialogProps {
-  title: string;
-  content: string;
-  className?: string;
-  style?: DialogStyle;
-  closeBtnText?: string;
-  confirmBtnText?: string;
-  onClose?: () => void;
-  onConfirm?: () => void;
-}
-
-export const showCommonDialog = (props: CommonDialogProps) => {
-  generateDialog(
-    {
-      className: `common-dialog ${props?.className ?? ""}`,
-    },
-    CommonDialog,
-    props
-  );
-};
diff --git a/web/src/components/Dialog/index.ts b/web/src/components/Dialog/index.ts
deleted file mode 100644
index d6e6507..0000000
--- a/web/src/components/Dialog/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { generateDialog } from "./BaseDialog";
diff --git a/web/src/components/Header.tsx b/web/src/components/Header.tsx
index 4aec5a6..c8acd4b 100644
--- a/web/src/components/Header.tsx
+++ b/web/src/components/Header.tsx
@@ -1,102 +1,130 @@
+import { useState } from "react";
 import { Link, useNavigate, useParams } from "react-router-dom";
 import { useAppSelector } from "../store";
 import { userService } from "../services";
 import Icon from "./Icon";
 import Dropdown from "./common/Dropdown";
-import showCreateWorkspaceDialog from "./CreateWorkspaceDialog";
+import CreateWorkspaceDialog from "./CreateWorkspaceDialog";
+
+interface State {
+  showCreateWorkspaceDialog: boolean;
+}
 
 const Header: React.FC = () => {
   const params = useParams();
   const navigate = useNavigate();
   const { user } = useAppSelector((state) => state.user);
   const { workspaceList } = useAppSelector((state) => state.workspace);
+  const [state, setState] = useState<State>({
+    showCreateWorkspaceDialog: false,
+  });
   const activedWorkspace = workspaceList.find((workspace) => workspace.name === params.workspaceName ?? "");
 
+  const handleCreateWorkspaceButtonClick = () => {
+    setState({
+      ...state,
+      showCreateWorkspaceDialog: true,
+    });
+  };
+
   const handleSignOutButtonClick = async () => {
     await userService.doSignOut();
     navigate("/user/auth");
   };
 
   return (
-    <div className="w-full bg-amber-50">
-      <div className="w-full max-w-4xl mx-auto px-3 py-5 flex flex-row justify-between items-center">
-        <div className="flex flex-row justify-start items-center">
-          <Link to={"/"} className="text-base font-mono font-medium cursor-pointer">
-            Corgi
-          </Link>
-          {workspaceList.length > 0 && activedWorkspace !== undefined && (
-            <>
-              <span className="font-mono mx-2 text-gray-200">/</span>
+    <>
+      <div className="w-full bg-amber-50">
+        <div className="w-full max-w-4xl mx-auto px-3 py-5 flex flex-row justify-between items-center">
+          <div className="flex flex-row justify-start items-center">
+            <Link to={"/"} className="text-base font-mono font-medium cursor-pointer">
+              Corgi
+            </Link>
+            {workspaceList.length > 0 && activedWorkspace !== undefined && (
+              <>
+                <span className="font-mono mx-2 text-gray-200">/</span>
+                <Dropdown
+                  trigger={
+                    <button className="flex flex-row justify-end items-center cursor-pointer">
+                      <span className="font-mono">{activedWorkspace?.name}</span>
+                      <Icon.ChevronDown className="ml-1 w-5 h-auto text-gray-600" />
+                    </button>
+                  }
+                  actions={
+                    <>
+                      {workspaceList.map((workspace) => {
+                        return (
+                          <Link
+                            key={workspace.id}
+                            to={`/${workspace.name}`}
+                            className="w-full px-3 leading-10 flex flex-row justify-between items-center text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
+                          >
+                            <span className="truncate">{workspace.name}</span>
+                            {workspace.name === activedWorkspace?.name && <Icon.Check className="w-4 h-auto ml-1 shrink-0" />}
+                          </Link>
+                        );
+                      })}
+                      <hr className="w-full border-t my-1 border-t-gray-100" />
+                      <button
+                        className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
+                        onClick={handleCreateWorkspaceButtonClick}
+                      >
+                        <Icon.Plus className="w-4 h-auto mr-2" /> Create Workspace
+                      </button>
+                    </>
+                  }
+                  actionsClassName="!w-48 !-left-4"
+                ></Dropdown>
+              </>
+            )}
+          </div>
+          <div className="relative">
+            {user ? (
               <Dropdown
                 trigger={
                   <button className="flex flex-row justify-end items-center cursor-pointer">
-                    <span className="font-mono">{activedWorkspace?.name}</span>
+                    <span>{user?.name}</span>
                     <Icon.ChevronDown className="ml-1 w-5 h-auto text-gray-600" />
                   </button>
                 }
                 actions={
                   <>
-                    {workspaceList.map((workspace) => {
-                      return (
-                        <Link
-                          key={workspace.id}
-                          to={`/${workspace.name}`}
-                          className="w-full px-3 leading-10 flex flex-row justify-between items-center text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
-                        >
-                          <span className="truncate">{workspace.name}</span>
-                          {workspace.name === activedWorkspace?.name && <Icon.Check className="w-4 h-auto ml-1 shrink-0" />}
-                        </Link>
-                      );
-                    })}
-                    <hr className="w-full border-t my-1 border-t-gray-100" />
-                    <button
-                      className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
-                      onClick={() => showCreateWorkspaceDialog()}
+                    <Link
+                      to="/account"
+                      className="w-full flex flex-row justify-start items-center px-3 leading-10 text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
                     >
-                      <Icon.Plus className="w-4 h-auto mr-1" /> Create Workspace
+                      <Icon.User className="w-4 h-auto mr-2" /> My Account
+                    </Link>
+                    <button
+                      className="w-full flex flex-row justify-start items-center px-3 leading-10 text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
+                      onClick={() => handleSignOutButtonClick()}
+                    >
+                      <Icon.LogOut className="w-4 h-auto mr-2" /> Sign out
                     </button>
                   </>
                 }
-                actionsClassName="!w-48 !-left-4"
+                actionsClassName="!w-40"
               ></Dropdown>
-            </>
-          )}
-        </div>
-        <div className="relative">
-          {user ? (
-            <Dropdown
-              trigger={
-                <button className="flex flex-row justify-end items-center cursor-pointer">
-                  <span>{user?.name}</span>
-                  <Icon.ChevronDown className="ml-1 w-5 h-auto text-gray-600" />
-                </button>
-              }
-              actions={
-                <>
-                  <Link
-                    to="/account"
-                    className="w-full flex flex-row justify-start items-center px-3 leading-10 text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
-                  >
-                    <Icon.User className="w-4 h-auto mr-1" /> My Account
-                  </Link>
-                  <button
-                    className="w-full flex flex-row justify-start items-center px-3 leading-10 text-left cursor-pointer rounded whitespace-nowrap hover:bg-gray-100"
-                    onClick={() => handleSignOutButtonClick()}
-                  >
-                    <Icon.LogOut className="w-4 h-auto mr-1" /> Sign out
-                  </button>
-                </>
-              }
-              actionsClassName="!w-40"
-            ></Dropdown>
-          ) : (
-            <span className="cursor-pointer" onClick={() => navigate("/user/auth")}>
-              Sign in
-            </span>
-          )}
+            ) : (
+              <span className="cursor-pointer" onClick={() => navigate("/user/auth")}>
+                Sign in
+              </span>
+            )}
+          </div>
         </div>
       </div>
-    </div>
+
+      {state.showCreateWorkspaceDialog && (
+        <CreateWorkspaceDialog
+          onClose={() => {
+            setState({
+              ...state,
+              showCreateWorkspaceDialog: false,
+            });
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/components/MemberListView.tsx b/web/src/components/MemberListView.tsx
index 9b3e7ac..e446c96 100644
--- a/web/src/components/MemberListView.tsx
+++ b/web/src/components/MemberListView.tsx
@@ -4,7 +4,7 @@ import useLoading from "../hooks/useLoading";
 import { workspaceService } from "../services";
 import toastHelper from "./Toast";
 import Dropdown from "./common/Dropdown";
-import { showCommonDialog } from "./Dialog/CommonDialog";
+import { showCommonDialog } from "./Alert";
 import Icon from "./Icon";
 
 const userRoles = ["Admin", "User"];
@@ -26,17 +26,16 @@ const MemberListView: React.FC<Props> = (props: Props) => {
   });
   const loadingState = useLoading();
 
-  const fetchWorkspaceUserList = () => {
+  const fetchWorkspaceUserList = async () => {
     loadingState.setLoading();
-    return Promise.all([workspaceService.getWorkspaceUserList(workspaceId)])
-      .then(([workspaceUserList]) => {
-        setState({
-          workspaceUserList: workspaceUserList,
-        });
-      })
-      .finally(() => {
-        loadingState.setFinish();
+    try {
+      const [workspaceUserList] = await Promise.all([workspaceService.getWorkspaceUserList(workspaceId)]);
+      setState({
+        workspaceUserList: workspaceUserList,
       });
+    } finally {
+      loadingState.setFinish();
+    }
   };
 
   useEffect(() => {
diff --git a/web/src/components/ShortcutListView.tsx b/web/src/components/ShortcutListView.tsx
index ed55d0c..ed90ba8 100644
--- a/web/src/components/ShortcutListView.tsx
+++ b/web/src/components/ShortcutListView.tsx
@@ -1,25 +1,41 @@
 import copy from "copy-to-clipboard";
+import { useState } from "react";
 import { shortcutService, workspaceService } from "../services";
 import { useAppSelector } from "../store";
-import { showCommonDialog } from "./Dialog/CommonDialog";
-import Dropdown from "./common/Dropdown";
+import { UNKNOWN_ID } from "../helpers/consts";
+import { showCommonDialog } from "./Alert";
 import Icon from "./Icon";
-import showCreateShortcutDialog from "./CreateShortcutDialog";
+import Dropdown from "./common/Dropdown";
+import CreateShortcutDialog from "./CreateShortcutDialog";
 
 interface Props {
   workspaceId: WorkspaceId;
   shortcutList: Shortcut[];
 }
 
+interface State {
+  currentEditingShortcutId: ShortcutId;
+}
+
 const ShortcutListView: React.FC<Props> = (props: Props) => {
   const { workspaceId, shortcutList } = props;
   const { user } = useAppSelector((state) => state.user);
+  const [state, setState] = useState<State>({
+    currentEditingShortcutId: UNKNOWN_ID,
+  });
 
   const handleCopyButtonClick = (shortcut: Shortcut) => {
     const workspace = workspaceService.getWorkspaceById(workspaceId);
     copy(`${location.host}/${workspace?.name}/go/${shortcut.name}`);
   };
 
+  const handleEditShortcutButtonClick = (shortcut: Shortcut) => {
+    setState({
+      ...state,
+      currentEditingShortcutId: shortcut.id,
+    });
+  };
+
   const handleDeleteShortcutButtonClick = (shortcut: Shortcut) => {
     showCommonDialog({
       title: "Delete Shortcut",
@@ -32,55 +48,76 @@ const ShortcutListView: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <div className="w-full flex flex-col justify-start items-start">
-      {shortcutList.map((shortcut) => {
-        return (
-          <div key={shortcut.id} className="w-full flex flex-row justify-between items-start border px-6 py-4 mb-3 rounded-lg">
-            <div className="flex flex-row justify-start items-center mr-4">
-              <span>{shortcut.name}</span>
-              <span className="text-gray-400 text-sm ml-2">({shortcut.description})</span>
+    <>
+      <div className="w-full flex flex-col justify-start items-start">
+        {shortcutList.map((shortcut) => {
+          return (
+            <div key={shortcut.id} className="w-full flex flex-row justify-between items-start border px-6 py-4 mb-3 rounded-lg">
+              <div className="flex flex-row justify-start items-center mr-4">
+                <span>{shortcut.name}</span>
+                <span className="text-gray-400 text-sm ml-2">({shortcut.description})</span>
+              </div>
+              <div className="flex flex-row justify-end items-center">
+                <span className=" w-12 mr-2 text-gray-600">{shortcut.creator.name}</span>
+                <button
+                  className="cursor-pointer mr-4 hover:opacity-80"
+                  onClick={() => {
+                    handleCopyButtonClick(shortcut);
+                  }}
+                >
+                  <Icon.Copy className="w-5 h-auto" />
+                </button>
+                <a className="cursor-pointer mr-4 hover:opacity-80" target="blank" href={shortcut.link}>
+                  <Icon.ExternalLink className="w-5 h-auto" />
+                </a>
+                <Dropdown
+                  actions={
+                    <>
+                      <button
+                        disabled={shortcut.creatorId !== user?.id}
+                        className="w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
+                        onClick={() => handleEditShortcutButtonClick(shortcut)}
+                      >
+                        Edit
+                      </button>
+                      <button
+                        disabled={shortcut.creatorId !== user?.id}
+                        className="w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
+                        onClick={() => {
+                          handleDeleteShortcutButtonClick(shortcut);
+                        }}
+                      >
+                        Delete
+                      </button>
+                    </>
+                  }
+                  actionsClassName="!w-24"
+                ></Dropdown>
+              </div>
             </div>
-            <div className="flex flex-row justify-end items-center">
-              <span className=" w-12 mr-2 text-gray-600">{shortcut.creator.name}</span>
-              <button
-                className="cursor-pointer mr-4 hover:opacity-80"
-                onClick={() => {
-                  handleCopyButtonClick(shortcut);
-                }}
-              >
-                <Icon.Copy className="w-5 h-auto" />
-              </button>
-              <a className="cursor-pointer mr-4 hover:opacity-80" target="blank" href={shortcut.link}>
-                <Icon.ExternalLink className="w-5 h-auto" />
-              </a>
-              <Dropdown
-                actions={
-                  <>
-                    <button
-                      disabled={shortcut.creatorId !== user?.id}
-                      className="w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
-                      onClick={() => showCreateShortcutDialog(workspaceId, shortcut.id)}
-                    >
-                      Edit
-                    </button>
-                    <button
-                      disabled={shortcut.creatorId !== user?.id}
-                      className="w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
-                      onClick={() => {
-                        handleDeleteShortcutButtonClick(shortcut);
-                      }}
-                    >
-                      Delete
-                    </button>
-                  </>
-                }
-                actionsClassName="!w-24"
-              ></Dropdown>
-            </div>
-          </div>
-        );
-      })}
-    </div>
+          );
+        })}
+      </div>
+
+      {state.currentEditingShortcutId !== UNKNOWN_ID && (
+        <CreateShortcutDialog
+          workspaceId={workspaceId}
+          shortcutId={state.currentEditingShortcutId}
+          onClose={() => {
+            setState({
+              ...state,
+              currentEditingShortcutId: UNKNOWN_ID,
+            });
+          }}
+          onConfirm={() => {
+            setState({
+              ...state,
+              currentEditingShortcutId: UNKNOWN_ID,
+            });
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/components/UpsertWorkspaceUserDialog.tsx b/web/src/components/UpsertWorkspaceUserDialog.tsx
index fb6b096..a8bedff 100644
--- a/web/src/components/UpsertWorkspaceUserDialog.tsx
+++ b/web/src/components/UpsertWorkspaceUserDialog.tsx
@@ -1,13 +1,15 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
 import { useState } from "react";
 import { UNKNOWN_ID } from "../helpers/consts";
 import { upsertWorkspaceUser } from "../helpers/api";
 import useLoading from "../hooks/useLoading";
 import Icon from "./Icon";
-import { generateDialog } from "./Dialog";
 import toastHelper from "./Toast";
 
-interface Props extends DialogProps {
+interface Props {
   workspaceId: WorkspaceId;
+  onClose: () => void;
+  onConfirm?: () => void;
 }
 
 interface State {
@@ -15,7 +17,7 @@ interface State {
 }
 
 const UpsertWorkspaceUserDialog: React.FC<Props> = (props: Props) => {
-  const { destroy, workspaceId } = props;
+  const { onClose, onConfirm, workspaceId } = props;
   const [state, setState] = useState<State>({
     workspaceUserUpsert: {
       workspaceId: workspaceId,
@@ -56,7 +58,12 @@ const UpsertWorkspaceUserDialog: React.FC<Props> = (props: Props) => {
       await upsertWorkspaceUser({
         ...state.workspaceUserUpsert,
       });
-      destroy();
+
+      if (onConfirm) {
+        onConfirm();
+      } else {
+        onClose();
+      }
     } catch (error: any) {
       console.error(error);
       toastHelper.error(error.response.data.error || error.response.data.message);
@@ -65,14 +72,14 @@ const UpsertWorkspaceUserDialog: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <>
-      <div className="max-w-full w-80 flex flex-row justify-between items-center mb-4">
+    <Dialog open={true}>
+      <DialogTitle className="flex flex-row justify-between items-center w-80">
         <p className="text-base">Create Workspace Member</p>
-        <button className="rounded p-1 hover:bg-gray-100" onClick={destroy}>
+        <button className="rounded p-1 hover:bg-gray-100" onClick={onClose}>
           <Icon.X className="w-5 h-auto text-gray-600" />
         </button>
-      </div>
-      <div className="w-full flex flex-col justify-start items-start">
+      </DialogTitle>
+      <DialogContent>
         <div className="w-full flex flex-col justify-start items-start mb-3">
           <span className="mb-2">User ID</span>
           <input
@@ -120,19 +127,9 @@ const UpsertWorkspaceUserDialog: React.FC<Props> = (props: Props) => {
             Save
           </button>
         </div>
-      </div>
-    </>
+      </DialogContent>
+    </Dialog>
   );
 };
 
-export default function showUpsertWorkspaceUserDialog(workspaceId: WorkspaceId, onDestory?: () => void) {
-  return generateDialog(
-    {
-      onDestory,
-    },
-    UpsertWorkspaceUserDialog,
-    {
-      workspaceId,
-    }
-  );
-}
+export default UpsertWorkspaceUserDialog;
diff --git a/web/src/components/WorkspaceListView.tsx b/web/src/components/WorkspaceListView.tsx
index 7f83df3..8d9459d 100644
--- a/web/src/components/WorkspaceListView.tsx
+++ b/web/src/components/WorkspaceListView.tsx
@@ -1,15 +1,31 @@
+import { useState } from "react";
 import { Link } from "react-router-dom";
+import { UNKNOWN_ID } from "../helpers/consts";
 import { workspaceService } from "../services";
-import { showCommonDialog } from "./Dialog/CommonDialog";
+import { showCommonDialog } from "./Alert";
 import Dropdown from "./common/Dropdown";
-import showCreateWorkspaceDialog from "./CreateWorkspaceDialog";
+import CreateWorkspaceDialog from "./CreateWorkspaceDialog";
 
 interface Props {
   workspaceList: Workspace[];
 }
 
+interface State {
+  currentEditingWorkspaceId: WorkspaceId;
+}
+
 const WorkspaceListView: React.FC<Props> = (props: Props) => {
   const { workspaceList } = props;
+  const [state, setState] = useState<State>({
+    currentEditingWorkspaceId: UNKNOWN_ID,
+  });
+
+  const handleEditWorkspaceButtonClick = (workspaceId: WorkspaceId) => {
+    setState({
+      ...state,
+      currentEditingWorkspaceId: workspaceId,
+    });
+  };
 
   const handleDeleteWorkspaceButtonClick = (workspace: Workspace) => {
     showCommonDialog({
@@ -23,41 +39,55 @@ const WorkspaceListView: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <div className="w-full flex flex-col justify-start items-start">
-      {workspaceList.map((workspace) => {
-        return (
-          <div key={workspace.id} className="w-full flex flex-row justify-between items-start border px-6 py-4 mb-3 rounded-lg">
-            <div className="flex flex-col justify-start items-start">
-              <Link to={`/${workspace.name}`} className="text-lg cursor-pointer hover:underline">
-                {workspace.name}
-              </Link>
-              <span className="text-sm mt-1 text-gray-600">{workspace.description}</span>
+    <>
+      <div className="w-full flex flex-col justify-start items-start">
+        {workspaceList.map((workspace) => {
+          return (
+            <div key={workspace.id} className="w-full flex flex-row justify-between items-start border px-6 py-4 mb-3 rounded-lg">
+              <div className="flex flex-col justify-start items-start">
+                <Link to={`/${workspace.name}`} className="text-lg cursor-pointer hover:underline">
+                  {workspace.name}
+                </Link>
+                <span className="text-sm mt-1 text-gray-600">{workspace.description}</span>
+              </div>
+              <Dropdown
+                actions={
+                  <>
+                    <button
+                      className="w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
+                      onClick={() => handleEditWorkspaceButtonClick(workspace.id)}
+                    >
+                      Edit
+                    </button>
+                    <button
+                      className="w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100"
+                      onClick={() => {
+                        handleDeleteWorkspaceButtonClick(workspace);
+                      }}
+                    >
+                      Delete
+                    </button>
+                  </>
+                }
+                actionsClassName="!w-24"
+              ></Dropdown>
             </div>
-            <Dropdown
-              actions={
-                <>
-                  <button
-                    className="w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
-                    onClick={() => showCreateWorkspaceDialog(workspace.id)}
-                  >
-                    Edit
-                  </button>
-                  <button
-                    className="w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100"
-                    onClick={() => {
-                      handleDeleteWorkspaceButtonClick(workspace);
-                    }}
-                  >
-                    Delete
-                  </button>
-                </>
-              }
-              actionsClassName="!w-24"
-            ></Dropdown>
-          </div>
-        );
-      })}
-    </div>
+          );
+        })}
+      </div>
+
+      {state.currentEditingWorkspaceId !== UNKNOWN_ID && (
+        <CreateWorkspaceDialog
+          workspaceId={state.currentEditingWorkspaceId}
+          onClose={() => {
+            setState({
+              ...state,
+              currentEditingWorkspaceId: UNKNOWN_ID,
+            });
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/components/WorkspaceSetting.tsx b/web/src/components/WorkspaceSetting.tsx
index 432453d..454d98e 100644
--- a/web/src/components/WorkspaceSetting.tsx
+++ b/web/src/components/WorkspaceSetting.tsx
@@ -5,9 +5,9 @@ import useLoading from "../hooks/useLoading";
 import { workspaceService } from "../services";
 import { useAppSelector } from "../store";
 import { unknownWorkspace, unknownWorkspaceUser } from "../store/modules/workspace";
-import showCreateWorkspaceDialog from "./CreateWorkspaceDialog";
-import { showCommonDialog } from "./Dialog/CommonDialog";
+import { showCommonDialog } from "./Alert";
 import toastHelper from "./Toast";
+import CreateWorkspaceDialog from "./CreateWorkspaceDialog";
 
 interface Props {
   workspaceId: WorkspaceId;
@@ -16,6 +16,7 @@ interface Props {
 interface State {
   workspace: Workspace;
   workspaceUser: WorkspaceUser;
+  showEditWorkspaceDialog: boolean;
 }
 
 const WorkspaceSetting: React.FC<Props> = (props: Props) => {
@@ -25,6 +26,7 @@ const WorkspaceSetting: React.FC<Props> = (props: Props) => {
   const [state, setState] = useState<State>({
     workspace: unknownWorkspace,
     workspaceUser: unknownWorkspaceUser,
+    showEditWorkspaceDialog: false,
   });
   const loadingState = useLoading();
 
@@ -39,6 +41,7 @@ const WorkspaceSetting: React.FC<Props> = (props: Props) => {
     Promise.all([workspaceService.getWorkspaceUser(workspace.id, user.id)])
       .then(([workspaceUser]) => {
         setState({
+          ...state,
           workspace,
           workspaceUser,
         });
@@ -49,7 +52,29 @@ const WorkspaceSetting: React.FC<Props> = (props: Props) => {
   }, []);
 
   const handleEditWorkspaceButtonClick = () => {
-    showCreateWorkspaceDialog(state.workspace.id);
+    setState({
+      ...state,
+      showEditWorkspaceDialog: true,
+    });
+  };
+
+  const handleEditWorkspaceDialogConfirm = () => {
+    const prevWorkspace = state.workspace;
+    const workspace = workspaceService.getWorkspaceById(workspaceId);
+    if (!workspace) {
+      toastHelper.error("workspace not found");
+      return;
+    }
+
+    setState({
+      ...state,
+      workspace: workspace,
+      showEditWorkspaceDialog: false,
+    });
+
+    if (prevWorkspace.name !== workspace.name) {
+      navigate(`/${workspace.name}#setting`);
+    }
   };
 
   const handleDeleteWorkspaceButtonClick = () => {
@@ -80,38 +105,53 @@ const WorkspaceSetting: React.FC<Props> = (props: Props) => {
   };
 
   return (
-    <div className="w-full flex flex-col justify-start items-start">
-      <p className="text-3xl mt-2 mb-4">{state.workspace.name}</p>
-      <p>{state.workspace.description}</p>
+    <>
+      <div className="w-full flex flex-col justify-start items-start">
+        <p className="text-3xl mt-2 mb-4">{state.workspace.name}</p>
+        <p>{state.workspace.description}</p>
 
-      <div className="border-t pt-4 mt-2 flex flex-row justify-start items-center">
-        <span className="text-gray-400 mr-2">Actions:</span>
-        <div className="flex flex-row justify-start items-center space-x-2">
-          {state.workspaceUser.role === "ADMIN" ? (
-            <>
-              <button className="border rounded-md px-3 leading-8 hover:shadow" onClick={handleEditWorkspaceButtonClick}>
-                Edit
-              </button>
-              <button
-                className="border rounded-md px-3 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
-                onClick={handleDeleteWorkspaceButtonClick}
-              >
-                Delete
-              </button>
-            </>
-          ) : (
-            <>
-              <button
-                className="border rounded-md px-3 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
-                onClick={handleExitWorkspaceButtonClick}
-              >
-                Exit
-              </button>
-            </>
-          )}
+        <div className="border-t pt-4 mt-2 flex flex-row justify-start items-center">
+          <span className="text-gray-400 mr-2">Actions:</span>
+          <div className="flex flex-row justify-start items-center space-x-2">
+            {state.workspaceUser.role === "ADMIN" ? (
+              <>
+                <button className="border rounded-md px-3 leading-8 hover:shadow" onClick={handleEditWorkspaceButtonClick}>
+                  Edit
+                </button>
+                <button
+                  className="border rounded-md px-3 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
+                  onClick={handleDeleteWorkspaceButtonClick}
+                >
+                  Delete
+                </button>
+              </>
+            ) : (
+              <>
+                <button
+                  className="border rounded-md px-3 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
+                  onClick={handleExitWorkspaceButtonClick}
+                >
+                  Exit
+                </button>
+              </>
+            )}
+          </div>
         </div>
       </div>
-    </div>
+
+      {state.showEditWorkspaceDialog && (
+        <CreateWorkspaceDialog
+          workspaceId={state.workspace.id}
+          onClose={() => {
+            setState({
+              ...state,
+              showEditWorkspaceDialog: false,
+            });
+          }}
+          onConfirm={handleEditWorkspaceDialogConfirm}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/less/base-dialog.less b/web/src/less/base-dialog.less
deleted file mode 100644
index b870dca..0000000
--- a/web/src/less/base-dialog.less
+++ /dev/null
@@ -1,37 +0,0 @@
-.dialog-wrapper {
-  @apply fixed top-0 left-0 flex flex-col justify-start items-center w-full h-full pt-16 z-100 overflow-x-hidden overflow-y-scroll bg-transparent transition-all;
-
-  &.showup {
-    background-color: rgba(0, 0, 0, 0.6);
-  }
-
-  &.showoff {
-    display: none;
-  }
-
-  > .dialog-container {
-    @apply flex flex-col justify-start items-start bg-white p-4 sm:px-6 rounded-lg;
-
-    > .dialog-header-container {
-      @apply flex flex-row justify-between items-center w-full mb-4;
-
-      > .title-text {
-        > .icon-text {
-          @apply mr-2 text-base;
-        }
-      }
-
-      .btn {
-        @apply flex flex-col justify-center items-center w-6 h-6 rounded hover:bg-gray-100 hover:shadow;
-      }
-    }
-
-    > .dialog-content-container {
-      @apply flex flex-col justify-start items-start w-full;
-    }
-
-    > .dialog-footer-container {
-      @apply flex flex-row justify-end items-center w-full mt-4;
-    }
-  }
-}
diff --git a/web/src/less/common-dialog.less b/web/src/less/common-dialog.less
deleted file mode 100644
index 125cb50..0000000
--- a/web/src/less/common-dialog.less
+++ /dev/null
@@ -1,25 +0,0 @@
-.common-dialog {
-  > .dialog-container {
-    @apply w-80;
-
-    > .dialog-content-container {
-      @apply flex flex-col justify-start items-start;
-
-      > .btns-container {
-        @apply flex flex-row justify-end items-center w-full mt-4;
-
-        > .btn {
-          @apply text-sm py-1 px-3 mr-2 rounded-md cursor-pointer hover:opacity-80;
-
-          &.confirm-btn {
-            @apply bg-red-100 border border-solid border-blue-600 text-blue-600;
-
-            &.warning {
-              @apply border-red-600 text-red-600;
-            }
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx
index 18ca447..2b14359 100644
--- a/web/src/pages/Home.tsx
+++ b/web/src/pages/Home.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
 import { useNavigate } from "react-router-dom";
 import { userService, workspaceService } from "../services";
 import { useAppSelector } from "../store";
@@ -6,11 +6,18 @@ import useLoading from "../hooks/useLoading";
 import Icon from "../components/Icon";
 import Header from "../components/Header";
 import WorkspaceListView from "../components/WorkspaceListView";
-import showCreateWorkspaceDialog from "../components/CreateWorkspaceDialog";
+import CreateWorkspaceDialog from "../components/CreateWorkspaceDialog";
+
+interface State {
+  showCreateWorkspaceDialog: boolean;
+}
 
 const Home: React.FC = () => {
   const navigate = useNavigate();
   const { workspaceList } = useAppSelector((state) => state.workspace);
+  const [state, setState] = useState<State>({
+    showCreateWorkspaceDialog: false,
+  });
   const loadingState = useLoading();
 
   useEffect(() => {
@@ -24,29 +31,49 @@ const Home: React.FC = () => {
     });
   }, []);
 
+  const handleCreateWorkspaceButtonClick = () => {
+    setState({
+      ...state,
+      showCreateWorkspaceDialog: true,
+    });
+  };
+
   return (
-    <div className="w-full h-full flex flex-col justify-start items-start">
-      <Header />
-      <div className="mx-auto max-w-4xl w-full px-3 py-6 flex flex-col justify-start items-start">
-        <div className="mb-4 w-full flex flex-row justify-between items-center">
-          <span className="font-mono text-gray-400">Workspace List</span>
-          <button
-            className="text-sm flex flex-row justify-start items-center border px-3 leading-10 rounded-lg cursor-pointer hover:shadow"
-            onClick={() => showCreateWorkspaceDialog()}
-          >
-            <Icon.Plus className="w-5 h-auto mr-1" /> Create Workspace
-          </button>
-        </div>
-        {loadingState.isLoading ? (
-          <div className="py-4 w-full flex flex-row justify-center items-center">
-            <Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
-            loading
+    <>
+      <div className="w-full h-full flex flex-col justify-start items-start">
+        <Header />
+        <div className="mx-auto max-w-4xl w-full px-3 py-6 flex flex-col justify-start items-start">
+          <div className="mb-4 w-full flex flex-row justify-between items-center">
+            <span className="font-mono text-gray-400">Workspace List</span>
+            <button
+              className="text-sm flex flex-row justify-start items-center border px-3 leading-10 rounded-lg cursor-pointer hover:shadow"
+              onClick={handleCreateWorkspaceButtonClick}
+            >
+              <Icon.Plus className="w-5 h-auto mr-1" /> Create Workspace
+            </button>
           </div>
-        ) : (
-          <WorkspaceListView workspaceList={workspaceList} />
-        )}
+          {loadingState.isLoading ? (
+            <div className="py-4 w-full flex flex-row justify-center items-center">
+              <Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
+              loading
+            </div>
+          ) : (
+            <WorkspaceListView workspaceList={workspaceList} />
+          )}
+        </div>
       </div>
-    </div>
+
+      {state.showCreateWorkspaceDialog && (
+        <CreateWorkspaceDialog
+          onClose={() => {
+            setState({
+              ...state,
+              showCreateWorkspaceDialog: false,
+            });
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/pages/UserDetail.tsx b/web/src/pages/UserDetail.tsx
index 9b6f512..99c6dc9 100644
--- a/web/src/pages/UserDetail.tsx
+++ b/web/src/pages/UserDetail.tsx
@@ -1,17 +1,24 @@
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
 import { useNavigate } from "react-router-dom";
 import { useAppSelector } from "../store";
 import Header from "../components/Header";
-import { showCommonDialog } from "../components/Dialog/CommonDialog";
+import { showCommonDialog } from "../components/Alert";
 import { userService } from "../services";
 import Icon from "../components/Icon";
 import copy from "copy-to-clipboard";
 import toastHelper from "../components/Toast";
-import showChangePasswordDialog from "../components/ChangePasswordDialog";
+import ChangePasswordDialog from "../components/ChangePasswordDialog";
+
+interface State {
+  showChangePasswordDialog: boolean;
+}
 
 const UserDetail: React.FC = () => {
   const navigate = useNavigate();
   const { user } = useAppSelector((state) => state.user);
+  const [state, setState] = useState<State>({
+    showChangePasswordDialog: false,
+  });
 
   useEffect(() => {
     if (!userService.getState().user) {
@@ -21,7 +28,10 @@ const UserDetail: React.FC = () => {
   }, []);
 
   const handleChangePasswordBtnClick = async () => {
-    showChangePasswordDialog();
+    setState({
+      ...state,
+      showChangePasswordDialog: true,
+    });
   };
 
   const handleCopyOpenIdBtnClick = async () => {
@@ -49,35 +59,47 @@ const UserDetail: React.FC = () => {
   };
 
   return (
-    <div className="w-full h-full flex flex-col justify-start items-start">
-      <Header />
-      <div className="mx-auto max-w-4xl w-full px-3 py-6 flex flex-col justify-start items-start space-y-4">
-        <p className="text-3xl mt-2 mb-4">{user?.name}</p>
-        <p className="leading-8 flex flex-row justify-start items-center">
-          <span className="mr-3 text-gray-500 font-mono">Email: </span>
-          {user?.email}
-        </p>
-        <p className="leading-8 flex flex-row justify-start items-center">
-          <span className="mr-3 text-gray-500 font-mono">Password: </span>
-          <button className="border rounded-md px-2 leading-8 hover:shadow" onClick={handleChangePasswordBtnClick}>
-            Change
-          </button>
-        </p>
-        <p className="leading-8 flex flex-row justify-start items-center">
-          <span className="mr-3 text-gray-500 font-mono">OpenID:</span>
-          <input type="text" value={user?.openId} readOnly className="border shrink rounded-md px-3 pr-5 shadow-inner truncate" />
-          <button className="-ml-6 bg-white text-gray-600 hover:text-black" onClick={handleCopyOpenIdBtnClick}>
-            <Icon.Clipboard className="w-4 h-auto" />
-          </button>
-          <button
-            className="border ml-4 rounded-md px-2 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
-            onClick={handleResetOpenIdBtnClick}
-          >
-            Reset
-          </button>
-        </p>
+    <>
+      <div className="w-full h-full flex flex-col justify-start items-start">
+        <Header />
+        <div className="mx-auto max-w-4xl w-full px-3 py-6 flex flex-col justify-start items-start space-y-4">
+          <p className="text-3xl mt-2 mb-4">{user?.name}</p>
+          <p className="leading-8 flex flex-row justify-start items-center">
+            <span className="mr-3 text-gray-500 font-mono">Email: </span>
+            {user?.email}
+          </p>
+          <p className="leading-8 flex flex-row justify-start items-center">
+            <span className="mr-3 text-gray-500 font-mono">Password: </span>
+            <button className="border rounded-md px-2 leading-8 hover:shadow" onClick={handleChangePasswordBtnClick}>
+              Change
+            </button>
+          </p>
+          <p className="leading-8 flex flex-row justify-start items-center">
+            <span className="mr-3 text-gray-500 font-mono">OpenID:</span>
+            <input type="text" value={user?.openId} readOnly className="border shrink rounded-md px-3 pr-5 shadow-inner truncate" />
+            <button className="-ml-6 bg-white text-gray-600 hover:text-black" onClick={handleCopyOpenIdBtnClick}>
+              <Icon.Clipboard className="w-4 h-auto" />
+            </button>
+            <button
+              className="border ml-4 rounded-md px-2 leading-8 border-red-600 text-red-600 bg-red-50 hover:shadow"
+              onClick={handleResetOpenIdBtnClick}
+            >
+              Reset
+            </button>
+          </p>
+        </div>
       </div>
-    </div>
+      {state.showChangePasswordDialog && (
+        <ChangePasswordDialog
+          onClose={() => {
+            setState({
+              ...state,
+              showChangePasswordDialog: false,
+            });
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/pages/WorkspaceDetail.tsx b/web/src/pages/WorkspaceDetail.tsx
index ae98483..ac71b2b 100644
--- a/web/src/pages/WorkspaceDetail.tsx
+++ b/web/src/pages/WorkspaceDetail.tsx
@@ -7,17 +7,19 @@ import useLoading from "../hooks/useLoading";
 import Icon from "../components/Icon";
 import toastHelper from "../components/Toast";
 import Dropdown from "../components/common/Dropdown";
-import showCreateShortcutDialog from "../components/CreateShortcutDialog";
-import showUpsertWorkspaceUserDialog from "../components/UpsertWorkspaceUserDialog";
 import Header from "../components/Header";
 import ShortcutListView from "../components/ShortcutListView";
 import MemberListView from "../components/MemberListView";
 import WorkspaceSetting from "../components/WorkspaceSetting";
+import CreateShortcutDialog from "../components/CreateShortcutDialog";
+import UpsertWorkspaceUserDialog from "../components/UpsertWorkspaceUserDialog";
 
 interface State {
   workspace: Workspace;
   workspaceUser: WorkspaceUser;
   userList: WorkspaceUser[];
+  showCreateShortcutDialog: boolean;
+  showUpsertWorkspaceUserDialog: boolean;
 }
 
 const WorkspaceDetail: React.FC = () => {
@@ -30,6 +32,8 @@ const WorkspaceDetail: React.FC = () => {
     workspace: unknownWorkspace,
     workspaceUser: unknownWorkspaceUser,
     userList: [],
+    showCreateShortcutDialog: false,
+    showUpsertWorkspaceUserDialog: false,
   });
   const loadingState = useLoading();
 
@@ -53,6 +57,7 @@ const WorkspaceDetail: React.FC = () => {
     ])
       .then(([, workspaceUser, workspaceUserList]) => {
         setState({
+          ...state,
           workspace,
           workspaceUser,
           userList: workspaceUserList,
@@ -70,86 +75,130 @@ const WorkspaceDetail: React.FC = () => {
   }, [location.hash]);
 
   const handleCreateShortcutButtonClick = () => {
-    showCreateShortcutDialog(state.workspace.id, undefined, async () => {
-      if (location.hash !== "#shortcuts") {
-        navigate("#shortcuts");
-      }
+    setState({
+      ...state,
+      showCreateShortcutDialog: true,
     });
   };
 
   const handleUpsertWorkspaceMemberButtonClick = () => {
-    showUpsertWorkspaceUserDialog(state.workspace.id, async () => {
-      const workspaceUserList = await workspaceService.getWorkspaceUserList(state.workspace.id);
-      setState({
-        ...state,
-        userList: workspaceUserList,
-      });
-
-      if (location.hash !== "#members") {
-        navigate("#members");
-      }
+    setState({
+      ...state,
+      showUpsertWorkspaceUserDialog: true,
     });
   };
 
   return (
-    <div className="w-full h-full flex flex-col justify-start items-start">
-      <Header />
-      <div className="mx-auto max-w-4xl w-full px-3 pb-6 flex flex-col justify-start items-start">
-        <div className="w-full flex flex-row justify-between items-center mt-4 mb-4">
-          <div className="flex flex-row justify-start items-center space-x-4">
-            <NavLink to="#shortcuts" className={`${location.hash === "#shortcuts" && "underline"}`}>
-              Shortcuts
-            </NavLink>
-            <NavLink to="#members" className={`${location.hash === "#members" && "underline"}`}>
-              Members
-            </NavLink>
-            <NavLink to="#setting" className={`${location.hash === "#setting" && "underline"}`}>
-              Setting
-            </NavLink>
-          </div>
-          <div>
-            <Dropdown
-              trigger={
-                <button className="w-32 flex flex-row justify-start items-center border px-3 leading-10 rounded-lg cursor-pointer hover:shadow">
-                  <Icon.Plus className="w-4 h-auto mr-1" /> Add new...
-                </button>
-              }
-              actions={
-                <>
-                  <button
-                    className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
-                    onClick={handleCreateShortcutButtonClick}
-                  >
-                    Shortcut
+    <>
+      <div className="w-full h-full flex flex-col justify-start items-start">
+        <Header />
+        <div className="mx-auto max-w-4xl w-full px-3 pb-6 flex flex-col justify-start items-start">
+          <div className="w-full flex flex-row justify-between items-center mt-4 mb-4">
+            <div className="flex flex-row justify-start items-center space-x-4">
+              <NavLink to="#shortcuts" className={`${location.hash === "#shortcuts" && "underline"}`}>
+                Shortcuts
+              </NavLink>
+              <NavLink to="#members" className={`${location.hash === "#members" && "underline"}`}>
+                Members
+              </NavLink>
+              <NavLink to="#setting" className={`${location.hash === "#setting" && "underline"}`}>
+                Setting
+              </NavLink>
+            </div>
+            <div>
+              <Dropdown
+                trigger={
+                  <button className="w-32 flex flex-row justify-start items-center border px-3 leading-10 rounded-lg cursor-pointer hover:shadow">
+                    <Icon.Plus className="w-4 h-auto mr-1" /> Add new...
                   </button>
-                  <button
-                    className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
-                    onClick={handleUpsertWorkspaceMemberButtonClick}
-                  >
-                    Member
-                  </button>
-                </>
-              }
-              actionsClassName="!w-32"
-            />
+                }
+                actions={
+                  <>
+                    <button
+                      className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
+                      onClick={handleCreateShortcutButtonClick}
+                    >
+                      Shortcut
+                    </button>
+                    <button
+                      className="w-full flex flex-row justify-start items-center px-3 leading-10 rounded cursor-pointer hover:bg-gray-100"
+                      onClick={handleUpsertWorkspaceMemberButtonClick}
+                    >
+                      Member
+                    </button>
+                  </>
+                }
+                actionsClassName="!w-32"
+              />
+            </div>
           </div>
+          {loadingState.isLoading ? (
+            <div className="py-4 w-full flex flex-row justify-center items-center">
+              <Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
+              loading
+            </div>
+          ) : (
+            <>
+              {location.hash === "#shortcuts" && <ShortcutListView workspaceId={state.workspace.id} shortcutList={shortcutList} />}
+              {location.hash === "#members" && (
+                <MemberListView
+                  key={Date.now()}
+                  workspaceId={state.workspace.id}
+                  workspaceUser={state.workspaceUser}
+                  userList={state.userList}
+                />
+              )}
+              {location.hash === "#setting" && <WorkspaceSetting workspaceId={state.workspace.id} />}
+            </>
+          )}
         </div>
-        {loadingState.isLoading ? (
-          <div className="py-4 w-full flex flex-row justify-center items-center">
-            <Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
-            loading
-          </div>
-        ) : (
-          <>
-            {location.hash === "#shortcuts" && <ShortcutListView workspaceId={state.workspace.id} shortcutList={shortcutList} />}
-            {location.hash === "#members" && (
-              <MemberListView workspaceId={state.workspace.id} workspaceUser={state.workspaceUser} userList={state.userList} />
-            )}
-            {location.hash === "#setting" && <WorkspaceSetting workspaceId={state.workspace.id} />}
-          </>
-        )}
       </div>
-    </div>
+
+      {state.showCreateShortcutDialog && (
+        <CreateShortcutDialog
+          workspaceId={state.workspace.id}
+          onClose={() => {
+            setState({
+              ...state,
+              showCreateShortcutDialog: false,
+            });
+          }}
+          onConfirm={() => {
+            setState({
+              ...state,
+              showCreateShortcutDialog: false,
+            });
+            if (location.hash !== "#shortcuts") {
+              navigate("#shortcuts");
+            }
+          }}
+        />
+      )}
+
+      {state.showUpsertWorkspaceUserDialog && (
+        <UpsertWorkspaceUserDialog
+          workspaceId={state.workspace.id}
+          onClose={() => {
+            setState({
+              ...state,
+              showUpsertWorkspaceUserDialog: false,
+            });
+          }}
+          onConfirm={async () => {
+            const workspaceUserList = await workspaceService.getWorkspaceUserList(state.workspace.id);
+            setState({
+              ...state,
+              userList: workspaceUserList,
+              showUpsertWorkspaceUserDialog: false,
+            });
+
+            if (location.hash !== "#members") {
+              navigate("#members");
+            }
+          }}
+        />
+      )}
+    </>
   );
 };
 
diff --git a/web/src/types/view.d.ts b/web/src/types/view.d.ts
deleted file mode 100644
index 32df3ea..0000000
--- a/web/src/types/view.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-interface DialogProps {
-  destroy: FunctionType;
-}
-
-interface DialogCallback {
-  destroy: FunctionType;
-}
diff --git a/web/yarn.lock b/web/yarn.lock
index 5be25ad..63bc39c 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -10,7 +10,7 @@
     "@jridgewell/gen-mapping" "^0.1.0"
     "@jridgewell/trace-mapping" "^0.3.9"
 
-"@babel/code-frame@^7.18.6":
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
   integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
@@ -89,7 +89,7 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-module-imports@^7.18.6":
+"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
   integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
@@ -172,7 +172,7 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
   integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
 
-"@babel/plugin-syntax-jsx@^7.18.6":
+"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
   integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
@@ -229,6 +229,13 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
+  integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/template@^7.18.10":
   version "7.18.10"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
@@ -271,6 +278,114 @@
     "@babel/helper-validator-identifier" "^7.18.6"
     to-fast-properties "^2.0.0"
 
+"@emotion/babel-plugin@^11.10.0":
+  version "11.10.2"
+  resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz#879db80ba622b3f6076917a1e6f648b1c7d008c7"
+  integrity sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==
+  dependencies:
+    "@babel/helper-module-imports" "^7.16.7"
+    "@babel/plugin-syntax-jsx" "^7.17.12"
+    "@babel/runtime" "^7.18.3"
+    "@emotion/hash" "^0.9.0"
+    "@emotion/memoize" "^0.8.0"
+    "@emotion/serialize" "^1.1.0"
+    babel-plugin-macros "^3.1.0"
+    convert-source-map "^1.5.0"
+    escape-string-regexp "^4.0.0"
+    find-root "^1.1.0"
+    source-map "^0.5.7"
+    stylis "4.0.13"
+
+"@emotion/cache@^11.10.0", "@emotion/cache@^11.10.3":
+  version "11.10.3"
+  resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.3.tgz#c4f67904fad10c945fea5165c3a5a0583c164b87"
+  integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==
+  dependencies:
+    "@emotion/memoize" "^0.8.0"
+    "@emotion/sheet" "^1.2.0"
+    "@emotion/utils" "^1.2.0"
+    "@emotion/weak-memoize" "^0.3.0"
+    stylis "4.0.13"
+
+"@emotion/hash@^0.9.0":
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
+  integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
+
+"@emotion/is-prop-valid@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
+  integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
+  dependencies:
+    "@emotion/memoize" "^0.8.0"
+
+"@emotion/memoize@^0.8.0":
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
+  integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
+
+"@emotion/react@^11.10.4":
+  version "11.10.4"
+  resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.4.tgz#9dc6bccbda5d70ff68fdb204746c0e8b13a79199"
+  integrity sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==
+  dependencies:
+    "@babel/runtime" "^7.18.3"
+    "@emotion/babel-plugin" "^11.10.0"
+    "@emotion/cache" "^11.10.0"
+    "@emotion/serialize" "^1.1.0"
+    "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
+    "@emotion/utils" "^1.2.0"
+    "@emotion/weak-memoize" "^0.3.0"
+    hoist-non-react-statics "^3.3.1"
+
+"@emotion/serialize@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.0.tgz#b1f97b1011b09346a40e9796c37a3397b4ea8ea8"
+  integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==
+  dependencies:
+    "@emotion/hash" "^0.9.0"
+    "@emotion/memoize" "^0.8.0"
+    "@emotion/unitless" "^0.8.0"
+    "@emotion/utils" "^1.2.0"
+    csstype "^3.0.2"
+
+"@emotion/sheet@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.0.tgz#771b1987855839e214fc1741bde43089397f7be5"
+  integrity sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==
+
+"@emotion/styled@^11.10.4":
+  version "11.10.4"
+  resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.4.tgz#e93f84a4d54003c2acbde178c3f97b421fce1cd4"
+  integrity sha512-pRl4R8Ez3UXvOPfc2bzIoV8u9P97UedgHS4FPX594ntwEuAMA114wlaHvOK24HB48uqfXiGlYIZYCxVJ1R1ttQ==
+  dependencies:
+    "@babel/runtime" "^7.18.3"
+    "@emotion/babel-plugin" "^11.10.0"
+    "@emotion/is-prop-valid" "^1.2.0"
+    "@emotion/serialize" "^1.1.0"
+    "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
+    "@emotion/utils" "^1.2.0"
+
+"@emotion/unitless@^0.8.0":
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
+  integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
+
+"@emotion/use-insertion-effect-with-fallbacks@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
+  integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
+
+"@emotion/utils@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
+  integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
+
+"@emotion/weak-memoize@^0.3.0":
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
+  integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
+
 "@esbuild/linux-loong64@0.15.7":
   version "0.15.7"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz#1ec4af4a16c554cbd402cc557ccdd874e3f7be53"
@@ -345,6 +460,92 @@
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/sourcemap-codec" "^1.4.10"
 
+"@mui/base@5.0.0-alpha.99":
+  version "5.0.0-alpha.99"
+  resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.99.tgz#52589c72b6bf69e016e5811292529d60f81537ad"
+  integrity sha512-D04H6O1c0Jv561yI0SVbpa8MpqpW3G43CwJxV2o6ALfI0DMJ45w07dGafmDchb6aCWTRTdggd3rjgmuzyNwPiQ==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@emotion/is-prop-valid" "^1.2.0"
+    "@mui/types" "^7.2.0"
+    "@mui/utils" "^5.10.6"
+    "@popperjs/core" "^2.11.6"
+    clsx "^1.2.1"
+    prop-types "^15.8.1"
+    react-is "^18.2.0"
+
+"@mui/core-downloads-tracker@^5.10.7":
+  version "5.10.7"
+  resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.7.tgz#b0dd472438cf769ba10c44ce44b35b597bfa0e17"
+  integrity sha512-3N0UYVy3MbrHzM3j6f7fIUCZ+bQ1/sSZq143tLxwSssW3Z4AqE83brpr5flEY1Lx+Aowv/cPyQMmZxzRlFCGqw==
+
+"@mui/material@^5.10.7":
+  version "5.10.7"
+  resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.10.7.tgz#08e72c554bd528f9f5fef604eea542551f9e5986"
+  integrity sha512-o1jcQGii+q7ORrXhBiMmGzFDaboc1qTgOOC3zDW+NR9ryVzWzL7qEeqoORbgDB5zk9OBsXCjB91fUH/ls5xMwg==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@mui/base" "5.0.0-alpha.99"
+    "@mui/core-downloads-tracker" "^5.10.7"
+    "@mui/system" "^5.10.7"
+    "@mui/types" "^7.2.0"
+    "@mui/utils" "^5.10.6"
+    "@types/react-transition-group" "^4.4.5"
+    clsx "^1.2.1"
+    csstype "^3.1.1"
+    prop-types "^15.8.1"
+    react-is "^18.2.0"
+    react-transition-group "^4.4.5"
+
+"@mui/private-theming@^5.10.6":
+  version "5.10.6"
+  resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.10.6.tgz#2c6bb2a4b7034cd402a099bd0349f217584e7b25"
+  integrity sha512-I/W0QyTLRdEx6py3lKAquKO/rNF/7j+nIOM/xCyI9kU0fcotVTcTY08mKMsS6vrzdWpi6pAkD0wP0KwWy5R5VA==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@mui/utils" "^5.10.6"
+    prop-types "^15.8.1"
+
+"@mui/styled-engine@^5.10.7":
+  version "5.10.7"
+  resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.10.7.tgz#0080319577aec765590e3c2272f6629427a65eb0"
+  integrity sha512-CCrtW+vvCKEm6pOE/QcutQ+ORC/iE6D1ghscN4l7LE2JXPvTXO/z0yu8Wxug1JEDlWm4r1Qa0PzJe1P9bjKzNA==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@emotion/cache" "^11.10.3"
+    csstype "^3.1.1"
+    prop-types "^15.8.1"
+
+"@mui/system@^5.10.7":
+  version "5.10.7"
+  resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.10.7.tgz#c13e5d135967e9689c473a66db4695ff78012701"
+  integrity sha512-kwyhjjKGsgtBRFl6vSqidDZcNKU5S1juTgm4Xi2fyWxaEbIQb9Sh9y0iVP2bNCJzgDr0alLaENOZOEaDWHISAQ==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@mui/private-theming" "^5.10.6"
+    "@mui/styled-engine" "^5.10.7"
+    "@mui/types" "^7.2.0"
+    "@mui/utils" "^5.10.6"
+    clsx "^1.2.1"
+    csstype "^3.1.1"
+    prop-types "^15.8.1"
+
+"@mui/types@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.0.tgz#91380c2d42420f51f404120f7a9270eadd6f5c23"
+  integrity sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==
+
+"@mui/utils@^5.10.6":
+  version "5.10.6"
+  resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.10.6.tgz#98d432d2b05544c46efe356cf095cea3a37c2e59"
+  integrity sha512-g0Qs8xN/MW2M3fLL8197h5J2VB9U+49fLlnKKqC6zy/yus5cZwdT+Gwec+wUMxgwQoxMDn+J8oDWAn28kEOR/Q==
+  dependencies:
+    "@babel/runtime" "^7.19.0"
+    "@types/prop-types" "^15.7.5"
+    "@types/react-is" "^16.7.1 || ^17.0.0"
+    prop-types "^15.8.1"
+    react-is "^18.2.0"
+
 "@nodelib/fs.scandir@2.1.5":
   version "2.1.5"
   resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -366,6 +567,11 @@
     "@nodelib/fs.scandir" "2.1.5"
     fastq "^1.6.0"
 
+"@popperjs/core@^2.11.6":
+  version "2.11.6"
+  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
+  integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
+
 "@reduxjs/toolkit@^1.8.1":
   version "1.8.3"
   resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.8.3.tgz#9c6a9c497bde43a67618d37a4175a00ae12efeb2"
@@ -411,7 +617,12 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199"
   integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==
 
-"@types/prop-types@*":
+"@types/parse-json@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
+"@types/prop-types@*", "@types/prop-types@^15.7.5":
   version "15.7.5"
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
   integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
@@ -428,6 +639,20 @@
   dependencies:
     "@types/react" "*"
 
+"@types/react-is@^16.7.1 || ^17.0.0":
+  version "17.0.3"
+  resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a"
+  integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==
+  dependencies:
+    "@types/react" "*"
+
+"@types/react-transition-group@^4.4.5":
+  version "4.4.5"
+  resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
+  integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
+  dependencies:
+    "@types/react" "*"
+
 "@types/react@*", "@types/react@^18.0.9":
   version "18.0.15"
   resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe"
@@ -667,6 +892,15 @@ axios@^0.27.2:
     follow-redirects "^1.14.9"
     form-data "^4.0.0"
 
+babel-plugin-macros@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
+  integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    cosmiconfig "^7.0.0"
+    resolve "^1.19.0"
+
 balanced-match@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -757,6 +991,11 @@ chokidar@^3.5.3:
   optionalDependencies:
     fsevents "~2.3.2"
 
+clsx@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+  integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
 color-convert@^1.9.0:
   version "1.9.3"
   resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -793,7 +1032,7 @@ concat-map@0.0.1:
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
   integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
-convert-source-map@^1.7.0:
+convert-source-map@^1.5.0, convert-source-map@^1.7.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
   integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
@@ -814,6 +1053,17 @@ copy-to-clipboard@^3.3.2:
   dependencies:
     toggle-selection "^1.0.6"
 
+cosmiconfig@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
+  integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
+  dependencies:
+    "@types/parse-json" "^4.0.0"
+    import-fresh "^3.2.1"
+    parse-json "^5.0.0"
+    path-type "^4.0.0"
+    yaml "^1.10.0"
+
 cross-spawn@^7.0.2:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -833,6 +1083,11 @@ csstype@^3.0.2:
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
   integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
 
+csstype@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
+  integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
+
 dayjs@^1.11.3:
   version "1.11.3"
   resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258"
@@ -915,6 +1170,14 @@ doctrine@^3.0.0:
   dependencies:
     esutils "^2.0.2"
 
+dom-helpers@^5.0.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+  integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
+  dependencies:
+    "@babel/runtime" "^7.8.7"
+    csstype "^3.0.2"
+
 electron-to-chromium@^1.4.172:
   version "1.4.185"
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz#3432d7944f1c5fe20664bb45d9cced2151405ce2"
@@ -927,6 +1190,13 @@ errno@^0.1.1:
   dependencies:
     prr "~1.0.1"
 
+error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
 es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
   version "1.20.1"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
@@ -1310,6 +1580,11 @@ fill-range@^7.0.1:
   dependencies:
     to-regex-range "^5.0.1"
 
+find-root@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+  integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
 flat-cache@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -1495,7 +1770,7 @@ has@^1.0.3:
   dependencies:
     function-bind "^1.1.1"
 
-hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
+hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
   integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -1559,6 +1834,11 @@ internal-slot@^1.0.3:
     has "^1.0.3"
     side-channel "^1.0.4"
 
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
 is-bigint@^1.0.1:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@@ -1692,6 +1972,11 @@ jsesc@^2.5.1:
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
   integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
 
+json-parse-even-better-errors@^2.3.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
 json-schema-traverse@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -1745,6 +2030,11 @@ lilconfig@^2.0.5:
   resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
   integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
 
+lines-and-columns@^1.1.6:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
 lodash-es@^4.17.21:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
@@ -1961,6 +2251,16 @@ parent-module@^1.0.0:
   dependencies:
     callsites "^3.0.0"
 
+parse-json@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    error-ex "^1.3.1"
+    json-parse-even-better-errors "^2.3.0"
+    lines-and-columns "^1.1.6"
+
 parse-node-version@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
@@ -2085,7 +2385,7 @@ prettier@2.5.1:
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
   integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
 
-prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
   version "15.8.1"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
   integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -2141,7 +2441,7 @@ react-is@^16.13.1, react-is@^16.7.0:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
-react-is@^18.0.0:
+react-is@^18.0.0, react-is@^18.2.0:
   version "18.2.0"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
   integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
@@ -2177,6 +2477,16 @@ react-router@6.4.0:
   dependencies:
     "@remix-run/router" "1.0.0"
 
+react-transition-group@^4.4.5:
+  version "4.4.5"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+  integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    dom-helpers "^5.0.1"
+    loose-envify "^1.4.0"
+    prop-types "^15.6.2"
+
 react@^18.1.0:
   version "18.2.0"
   resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@@ -2239,7 +2549,7 @@ resolve-from@^4.0.0:
   resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
   integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
 
-resolve@^1.1.7, resolve@^1.22.1:
+resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.1:
   version "1.22.1"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
   integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -2353,6 +2663,11 @@ source-map-js@^1.0.2:
   resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
   integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
 
+source-map@^0.5.7:
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+  integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+
 source-map@~0.6.0:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@@ -2407,6 +2722,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
   integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
 
+stylis@4.0.13:
+  version "4.0.13"
+  resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
+  integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
+
 supports-color@^5.3.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -2600,6 +2920,11 @@ yallist@^4.0.0:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
+yaml@^1.10.0:
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
 yaml@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"