Uniformize styles for dialogs and popovers, add ContextMenu

Change-Id: I8687b2d171f9c15e8eb8dd5ba2a32cdaa27b70d6
diff --git a/client/src/components/PopoverList.tsx b/client/src/components/PopoverList.tsx
new file mode 100644
index 0000000..7c81344
--- /dev/null
+++ b/client/src/components/PopoverList.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import {
+  ListItemText,
+  ListItemTextProps,
+  MenuItem,
+  MenuItemProps,
+  MenuList,
+  MenuListProps,
+  MenuProps,
+  Stack,
+  styled,
+  SvgIconProps,
+} from '@mui/material';
+import { ComponentType } from 'react';
+
+export type PopoverListItemData = {
+  label: string;
+  Icon: ComponentType<SvgIconProps>;
+  onClick: () => void;
+};
+
+interface ListIconProps extends SvgIconProps {
+  Icon: ComponentType<SvgIconProps>;
+}
+
+const ListIcon = styled(({ Icon, ...props }: ListIconProps) => <Icon {...props} />)(({ theme }) => ({
+  height: '16px',
+  fontSize: '16px',
+  color: theme?.palette?.primary?.dark,
+}));
+
+interface ListLabelProps extends ListItemTextProps {
+  label: string;
+}
+
+const ListLabel = styled(({ label, ...props }: ListLabelProps) => (
+  <ListItemText
+    {...props}
+    primary={label}
+    primaryTypographyProps={{
+      fontSize: '12px',
+      lineHeight: '16px',
+    }}
+  />
+))(() => ({
+  height: '16px',
+}));
+
+interface PopoverListItemProps extends MenuItemProps {
+  item: PopoverListItemData;
+  closeMenu?: MenuProps['onClose'];
+}
+
+const PopoverListItem = styled(({ item, closeMenu, ...props }: PopoverListItemProps) => (
+  <MenuItem
+    {...props}
+    onClick={() => {
+      item.onClick();
+      closeMenu?.({}, 'backdropClick');
+    }}
+    sx={{
+      paddingY: '11px',
+      paddingX: '16px',
+    }}
+  >
+    <Stack direction="row" spacing="10px">
+      <ListIcon Icon={item.Icon} />
+      <ListLabel label={item.label} />
+    </Stack>
+  </MenuItem>
+))(() => ({
+  // Failed to modify the styles from here
+}));
+
+interface PopoverListProps extends MenuListProps {
+  items: PopoverListItemData[];
+  onClose?: MenuProps['onClose'];
+}
+
+// A list intended to be used as a menu into a popover
+const PopoverList = styled(({ items, onClose, ...props }: PopoverListProps) => (
+  <MenuList {...props}>
+    {items.map((item, index) => (
+      <PopoverListItem key={index} item={item} closeMenu={onClose} />
+    ))}
+  </MenuList>
+))(() => ({
+  padding: '3px 0px',
+}));
+
+export default PopoverList;