From 31764d291c754853bce84ead89df96f6340d53cd Mon Sep 17 00:00:00 2001 From: Ebubeker Rexha <60944813+Ebubeker@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:30:04 +0200 Subject: [PATCH 1/9] feat: still working in the content management --- .../keycloak-theme/src/login/Template.tsx | 2 +- .../keycloak-theme/src/login/pages/Login.tsx | 2 +- .../src/login/pages/LoginResetPassword.tsx | 2 +- .../src/login/pages/LoginUpdatePassword.tsx | 2 +- .../src/login/pages/RegisterUserProfile.tsx | 2 +- .../pages/shared/UserProfileFormFields.tsx | 4 +- .../packages/keycloak-theme/src/theme.tsx | 4 +- .../packages/ui/components/Alert.tsx | 6 +- .../packages/ui/components/Button.tsx | 2 +- .../ui/components/DataDisplay/Chip.tsx | 57 + .../components/{ => DataDisplay}/Divider.tsx | 2 +- .../{ => DataDisplay}/EnhancedTable.tsx | 69 +- .../DataDisplay/FileManagementTable.tsx | 322 + .../components/{Icon => DataDisplay}/Icon.tsx | 18 - .../{Icon => DataDisplay}/IconButton.tsx | 98 +- .../ui/components/{ => DataDisplay}/Table.tsx | 10 +- .../components/{Text => DataDisplay}/Text.tsx | 0 .../components/{ => DataDisplay}/Tooltip.tsx | 4 +- .../ui/components/DataDisplay/TreeView.tsx | 141 + .../ui/components/DataDisplay/index.ts | 10 + .../packages/ui/components/Dialog.tsx | 18 +- .../packages/ui/components/Icon/IconBase.ts | 11 - .../packages/ui/components/Icon/index.ts | 2 - .../components/{ => Inputs}/SelectField.tsx | 2 +- .../components/{Text => Inputs}/TextField.tsx | 22 +- .../packages/ui/components/Inputs/index.ts | 2 + .../packages/ui/components/Lists/ChipList.tsx | 2 +- .../{ => Navigation}/DashboardSidebar.tsx | 11 +- .../ui/components/{ => Navigation}/Footer.tsx | 8 +- .../ui/components/{ => Navigation}/Tabs.tsx | 2 +- .../ui/components/Navigation/ToggleTabs.tsx | 62 + .../components/{ => Navigation}/Toolbar.tsx | 8 +- .../ui/components/Navigation/index.ts | 5 + .../ui/components/{ => Surfaces}/Banner.tsx | 4 +- .../ui/components/{Card => Surfaces}/Card.tsx | 2 +- .../{Card => Surfaces}/CardContent.tsx | 0 .../{Card => Surfaces}/CardMedia.tsx | 0 .../ui/components/{Card => Surfaces}/index.ts | 1 + .../packages/ui/components/Text/TextBase.ts | 9 - .../packages/ui/components/Text/index.ts | 1 - .../components/temporary/DashboardLayout.tsx | 16 +- .../temporary/auth/steps/Create.tsx | 6 +- .../contentManagement/ContentManagement.tsx | 318 + .../components/ContentInfoModal.tsx | 154 + .../components/HeaderCard.tsx | 87 + .../contentManagement/components/MoreMenu.tsx | 91 + .../components/TreeViewFilter.tsx | 86 + .../ui/components/temporary/home/CardList.tsx | 10 +- .../temporary/home/NewsLetterSection.tsx | 4 +- .../temporary/settings/Settings.tsx | 2 +- .../settings/organization/ManageUsers.tsx | 12 +- .../settings/organization/Organization.tsx | 2 +- .../settings/organization/Overview.tsx | 4 +- .../settings/subscription/Overview.tsx | 2 +- .../settings/subscription/Subscription.tsx | 2 +- .../subscription/SubscriptionSettings.tsx | 2 +- .../subscription/SubscriptionStatusCard.tsx | 2 +- app/client-v2/packages/ui/components/theme.ts | 34 +- app/client-v2/packages/ui/lib/color.ts | 2 + app/client-v2/packages/ui/lib/shadows.ts | 2 + .../components/ContentManagement.stories.tsx | 31 + .../components/Data Display/Chip.stories.tsx | 85 + .../{ => Data Display}/Divider.stories.tsx | 4 +- .../Icon.stories.tsx | 0 .../IconButton.stories.tsx | 0 .../components/Data Display/Table.stories.tsx | 517 ++ .../Text.stories.tsx | 0 .../{ => Data Display}/Tooltip.stories.tsx | 4 +- .../Data Display/TreeView.stories.tsx | 67 + .../components/EnhancedTable.stories.tsx | 328 - .../{ => Inputs}/SelectField.stories.tsx | 4 +- .../TextField.stories.tsx | 2 +- .../{ => Navigation}/Footer.stories.tsx | 4 +- .../{ => Navigation}/Sidebar.stories.tsx | 4 +- .../{ => Navigation}/Tabs.stories.tsx | 4 +- .../Navigation/ToggleTab.stories.tsx | 41 + .../{ => Navigation}/Toolbar.stories.tsx | 6 +- .../{ => Surfaces}/Banner.stories.tsx | 4 +- .../Card.stories.tsx | 10 +- .../CardContent.stories.tsx | 2 +- .../CardMedia.stories.tsx | 2 +- .../ui/stories/components/Table.stories.tsx | 68 - app/client-v2/packages/ui/stories/theme.ts | 32 +- app/client-v2/pnpm-lock.yaml | 7742 +++++++++-------- 84 files changed, 6372 insertions(+), 4356 deletions(-) create mode 100644 app/client-v2/packages/ui/components/DataDisplay/Chip.tsx rename app/client-v2/packages/ui/components/{ => DataDisplay}/Divider.tsx (96%) rename app/client-v2/packages/ui/components/{ => DataDisplay}/EnhancedTable.tsx (87%) create mode 100644 app/client-v2/packages/ui/components/DataDisplay/FileManagementTable.tsx rename app/client-v2/packages/ui/components/{Icon => DataDisplay}/Icon.tsx (87%) rename app/client-v2/packages/ui/components/{Icon => DataDisplay}/IconButton.tsx (62%) rename app/client-v2/packages/ui/components/{ => DataDisplay}/Table.tsx (96%) rename app/client-v2/packages/ui/components/{Text => DataDisplay}/Text.tsx (100%) rename app/client-v2/packages/ui/components/{ => DataDisplay}/Tooltip.tsx (90%) create mode 100644 app/client-v2/packages/ui/components/DataDisplay/TreeView.tsx create mode 100644 app/client-v2/packages/ui/components/DataDisplay/index.ts delete mode 100644 app/client-v2/packages/ui/components/Icon/IconBase.ts delete mode 100644 app/client-v2/packages/ui/components/Icon/index.ts rename app/client-v2/packages/ui/components/{ => Inputs}/SelectField.tsx (97%) rename app/client-v2/packages/ui/components/{Text => Inputs}/TextField.tsx (96%) create mode 100644 app/client-v2/packages/ui/components/Inputs/index.ts rename app/client-v2/packages/ui/components/{ => Navigation}/DashboardSidebar.tsx (92%) rename app/client-v2/packages/ui/components/{ => Navigation}/Footer.tsx (95%) rename app/client-v2/packages/ui/components/{ => Navigation}/Tabs.tsx (97%) create mode 100644 app/client-v2/packages/ui/components/Navigation/ToggleTabs.tsx rename app/client-v2/packages/ui/components/{ => Navigation}/Toolbar.tsx (90%) create mode 100644 app/client-v2/packages/ui/components/Navigation/index.ts rename app/client-v2/packages/ui/components/{ => Surfaces}/Banner.tsx (97%) rename app/client-v2/packages/ui/components/{Card => Surfaces}/Card.tsx (99%) rename app/client-v2/packages/ui/components/{Card => Surfaces}/CardContent.tsx (100%) rename app/client-v2/packages/ui/components/{Card => Surfaces}/CardMedia.tsx (100%) rename app/client-v2/packages/ui/components/{Card => Surfaces}/index.ts (76%) delete mode 100644 app/client-v2/packages/ui/components/Text/TextBase.ts delete mode 100644 app/client-v2/packages/ui/components/Text/index.ts create mode 100644 app/client-v2/packages/ui/components/temporary/contentManagement/ContentManagement.tsx create mode 100644 app/client-v2/packages/ui/components/temporary/contentManagement/components/ContentInfoModal.tsx create mode 100644 app/client-v2/packages/ui/components/temporary/contentManagement/components/HeaderCard.tsx create mode 100644 app/client-v2/packages/ui/components/temporary/contentManagement/components/MoreMenu.tsx create mode 100644 app/client-v2/packages/ui/components/temporary/contentManagement/components/TreeViewFilter.tsx create mode 100644 app/client-v2/packages/ui/stories/components/ContentManagement.stories.tsx create mode 100644 app/client-v2/packages/ui/stories/components/Data Display/Chip.stories.tsx rename app/client-v2/packages/ui/stories/components/{ => Data Display}/Divider.stories.tsx (87%) rename app/client-v2/packages/ui/stories/components/{Icon Components => Data Display}/Icon.stories.tsx (100%) rename app/client-v2/packages/ui/stories/components/{Icon Components => Data Display}/IconButton.stories.tsx (100%) create mode 100644 app/client-v2/packages/ui/stories/components/Data Display/Table.stories.tsx rename app/client-v2/packages/ui/stories/components/{Text Component => Data Display}/Text.stories.tsx (100%) rename app/client-v2/packages/ui/stories/components/{ => Data Display}/Tooltip.stories.tsx (90%) create mode 100644 app/client-v2/packages/ui/stories/components/Data Display/TreeView.stories.tsx delete mode 100644 app/client-v2/packages/ui/stories/components/EnhancedTable.stories.tsx rename app/client-v2/packages/ui/stories/components/{ => Inputs}/SelectField.stories.tsx (91%) rename app/client-v2/packages/ui/stories/components/{Text Component => Inputs}/TextField.stories.tsx (95%) rename app/client-v2/packages/ui/stories/components/{ => Navigation}/Footer.stories.tsx (94%) rename app/client-v2/packages/ui/stories/components/{ => Navigation}/Sidebar.stories.tsx (87%) rename app/client-v2/packages/ui/stories/components/{ => Navigation}/Tabs.stories.tsx (87%) create mode 100644 app/client-v2/packages/ui/stories/components/Navigation/ToggleTab.stories.tsx rename app/client-v2/packages/ui/stories/components/{ => Navigation}/Toolbar.stories.tsx (82%) rename app/client-v2/packages/ui/stories/components/{ => Surfaces}/Banner.stories.tsx (97%) rename app/client-v2/packages/ui/stories/components/{Card Components => Surfaces}/Card.stories.tsx (92%) rename app/client-v2/packages/ui/stories/components/{Card Components => Surfaces}/CardContent.stories.tsx (95%) rename app/client-v2/packages/ui/stories/components/{Card Components => Surfaces}/CardMedia.stories.tsx (94%) delete mode 100644 app/client-v2/packages/ui/stories/components/Table.stories.tsx diff --git a/app/client-v2/packages/keycloak-theme/src/login/Template.tsx b/app/client-v2/packages/keycloak-theme/src/login/Template.tsx index 60aaceced..2bb43f89e 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/Template.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/Template.tsx @@ -13,7 +13,7 @@ import { memo } from "react"; import { symToStr } from "tsafe/symToStr"; import { Alert } from "@p4b/ui/components/Alert"; -import { Card } from "@p4b/ui/components/Card"; +import { Card } from "@p4b/ui/components/Surfaces"; import { useIsDarkModeEnabled } from "@p4b/ui/lib"; import { useDomRect, useWindowInnerSize } from "@p4b/ui/lib"; diff --git a/app/client-v2/packages/keycloak-theme/src/login/pages/Login.tsx b/app/client-v2/packages/keycloak-theme/src/login/pages/Login.tsx index fbad344f4..0c1d557ec 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/pages/Login.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/pages/Login.tsx @@ -12,7 +12,7 @@ import { useStateRef } from "powerhooks/useStateRef"; import { useState, type FormEventHandler } from "react"; import { Checkbox } from "@p4b/ui/components/Checkbox"; -import { TextField } from "@p4b/ui/components/Text/TextField"; +import { TextField } from "@p4b/ui/components/Inputs"; import { makeStyles, Text, Button } from "../../theme"; import type { I18n } from "../i18n"; diff --git a/app/client-v2/packages/keycloak-theme/src/login/pages/LoginResetPassword.tsx b/app/client-v2/packages/keycloak-theme/src/login/pages/LoginResetPassword.tsx index 9afaaf949..55a373890 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/pages/LoginResetPassword.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/pages/LoginResetPassword.tsx @@ -1,7 +1,7 @@ import { Link } from "@mui/material"; import type { PageProps } from "keycloakify/login/pages/PageProps"; -import { TextField } from "@p4b/ui/components/Text/TextField"; +import { TextField } from "@p4b/ui/components/Inputs/TextField"; import { Button, makeStyles, Text } from "../../theme"; import type { I18n } from "../i18n"; diff --git a/app/client-v2/packages/keycloak-theme/src/login/pages/LoginUpdatePassword.tsx b/app/client-v2/packages/keycloak-theme/src/login/pages/LoginUpdatePassword.tsx index fbff2fe4c..1a025d80a 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/pages/LoginUpdatePassword.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/pages/LoginUpdatePassword.tsx @@ -2,7 +2,7 @@ import FormControlLabel from "@mui/material/FormControlLabel"; import type { PageProps } from "keycloakify/login/pages/PageProps"; import { Checkbox } from "@p4b/ui/components/Checkbox"; -import { TextField } from "@p4b/ui/components/Text/TextField"; +import { TextField } from "@p4b/ui/components/Inputs/TextField"; import { makeStyles, Text, Button } from "../../theme"; import type { I18n } from "../i18n"; diff --git a/app/client-v2/packages/keycloak-theme/src/login/pages/RegisterUserProfile.tsx b/app/client-v2/packages/keycloak-theme/src/login/pages/RegisterUserProfile.tsx index 6a89e4e50..6f59d22b4 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/pages/RegisterUserProfile.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/pages/RegisterUserProfile.tsx @@ -5,7 +5,7 @@ import { useRef, useState } from "react"; // @ts-ignore import ReCAPTCHA from "react-google-recaptcha"; -import { Tooltip } from "@p4b/ui/components/Tooltip"; +import { Tooltip } from "@p4b/ui/components/DataDisplay/Tooltip"; import { useIsDarkModeEnabled } from "@p4b/ui/lib"; import { makeStyles, Button, Text } from "../../theme"; diff --git a/app/client-v2/packages/keycloak-theme/src/login/pages/shared/UserProfileFormFields.tsx b/app/client-v2/packages/keycloak-theme/src/login/pages/shared/UserProfileFormFields.tsx index fe6e533cc..4aea1b5e9 100644 --- a/app/client-v2/packages/keycloak-theme/src/login/pages/shared/UserProfileFormFields.tsx +++ b/app/client-v2/packages/keycloak-theme/src/login/pages/shared/UserProfileFormFields.tsx @@ -7,8 +7,8 @@ import { useMemo, useEffect, Fragment } from "react"; import { capitalize } from "tsafe/capitalize"; import { Checkbox } from "@p4b/ui/components/Checkbox"; -import type { AttributeOptions } from "@p4b/ui/components/Text/TextField"; -import { TextField } from "@p4b/ui/components/Text/TextField"; +import type { AttributeOptions } from "@p4b/ui/components/Inputs"; +import { TextField } from "@p4b/ui/components/Inputs"; import { Text, makeStyles } from "../../../theme"; import { regExpStrToEmailDomains } from "../../emailDomainAcceptListHelper"; diff --git a/app/client-v2/packages/keycloak-theme/src/theme.tsx b/app/client-v2/packages/keycloak-theme/src/theme.tsx index 81a84c974..806b46396 100644 --- a/app/client-v2/packages/keycloak-theme/src/theme.tsx +++ b/app/client-v2/packages/keycloak-theme/src/theme.tsx @@ -2,9 +2,7 @@ import CloseSharp from "@mui/icons-material/CloseSharp"; import "@p4b/ui/assets/fonts/mulish/font.css"; import { createButton } from "@p4b/ui/components/Button"; -import { createIcon } from "@p4b/ui/components/Icon"; -import { createIconButton } from "@p4b/ui/components/Icon/IconButton"; -import { createText } from "@p4b/ui/components/Text"; +import { createText, createIconButton, createIcon } from "@p4b/ui/components/DataDisplay"; import { createThemeProvider, defaultGetTypographyDesc, diff --git a/app/client-v2/packages/ui/components/Alert.tsx b/app/client-v2/packages/ui/components/Alert.tsx index 0197f7747..7427a52e8 100644 --- a/app/client-v2/packages/ui/components/Alert.tsx +++ b/app/client-v2/packages/ui/components/Alert.tsx @@ -7,9 +7,9 @@ import { useReducer, memo } from "react"; import type { ReactNode } from "react"; import { makeStyles } from "../lib/ThemeProvider"; -import { createIcon } from "./Icon/Icon"; -import { createIconButton } from "./Icon/IconButton"; -import { Text } from "./Text/TextBase"; +import { createIcon } from "./DataDisplay"; +import { createIconButton } from "./DataDisplay/IconButton"; +import { Text } from "./theme"; export type AlertProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Button.tsx b/app/client-v2/packages/ui/components/Button.tsx index c2c18a20a..143ae5ba2 100644 --- a/app/client-v2/packages/ui/components/Button.tsx +++ b/app/client-v2/packages/ui/components/Button.tsx @@ -18,7 +18,7 @@ import { makeStyles } from "../lib/ThemeProvider"; import { breakpointsValues } from "../lib/breakpoints"; import { variantNameUsedForMuiButton } from "../lib/typography"; import { pxToNumber } from "../tools/pxToNumber"; -import type { IconProps } from "./Icon/Icon"; +import type { IconProps } from "./DataDisplay"; export type ButtonProps = | ButtonProps.Regular diff --git a/app/client-v2/packages/ui/components/DataDisplay/Chip.tsx b/app/client-v2/packages/ui/components/DataDisplay/Chip.tsx new file mode 100644 index 000000000..72474fdfb --- /dev/null +++ b/app/client-v2/packages/ui/components/DataDisplay/Chip.tsx @@ -0,0 +1,57 @@ +import { Chip as MUIChip } from "@mui/material"; +import React from "react"; + +import { changeColorOpacity } from "../../lib"; +import { makeStyles } from "../../lib/ThemeProvider"; + +interface ChipProps { + variant: "filled" | "Border" | "filledWithBorder"; + textDesign: "normal" | "italic"; + label: React.ReactNode; +} + +export const Chip = (props: ChipProps) => { + const { variant = "filled", textDesign = "normal", label } = props; + + const { classes } = useStyles({ variant, textDesign }); + + return ; +}; + +const useStyles = makeStyles<{ + variant: "filled" | "Border" | "filledWithBorder"; + textDesign: "normal" | "italic"; +}>({ name: { Chip } })((theme, { variant, textDesign }) => { + let bgColor; + switch (variant) { + case "filled": + case "filledWithBorder": + bgColor = changeColorOpacity({ + color: theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant2, + opacity: 0.3, + }); + break; + case "Border": + bgColor = "transparent"; + break; + } + + let border; + switch (variant) { + case "filled": + border = "none"; + break; + case "filledWithBorder": + case "Border": + border = `1px solid ${theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant3}`; + break; + } + + return { + chip: { + backgroundColor: bgColor, + border: border, + fontStyle: textDesign === "italic" ? "italic" : "normal", + }, + }; +}); diff --git a/app/client-v2/packages/ui/components/Divider.tsx b/app/client-v2/packages/ui/components/DataDisplay/Divider.tsx similarity index 96% rename from app/client-v2/packages/ui/components/Divider.tsx rename to app/client-v2/packages/ui/components/DataDisplay/Divider.tsx index 89bff14b6..11a371475 100644 --- a/app/client-v2/packages/ui/components/Divider.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/Divider.tsx @@ -3,7 +3,7 @@ import { forwardRef, memo } from "react"; import type { Equals } from "tsafe"; import { assert } from "tsafe/assert"; -import { makeStyles } from "../lib/ThemeProvider"; +import { makeStyles } from "../../lib/ThemeProvider"; export type DividerProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/EnhancedTable.tsx b/app/client-v2/packages/ui/components/DataDisplay/EnhancedTable.tsx similarity index 87% rename from app/client-v2/packages/ui/components/EnhancedTable.tsx rename to app/client-v2/packages/ui/components/DataDisplay/EnhancedTable.tsx index c33a167a5..7afeabf4f 100644 --- a/app/client-v2/packages/ui/components/EnhancedTable.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/EnhancedTable.tsx @@ -12,11 +12,11 @@ import TableSortLabel from "@mui/material/TableSortLabel"; import { visuallyHidden } from "@mui/utils"; import * as React from "react"; -import { changeColorOpacity } from "../lib"; -import { makeStyles } from "../lib/ThemeProvider"; -import Dialog from "./Dialog"; -import { Text } from "./theme"; -import { IconButton } from "./theme"; +import { changeColorOpacity } from "../../lib"; +import { makeStyles } from "../../lib/ThemeProvider"; +import Dialog from "../Dialog"; +import { Text } from "../theme"; +import { IconButton } from "../theme"; function descendingComparator(a: T, b: T, orderBy: keyof T) { if (b[orderBy] < a[orderBy]) { @@ -76,7 +76,7 @@ function EnhancedTableHead(props: EnhancedTableProps) { onRequestSort(event, property); }; - const { classes } = useStyles(); + const { classes } = useStyles({ dense: undefined, alternativeColors: false, checkbox }); return ( @@ -104,7 +104,9 @@ function EnhancedTableHead(props: EnhancedTableProps) { active={orderBy === headCell.id} direction={orderBy === headCell.id ? order : "asc"} onClick={createSortHandler(headCell.id)}> - {headCell.label} + + {headCell.label} + {orderBy === headCell.id ? ( {order === "desc" ? "sorted descending" : "sorted ascending"} @@ -120,7 +122,10 @@ function EnhancedTableHead(props: EnhancedTableProps) { } type EnhanceTableProps = { - rows: { name: string | number; [key: string]: any }[]; + rows: { name: React.ReactNode; [key: string]: any }[]; + dense: boolean; + alternativeColors: boolean; + hover?: boolean; columnNames: { id: string; numeric: boolean; @@ -132,8 +137,19 @@ type EnhanceTableProps = { more?: boolean; }; -export default function EnhancedTable(props: EnhanceTableProps) { - const { rows, columnNames, openDialog, dialog, checkbox = true, more = true, ...rest } = props; +export function EnhancedTable(props: EnhanceTableProps) { + const { + rows, + columnNames, + openDialog, + dense, + dialog, + checkbox = true, + more = true, + alternativeColors = true, + hover = false, + ...rest + } = props; type ObjectKeys = keyof (typeof rows)[0]; @@ -144,9 +160,8 @@ export default function EnhancedTable(props: EnhanceTableProps) { const [selected, setSelected] = React.useState<(string | number)[]>([]); const [anchorEl, setAnchorEl] = React.useState(null); const [page, setPage] = React.useState(0); - const [dense, setDense] = React.useState(false); const [rowsPerPage, setRowsPerPage] = React.useState(5); - const { classes } = useStyles(); + const { classes } = useStyles({ dense, alternativeColors, checkbox }); const handleRequestSort = (event: React.MouseEvent, property: keyof ObjectKeys) => { const isAsc = orderBy === property && order === "asc"; @@ -188,10 +203,6 @@ export default function EnhancedTable(props: EnhanceTableProps) { setPage(0); }; - const handleChangeDense = (event: React.ChangeEvent) => { - setDense(event.target.checked); - }; - const isSelected = (name: string | number) => selected.indexOf(name) !== -1; function openDialogInitializer(event: React.MouseEvent, indx: number) { @@ -243,7 +254,7 @@ export default function EnhancedTable(props: EnhanceTableProps) { return ( ({ name: { EnhancedTable }, -})((theme) => ({ +})((theme, { dense, alternativeColors, checkbox }) => ({ tableRow: { - border: "none", backgroundColor: "transparent", "&:nth-of-type": {}, "&:nth-of-type(odd)": { - backgroundColor: changeColorOpacity({ color: theme.colors.palette.focus.main, opacity: 0.08 }), + backgroundColor: alternativeColors + ? changeColorOpacity({ color: theme.colors.palette.focus.main, opacity: 0.08 }) + : "transparent", borderColor: changeColorOpacity({ color: theme.colors.palette.focus.main, opacity: 0.08 }), }, // hide last border "&:last-child td, &:last-child th": { - border: 0, + border: alternativeColors ? 0 : "", + }, + "&.MuiTableRow-hover:hover": { + background: theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant1, }, }, tableCell: { @@ -357,7 +372,11 @@ const useStyles = makeStyles({ [`&.${tableCellClasses.body}`]: { fontSize: 14, border: "none", + borderBottom: alternativeColors + ? "none" + : `0.5px solid ${theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant1}`, }, + paddingLeft: checkbox ? 0 : theme.spacing(3), }, tableContainer: { boxShadow: "none", @@ -365,7 +384,11 @@ const useStyles = makeStyles({ backgroundColor: "transparent", }, tableCellText: { - padding: theme.spacing(3), + padding: dense ? 0 : theme.spacing(3), fontSize: "12px", }, + tableCellHeaderText: { + fontWeight: "bold", + paddingLeft: checkbox ? theme.spacing(3) : 0, + }, })); diff --git a/app/client-v2/packages/ui/components/DataDisplay/FileManagementTable.tsx b/app/client-v2/packages/ui/components/DataDisplay/FileManagementTable.tsx new file mode 100644 index 000000000..2693d6544 --- /dev/null +++ b/app/client-v2/packages/ui/components/DataDisplay/FileManagementTable.tsx @@ -0,0 +1,322 @@ +import Box from "@mui/material/Box"; +import Paper from "@mui/material/Paper"; +import Table from "@mui/material/Table"; +import TableBody from "@mui/material/TableBody"; +import TableCell, { tableCellClasses } from "@mui/material/TableCell"; +import TableContainer from "@mui/material/TableContainer"; +import TableHead from "@mui/material/TableHead"; +import TablePagination from "@mui/material/TablePagination"; +import TableRow from "@mui/material/TableRow"; +import TableSortLabel from "@mui/material/TableSortLabel"; +import { visuallyHidden } from "@mui/utils"; +import * as React from "react"; + +import { changeColorOpacity } from "../../lib"; +import { makeStyles } from "../../lib/ThemeProvider"; +import { Text } from "../theme"; +import { IconButton } from "../theme"; + +function descendingComparator(a: T, b: T, orderBy: keyof T) { + if (b[orderBy] < a[orderBy]) { + return -1; + } + if (b[orderBy] > a[orderBy]) { + return 1; + } + return 0; +} + +type Order = "asc" | "desc"; + +function getComparator( + order: Order, + orderBy: Key +): (a: { [key in Key]: number | string }, b: { [key in Key]: number | string }) => number { + return order === "desc" + ? (a, b) => descendingComparator(a, b, orderBy) + : (a, b) => -descendingComparator(a, b, orderBy); +} + +// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). +// stableSort() brings sort stability to non-modern browsers (notably IE11). If you +// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) +// with exampleArray.slice().sort(exampleComparator) +function stableSort(array: readonly T[], comparator: (a: T, b: T) => number) { + const stabilizedThis = array.map((el, index) => [el, index] as [T, number]); + stabilizedThis.sort((a, b) => { + const order = comparator(a[0], b[0]); + if (order !== 0) { + return order; + } + return a[1] - b[1]; + }); + return stabilizedThis.map((el) => el[0]); +} + +interface FileManagementHeadProps { + numSelected: number; + onRequestSort: (event: React.MouseEvent, property: any) => void; + order: Order; + orderBy: string | number; + rowCount: number; + columns: { + id: string; + numeric: boolean; + label: string; + }[]; +} + +function FileManagementHead(props: FileManagementHeadProps) { + const { order, orderBy, numSelected, rowCount, onRequestSort, columns } = props; + const createSortHandler = (property: any) => (event: React.MouseEvent) => { + onRequestSort(event, property); + }; + + const { classes } = useStyles(); + + return ( + + + {columns.map((headCell) => ( + + + + {headCell.label} + + {orderBy === headCell.id ? ( + + {order === "desc" ? "sorted descending" : "sorted ascending"} + + ) : null} + + + ))} + + + + ); +} + +type FileManagementProps = { + rows: { name: React.ReactNode; [key: string]: any }[]; + hover?: boolean; + columnNames: { + id: string; + numeric: boolean; + label: string; + }[]; + openDialog?: React.Dispatch>; + modal?: { body: React.ReactNode; action: React.ReactNode; header: React.ReactNode } | null; + openModal?: React.Dispatch>; + setDialogAnchor?: React.Dispatch>; + more?: boolean; +}; + +export function FileManagementTable(props: FileManagementProps) { + const { + rows, + columnNames, + openModal, + setDialogAnchor, + modal, + openDialog, + more = true, + hover = false, + ...rest + } = props; + + type ObjectKeys = keyof (typeof rows)[0]; + + const rowKeys: ObjectKeys[] = Object.keys(rows[0]) as ObjectKeys[]; + + const [order, setOrder] = React.useState("asc"); + const [orderBy, setOrderBy] = React.useState(rowKeys[0]); + const [selected, setSelected] = React.useState<(string | number)[]>([]); + const [modalStatus, setModalStatus] = React.useState(false); + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(5); + const { classes } = useStyles(); + + const handleRequestSort = (event: React.MouseEvent, property: keyof ObjectKeys) => { + const isAsc = orderBy === property && order === "asc"; + setOrder(isAsc ? "desc" : "asc"); + setOrderBy(property); + }; + + const handleChangePage = (event: unknown, newPage: number) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event: React.ChangeEvent) => { + setRowsPerPage(parseInt(event.target.value, 10)); + setPage(0); + }; + + const isSelected = (name: string | number) => selected.indexOf(name) !== -1; + + function handleRowClick(row: { [x: string]: string | number; [x: number]: string | number }) { + if (openModal && !React.isValidElement(row.name)) { + openModal(row); + } else { + } + } + + function openDialogInitializer(event: React.MouseEvent, indx: number) { + if (setDialogAnchor) { + setDialogAnchor(event.currentTarget); + if (openDialog) { + openDialog(rows[indx]); + } + } + } + + // Avoid a layout jump when reaching the last page with empty rows. + const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0; + + const visibleRows = React.useMemo( + () => + stableSort(rows, getComparator(order, orderBy)).slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage + ), + [order, orderBy, page, rowsPerPage] + ); + + return ( + + + + + + + {visibleRows.map((row, index) => { + const isItemSelected = isSelected(row.name); + const labelId = `enhanced-table-checkbox-${index}`; + + return ( + + {rowKeys && + rowKeys.map((key, index) => ( + handleRowClick(row)} + className={classes.tableCell} + key={index} + component="th" + id={labelId} + scope="row" + padding="none"> + + {row[key]} + + + ))} + {more ? ( + + openDialogInitializer(e, index)} + iconId="moreVert" + size="medium" + /> + + ) : null} + + ); + })} + {emptyRows > 0 && ( + + + + )} + +
+
+ +
+
+ ); +} + +const useStyles = makeStyles({ + name: { FileManagementTable }, +})((theme) => ({ + tableRow: { + backgroundColor: "transparent", + "&:nth-of-type": {}, + "&:nth-of-type(odd)": { + backgroundColor: "transparent", + borderColor: changeColorOpacity({ color: theme.colors.palette.focus.main, opacity: 0.08 }), + }, + "&.MuiTableRow-hover:hover": { + background: `${theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant1}80`, + }, + }, + tableCell: { + [`&.${tableCellClasses.head}`]: { + backgroundColor: "transparent", + color: theme.colors.useCases.typography[theme.isDarkModeEnabled ? "textSecondary" : "textPrimary"], + fontWeight: "bold", + borderBottom: `0.5px solid ${ + theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant1 + }`, + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + border: "none", + borderBottom: `0.5px solid ${ + theme.colors.palette[theme.isDarkModeEnabled ? "dark" : "light"].greyVariant1 + }`, + }, + paddingLeft: theme.spacing(3), + }, + tableContainer: { + boxShadow: "none", + backgroundImage: "none", + backgroundColor: "transparent", + }, + tableCellText: { + padding: 0, + fontSize: "12px", + }, + tableCellHeaderText: { + fontWeight: "bold", + paddingLeft: 0, + }, + modalHeader: { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }, +})); diff --git a/app/client-v2/packages/ui/components/Icon/Icon.tsx b/app/client-v2/packages/ui/components/DataDisplay/Icon.tsx similarity index 87% rename from app/client-v2/packages/ui/components/Icon/Icon.tsx rename to app/client-v2/packages/ui/components/DataDisplay/Icon.tsx index 68c48b5f8..ada4b4f09 100644 --- a/app/client-v2/packages/ui/components/Icon/Icon.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/Icon.tsx @@ -56,20 +56,6 @@ export type MuiIconLike = (props: { export type SvgComponentLike = ElementType; -// function blendHexColorWithOpacity(hexColor: string, opacity: number) { -// // Remove the '#' character from the hex color -// const normalizedHexColor = hexColor.replace("#", ""); - -// // Convert the opacity to its hexadecimal equivalent -// const opacityHex = Math.round(opacity * 255) -// .toString(16) -// .padStart(2, "0"); - -// // Combine the opacity hex value with the original hex color -// const blendedHexColor = `#${normalizedHexColor}${opacityHex}`; -// return blendedHexColor; -// } - function isMuiIcon(Component: MuiIconLike | SvgComponentLike): Component is MuiIconLike { return "type" in (Component as MuiIconLike); } @@ -109,10 +95,6 @@ export function createIcon(componentByIconId: { position: "relative", }, iconWrapper: { - // backgroundColor: wrapped ? `${theme.colors.palette.focus.main}14` : "", - // width: 'fit-content', - // height: 'fit-content', - // borderRadius: wrapped === "circle" ? "50%" : 4, padding: wrapped ? "4px" : "", display: "flex", alignItems: "center", diff --git a/app/client-v2/packages/ui/components/Icon/IconButton.tsx b/app/client-v2/packages/ui/components/DataDisplay/IconButton.tsx similarity index 62% rename from app/client-v2/packages/ui/components/Icon/IconButton.tsx rename to app/client-v2/packages/ui/components/DataDisplay/IconButton.tsx index c25b9b29b..dd174e1de 100644 --- a/app/client-v2/packages/ui/components/Icon/IconButton.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/IconButton.tsx @@ -35,6 +35,8 @@ export namespace IconButtonProps { tabIndex?: number; + /** Defaults to grey */ + iconVariant?: "white" | "secondary" | "focus" | "grey" | "grey2" | "error"; name?: string; id?: string; "aria-label"?: string; @@ -73,6 +75,7 @@ export function createIconButton(params?: { disabled = false, autoFocus = false, tabIndex, + iconVariant = "grey2", name, id, "aria-label": ariaLabel, @@ -95,7 +98,7 @@ export function createIconButton(params?: { }) ); - const { classes, cx } = useStyles({ disabled, isMouseIn }); + const { classes, cx } = useStyles({ disabled, isMouseIn, iconVariant }); return ( (params?: { }) ); - const useStyles = makeStyles<{ disabled: boolean; isMouseIn: boolean }>({ + const useStyles = makeStyles<{ + disabled: boolean; + isMouseIn: boolean; + iconVariant: "white" | "secondary" | "focus" | "grey" | "grey2" | "error"; + }>({ name: { IconButton }, - })((theme, { disabled, isMouseIn }) => ({ - root: { - padding: theme.spacing(2), - "&:hover": { - backgroundColor: "unset", - "& svg": { - color: theme.colors.useCases.buttons.actionHoverPrimary, + })((theme, { disabled, isMouseIn, iconVariant }) => { + let color; + let hoverColor; + switch (iconVariant) { + case "focus": + color = theme.colors.palette.focus.main; + hoverColor = theme.colors.palette.focus.light; + break; + case "secondary": + color = theme.colors.palette.light.main; + hoverColor = theme.colors.palette.light.light; + break; + case "grey": + color = theme.colors.palette.light.greyVariant4; + hoverColor = theme.colors.palette.light.greyVariant3; + break; + case "grey2": + color = theme.colors.palette.light.greyVariant2; + hoverColor = theme.colors.palette.light.greyVariant3; + break; + case "white": + color = theme.colors.palette.light.main; + hoverColor = theme.colors.palette.light.light; + break; + case "error": + color = theme.colors.palette.redError.main; + hoverColor = `${theme.colors.palette.redError.main}80`; + break; + default: + color = "light"; + break; + } + + return { + root: { + padding: theme.spacing(2), + "&:hover": { + backgroundColor: "unset", + "& svg": { + color: hoverColor, + }, }, - }, - //NOTE: If the position of the button is relative (the default) - //it goes hover everything not positioned, we have to mess with z-index and - //we don't want that. - //The relative positioning is needed for the touch ripple effect. - //If we dont have position relative the effect is not restricted to the - //button: https://user-images.githubusercontent.com/6702424/157982515-c97dfa81-b09a-4323-beb9-d1e92e7ebe4d.mov - //The solution is set 'position: relative' only when the ripple effect is supposed to be visible. - //This explain the following awful rules. - //The expected result is: https://user-images.githubusercontent.com/6702424/157984062-27e544c3-f86f-47b8-b141-c5f61b8a2880.mov - position: isMouseIn ? "relative" : "unset", - "& .MuiTouchRipple-root": { - display: isMouseIn ? "unset" : "none", + //NOTE: If the position of the button is relative (the default) + //it goes hover everything not positioned, we have to mess with z-index and + //we don't want that. + //The relative positioning is needed for the touch ripple effect. + //If we dont have position relative the effect is not restricted to the + //button: https://user-images.githubusercontent.com/6702424/157982515-c97dfa81-b09a-4323-beb9-d1e92e7ebe4d.mov + //The solution is set 'position: relative' only when the ripple effect is supposed to be visible. + //This explain the following awful rules. + //The expected result is: https://user-images.githubusercontent.com/6702424/157984062-27e544c3-f86f-47b8-b141-c5f61b8a2880.mov + position: isMouseIn ? "relative" : "unset", + "& .MuiTouchRipple-root": { + display: isMouseIn ? "unset" : "none", + }, + }, + icon: { + color: color, + "&:hover": { + color: hoverColor, + }, }, - }, - icon: { - color: theme.colors.useCases.typography[disabled ? "textDisabled" : "textPrimary"], - }, - })); + }; + }); return { IconButton }; } diff --git a/app/client-v2/packages/ui/components/Table.tsx b/app/client-v2/packages/ui/components/DataDisplay/Table.tsx similarity index 96% rename from app/client-v2/packages/ui/components/Table.tsx rename to app/client-v2/packages/ui/components/DataDisplay/Table.tsx index 0af9e4688..68ed5fd10 100644 --- a/app/client-v2/packages/ui/components/Table.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/Table.tsx @@ -9,11 +9,11 @@ import { forwardRef, memo } from "react"; import type { Dispatch, SetStateAction } from "react"; import React, { useState, useRef } from "react"; -import { changeColorOpacity } from "../lib"; -import { makeStyles } from "../lib/ThemeProvider"; -import { Checkbox } from "./Checkbox"; -import Dialog from "./Dialog"; -import { IconButton } from "./theme"; +import { changeColorOpacity } from "../../lib"; +import { makeStyles } from "../../lib/ThemeProvider"; +import { Checkbox } from "../Checkbox"; +import Dialog from "../Dialog"; +import { IconButton } from "../theme"; export type TableProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Text/Text.tsx b/app/client-v2/packages/ui/components/DataDisplay/Text.tsx similarity index 100% rename from app/client-v2/packages/ui/components/Text/Text.tsx rename to app/client-v2/packages/ui/components/DataDisplay/Text.tsx diff --git a/app/client-v2/packages/ui/components/Tooltip.tsx b/app/client-v2/packages/ui/components/DataDisplay/Tooltip.tsx similarity index 90% rename from app/client-v2/packages/ui/components/Tooltip.tsx rename to app/client-v2/packages/ui/components/DataDisplay/Tooltip.tsx index 926bba67e..274e6dfad 100644 --- a/app/client-v2/packages/ui/components/Tooltip.tsx +++ b/app/client-v2/packages/ui/components/DataDisplay/Tooltip.tsx @@ -5,8 +5,8 @@ import MuiTooltip from "@mui/material/Tooltip"; import { memo } from "react"; import type { ReactNode, ReactElement } from "react"; -import { makeStyles } from "../lib/ThemeProvider"; -import { Text } from "./Text/TextBase"; +import { makeStyles } from "../../lib/ThemeProvider"; +import { Text } from "../theme"; export type TooltipProps = { title: NonNullable | undefined; diff --git a/app/client-v2/packages/ui/components/DataDisplay/TreeView.tsx b/app/client-v2/packages/ui/components/DataDisplay/TreeView.tsx new file mode 100644 index 000000000..8ab1548a7 --- /dev/null +++ b/app/client-v2/packages/ui/components/DataDisplay/TreeView.tsx @@ -0,0 +1,141 @@ +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { TreeView, TreeItem } from "@mui/lab"; +import { Checkbox, FormControlLabel } from "@mui/material"; +import { styled } from "@mui/material/styles"; +import React, { useState, useEffect } from "react"; + +import { makeStyles } from "../../lib/ThemeProvider"; +import { Text } from "../theme"; + +// Custom styled TreeItem to adjust the padding +const StyledTreeItem = styled(TreeItem)(({ theme }) => ({ + "& .MuiTreeItem-content": { + paddingTop: theme.spacing(0.5), + paddingBottom: theme.spacing(0.5), + }, + "& .MuiTreeItem-content:hover, & .MuiTreeItem-content:focus, & .MuiTreeItem-content:active, & .MuiTreeItem-content.Mui-selected": + { + backgroundColor: "transparent", + }, +})); + +interface TreeNode { + id: string; + name: string; + count?: string; + children?: TreeNode[]; +} + +interface TreeViewProps { + treeData: TreeNode[]; + checkbox?: boolean; + selected: string[]; + changeSelected: (value: string[]) => void; +} + +export const TreeViewWithCheckboxes: React.FC = (props) => { + const { treeData, checkbox = true, selected, changeSelected } = props; + const [checked, setChecked] = useState([]); + + const { classes } = useStyles(); + + useEffect(() => { + if (!selected.length && checked.length) { + setChecked([]); + } + }, [selected]); + + const handleToggle = (event: React.ChangeEvent, nodeId: string) => { + if (checked.includes(nodeId)) { + setChecked(checked.filter((id) => id !== nodeId)); + changeSelected(checked.filter((id) => id !== nodeId)); + } else { + setChecked([...checked, nodeId]); + changeSelected([...checked, nodeId]); + } + }; + + const handleParentCheck = (parent: TreeNode) => { + if ("children" in parent) { + const checkedChildrenIds = getAllChildrenIds(parent); + const allChecked = checkedChildrenIds.every((id) => checked.includes(id)); + + if (allChecked) { + setChecked(checked.filter((id) => !checkedChildrenIds.includes(id))); + changeSelected(checked.filter((id) => !checkedChildrenIds.includes(id))); + } else { + setChecked([...checked, ...checkedChildrenIds]); + changeSelected([...checked, ...checkedChildrenIds]); + } + } + }; + + const getAllChildrenIds = (node: TreeNode): string[] => { + let childrenIds: string[] = []; + if (node.children) { + childrenIds = node.children.map((child) => child.id).flat(); + node.children.forEach((child) => { + childrenIds.push(...getAllChildrenIds(child)); + }); + } + return childrenIds; + }; + + const renderTree = (nodes: TreeNode) => ( + <> + checked.includes(child.id)) && + !checked.includes(nodes.id) + } + onChange={(event) => { + handleToggle(event, nodes.id); + handleParentCheck(nodes); + }} + /> + } + label={ + + {nodes.name} + {nodes.count ? ( + + {nodes.count} + + ) : null} + + } + /> + }> + {Array.isArray(nodes.children) ? nodes.children.map((childNode) => renderTree(childNode)) : null} + + + ); + + return ( + } defaultExpandIcon={}> + {treeData.map((data) => renderTree(data))} + + ); +}; + +const useStyles = makeStyles({ name: { TreeViewWithCheckboxes } })((theme) => ({ + label: { + "&:hover": { + background: "transparent", + }, + }, + count: { + fontStyle: "italic", + color: theme.colors.palette.dark.greyVariant4, + }, +})); diff --git a/app/client-v2/packages/ui/components/DataDisplay/index.ts b/app/client-v2/packages/ui/components/DataDisplay/index.ts new file mode 100644 index 000000000..93ee285e6 --- /dev/null +++ b/app/client-v2/packages/ui/components/DataDisplay/index.ts @@ -0,0 +1,10 @@ +export * from "./Chip"; +export * from "./Divider"; +export * from "./EnhancedTable"; +export * from "./FileManagementTable"; +export * from "./Icon"; +export * from "./IconButton"; +export * from "./Table"; +export * from "./Text"; +export * from "./Tooltip"; +export * from "./TreeView"; diff --git a/app/client-v2/packages/ui/components/Dialog.tsx b/app/client-v2/packages/ui/components/Dialog.tsx index 7d9855578..64300a8cd 100644 --- a/app/client-v2/packages/ui/components/Dialog.tsx +++ b/app/client-v2/packages/ui/components/Dialog.tsx @@ -35,14 +35,16 @@ const Dialog = memo( vertical: "top", horizontal: direction, }}> -
-
- {/* header */} - {title ? {title} : null} - - - -
+
+ {title ? ( +
+ {/* header */} + {title} + + + +
+ ) : null}
{/* header */} {children} diff --git a/app/client-v2/packages/ui/components/Icon/IconBase.ts b/app/client-v2/packages/ui/components/Icon/IconBase.ts deleted file mode 100644 index c28087e10..000000000 --- a/app/client-v2/packages/ui/components/Icon/IconBase.ts +++ /dev/null @@ -1,11 +0,0 @@ -import DescriptionIcon from "@mui/icons-material/Description"; -import HelpIcon from "@mui/icons-material/Help"; -import HomeIcon from "@mui/icons-material/Home"; - -import { createIcon } from "./Icon"; - -export const { Icon } = createIcon({ - help: HelpIcon, - home: HomeIcon, - file: DescriptionIcon, -}); diff --git a/app/client-v2/packages/ui/components/Icon/index.ts b/app/client-v2/packages/ui/components/Icon/index.ts deleted file mode 100644 index 62cbf816a..000000000 --- a/app/client-v2/packages/ui/components/Icon/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./Icon"; -export * from "./IconBase"; diff --git a/app/client-v2/packages/ui/components/SelectField.tsx b/app/client-v2/packages/ui/components/Inputs/SelectField.tsx similarity index 97% rename from app/client-v2/packages/ui/components/SelectField.tsx rename to app/client-v2/packages/ui/components/Inputs/SelectField.tsx index 2fae644a4..0c59694f7 100644 --- a/app/client-v2/packages/ui/components/SelectField.tsx +++ b/app/client-v2/packages/ui/components/Inputs/SelectField.tsx @@ -10,7 +10,7 @@ import * as React from "react"; import type { Equals } from "tsafe"; import { assert } from "tsafe/assert"; -import { makeStyles } from "../lib/ThemeProvider"; +import { makeStyles } from "../../lib/ThemeProvider"; export type SelectFieldProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Text/TextField.tsx b/app/client-v2/packages/ui/components/Inputs/TextField.tsx similarity index 96% rename from app/client-v2/packages/ui/components/Text/TextField.tsx rename to app/client-v2/packages/ui/components/Inputs/TextField.tsx index eac8a5a06..ec995296c 100644 --- a/app/client-v2/packages/ui/components/Text/TextField.tsx +++ b/app/client-v2/packages/ui/components/Inputs/TextField.tsx @@ -24,12 +24,10 @@ import { makeStyles } from "../../lib/ThemeProvider"; import { getBrowser } from "../../tools/getBrowser"; import { useNonPostableEvtLike } from "../../tools/useNonPostableEvtLike"; import { CircularProgress } from "../CircularProgress"; -import { createIcon } from "../Icon/Icon"; -import { createIconButton } from "../Icon/IconButton"; -import { Tooltip } from "../Tooltip"; +import { createIcon, createIconButton, Tooltip } from "../DataDisplay"; import type { IconId } from "../theme"; import { Icon as NormalIcon } from "../theme"; -import { Text } from "./TextBase"; +import { Text } from "../theme"; export type AttributeOption = string | { value: string; label: string }; export type AttributeOptions = AttributeOption[]; @@ -40,7 +38,10 @@ export type TextFieldProps = { name?: string; /** Default text */ type?: "text" | "password" | "email"; - size?: "small" | "medium"; + size?: "small" | "medium" | "verySmall"; + InputPropsClass?: { + className?: string; + }; /** Will overwrite value when updated */ defaultValue?: string; inputProps_ref?: RefObject; @@ -185,6 +186,7 @@ export const TextField = memo((props: TextFieldProps) => { name, selectAllTextOnFocus, isSubmitAllowed = true, + InputPropsClass, inputProps_ref, "inputProps_aria-label": inputProps_ariaLabel, inputProps_tabIndex, @@ -342,6 +344,7 @@ export const TextField = memo((props: TextFieldProps) => { const inputProps = useMemo( () => ({ + className: InputPropsClass?.className, ref: inputProps_ref, "aria-label": inputProps_ariaLabel, tabIndex: inputProps_tabIndex, @@ -398,7 +401,12 @@ export const TextField = memo((props: TextFieldProps) => { return ( { error={hasError} helperText={helperTextNode} InputProps={InputProps} - size={size} + size={size !== "verySmall" ? size : "medium"} onBlur={onMuiTextfieldBlur} onChange={onChange} placeholder={placeholder} diff --git a/app/client-v2/packages/ui/components/Inputs/index.ts b/app/client-v2/packages/ui/components/Inputs/index.ts new file mode 100644 index 000000000..5b4627ce2 --- /dev/null +++ b/app/client-v2/packages/ui/components/Inputs/index.ts @@ -0,0 +1,2 @@ +export * from "./SelectField"; +export * from "./TextField"; diff --git a/app/client-v2/packages/ui/components/Lists/ChipList.tsx b/app/client-v2/packages/ui/components/Lists/ChipList.tsx index 978401ee4..cb4694a49 100644 --- a/app/client-v2/packages/ui/components/Lists/ChipList.tsx +++ b/app/client-v2/packages/ui/components/Lists/ChipList.tsx @@ -2,7 +2,7 @@ import { Chip } from "@mui/material"; import { forwardRef, memo, useEffect, useRef } from "react"; import { makeStyles } from "../../lib/ThemeProvider"; -import { Text } from "../Text/TextBase"; +import { Text } from "../theme"; export type ChipListProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/DashboardSidebar.tsx b/app/client-v2/packages/ui/components/Navigation/DashboardSidebar.tsx similarity index 92% rename from app/client-v2/packages/ui/components/DashboardSidebar.tsx rename to app/client-v2/packages/ui/components/Navigation/DashboardSidebar.tsx index 31e2f81ed..905f6f866 100644 --- a/app/client-v2/packages/ui/components/DashboardSidebar.tsx +++ b/app/client-v2/packages/ui/components/Navigation/DashboardSidebar.tsx @@ -1,11 +1,11 @@ import { Fade, List, ListItem, ListItemButton, ListItemIcon } from "@mui/material"; import { useState } from "react"; -import { makeStyles } from "../lib/ThemeProvider"; -import { Icon } from "./theme"; -import type { IconId } from "./theme"; -import { Text } from "./theme"; -import { useTheme } from "./theme"; +import { makeStyles } from "../../lib/ThemeProvider"; +import { Icon } from "../theme"; +import type { IconId } from "../theme"; +import { Text } from "../theme"; +import { useTheme } from "../theme"; export type DashboardSidebarProps = { items: { link: string; icon: IconId; placeholder: string }[]; @@ -18,7 +18,6 @@ export function DashboardSidebar(props: DashboardSidebarProps) { const { items, children } = props; const { classes, cx } = useStyles(props)(); const theme = useTheme(); - console.log(theme); const [hover, setHover] = useState(false); const [active, setActive] = useState(items[0].placeholder); diff --git a/app/client-v2/packages/ui/components/Footer.tsx b/app/client-v2/packages/ui/components/Navigation/Footer.tsx similarity index 95% rename from app/client-v2/packages/ui/components/Footer.tsx rename to app/client-v2/packages/ui/components/Navigation/Footer.tsx index b261206df..b9fd12975 100644 --- a/app/client-v2/packages/ui/components/Footer.tsx +++ b/app/client-v2/packages/ui/components/Navigation/Footer.tsx @@ -1,9 +1,9 @@ import React, { forwardRef, memo } from "react"; -import { makeStyles } from "../lib/ThemeProvider"; -import P4BLogo from "./P4BLogo"; -import { Text, Icon } from "./theme"; -import type { IconId } from "./theme"; +import { makeStyles } from "../../lib/ThemeProvider"; +import P4BLogo from "../P4BLogo"; +import { Text, Icon } from "../theme"; +import type { IconId } from "../theme"; export type FooterProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Tabs.tsx b/app/client-v2/packages/ui/components/Navigation/Tabs.tsx similarity index 97% rename from app/client-v2/packages/ui/components/Tabs.tsx rename to app/client-v2/packages/ui/components/Navigation/Tabs.tsx index ef46fc085..267095754 100644 --- a/app/client-v2/packages/ui/components/Tabs.tsx +++ b/app/client-v2/packages/ui/components/Navigation/Tabs.tsx @@ -6,7 +6,7 @@ import React, { useState } from "react"; import type { Equals } from "tsafe"; import { assert } from "tsafe/assert"; -import { makeStyles } from "./../lib/ThemeProvider"; +import { makeStyles } from "../../lib/ThemeProvider"; export type SlideShowProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Navigation/ToggleTabs.tsx b/app/client-v2/packages/ui/components/Navigation/ToggleTabs.tsx new file mode 100644 index 000000000..31487f6a5 --- /dev/null +++ b/app/client-v2/packages/ui/components/Navigation/ToggleTabs.tsx @@ -0,0 +1,62 @@ +// Copyright (c) 2020 GitHub user u/garronej +import ToggleButton from "@mui/material/ToggleButton"; +import ToggleButtonGroup from "@mui/material/ToggleButtonGroup"; +import { forwardRef, memo } from "react"; +import React, { useState } from "react"; +import type { Equals } from "tsafe"; +import { assert } from "tsafe/assert"; + +import { makeStyles } from "../../lib/ThemeProvider"; +import { Icon } from "../theme"; +import type { IconId } from "../theme"; + +export type ToggleTabsProps = { + className?: string; + onResultChange: (value: string | null) => void; + defaultValue: string | null; + tabs: { + iconId: IconId; + value: string; + }[]; +}; + +export const ToggleTabs = memo( + forwardRef((props, ref) => { + const { + className, + tabs, + defaultValue, + onResultChange, + //For the forwarding, rest should be empty (typewise) + ...rest + } = props; + + //For the forwarding, rest should be empty (typewise), + // eslint-disable-next-line @typescript-eslint/ban-types + assert>(); + + const [value, setValue] = useState("1"); + + const handleChange = (event: React.SyntheticEvent, newValue: string) => { + onResultChange(newValue); + }; + + const { classes } = useStyles(); + + return ( + + {tabs.map((tab, index) => ( + + + + ))} + + ); + }) +); + +const useStyles = makeStyles({ name: { ToggleTabs } })((theme) => ({ + root: { + padding: theme.spacing(2), + }, +})); diff --git a/app/client-v2/packages/ui/components/Toolbar.tsx b/app/client-v2/packages/ui/components/Navigation/Toolbar.tsx similarity index 90% rename from app/client-v2/packages/ui/components/Toolbar.tsx rename to app/client-v2/packages/ui/components/Navigation/Toolbar.tsx index 1401727c1..f5cc33d4a 100644 --- a/app/client-v2/packages/ui/components/Toolbar.tsx +++ b/app/client-v2/packages/ui/components/Navigation/Toolbar.tsx @@ -1,8 +1,8 @@ import { Link, Stack } from "@mui/material"; -import { GOATLogoGreenSvg } from "../assets/svg/GOATLogoGreen"; -import { makeStyles } from "../lib/ThemeProvider"; -import { TextField } from "./Text/TextField"; +import { GOATLogoGreenSvg } from "../../assets/svg/GOATLogoGreen"; +import { makeStyles } from "../../lib/ThemeProvider"; +import { TextField } from "../Inputs/TextField"; export type ToolbarProps = { items: { link: string; icon: () => JSX.Element }[]; @@ -22,7 +22,6 @@ export function Toolbar(props: ToolbarProps) { placeholder="Search..." className={classes.searchInput} filled={true} - sx={{ paddingY: "6px" }} /> {items?.map(({ link, icon }, index) => ( @@ -56,6 +55,7 @@ const useStyles = (props: ToolbarProps) => height: "36px", }, searchInput: { + paddingY: "6px", width: "440px", border: "none", }, diff --git a/app/client-v2/packages/ui/components/Navigation/index.ts b/app/client-v2/packages/ui/components/Navigation/index.ts new file mode 100644 index 000000000..bffdb5c36 --- /dev/null +++ b/app/client-v2/packages/ui/components/Navigation/index.ts @@ -0,0 +1,5 @@ +export * from "./DashboardSidebar"; +export * from "./Footer"; +export * from "./Tabs"; +export * from "./ToggleTabs"; +export * from "./Toolbar"; diff --git a/app/client-v2/packages/ui/components/Banner.tsx b/app/client-v2/packages/ui/components/Surfaces/Banner.tsx similarity index 97% rename from app/client-v2/packages/ui/components/Banner.tsx rename to app/client-v2/packages/ui/components/Surfaces/Banner.tsx index 2f9435998..c83288472 100644 --- a/app/client-v2/packages/ui/components/Banner.tsx +++ b/app/client-v2/packages/ui/components/Surfaces/Banner.tsx @@ -1,7 +1,7 @@ import React, { forwardRef, memo } from "react"; -import { makeStyles } from "../lib/ThemeProvider"; -import { Card } from "./Card"; +import { Card } from "."; +import { makeStyles } from "../../lib/ThemeProvider"; export type BannerProps = { className?: string; diff --git a/app/client-v2/packages/ui/components/Card/Card.tsx b/app/client-v2/packages/ui/components/Surfaces/Card.tsx similarity index 99% rename from app/client-v2/packages/ui/components/Card/Card.tsx rename to app/client-v2/packages/ui/components/Surfaces/Card.tsx index 7d13ecc2b..6de5103ca 100644 --- a/app/client-v2/packages/ui/components/Card/Card.tsx +++ b/app/client-v2/packages/ui/components/Surfaces/Card.tsx @@ -90,7 +90,7 @@ export const Card = memo( const useStyles = makeStyles<{ noHoverEffect: boolean }>({ name: { Card } })((theme, { noHoverEffect }) => ({ root: { borderRadius: 4, - boxShadow: theme.shadows[1], + boxShadow: theme.shadows[8], backgroundColor: theme.colors.useCases.surfaces.surface1, "&:hover": { boxShadow: !noHoverEffect ? theme.shadows[6] : "", diff --git a/app/client-v2/packages/ui/components/Card/CardContent.tsx b/app/client-v2/packages/ui/components/Surfaces/CardContent.tsx similarity index 100% rename from app/client-v2/packages/ui/components/Card/CardContent.tsx rename to app/client-v2/packages/ui/components/Surfaces/CardContent.tsx diff --git a/app/client-v2/packages/ui/components/Card/CardMedia.tsx b/app/client-v2/packages/ui/components/Surfaces/CardMedia.tsx similarity index 100% rename from app/client-v2/packages/ui/components/Card/CardMedia.tsx rename to app/client-v2/packages/ui/components/Surfaces/CardMedia.tsx diff --git a/app/client-v2/packages/ui/components/Card/index.ts b/app/client-v2/packages/ui/components/Surfaces/index.ts similarity index 76% rename from app/client-v2/packages/ui/components/Card/index.ts rename to app/client-v2/packages/ui/components/Surfaces/index.ts index a83ac576e..04143249b 100644 --- a/app/client-v2/packages/ui/components/Card/index.ts +++ b/app/client-v2/packages/ui/components/Surfaces/index.ts @@ -1,3 +1,4 @@ export * from "./Card"; +export * from "./Banner"; export * from "./CardContent"; export * from "./CardMedia"; diff --git a/app/client-v2/packages/ui/components/Text/TextBase.ts b/app/client-v2/packages/ui/components/Text/TextBase.ts deleted file mode 100644 index 917bb9555..000000000 --- a/app/client-v2/packages/ui/components/Text/TextBase.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { useStyles } from "../../lib/ThemeProvider"; -import { createText } from "./Text"; - -function useTheme() { - const { theme } = useStyles(); - return theme; -} - -export const { Text } = createText({ useTheme }); diff --git a/app/client-v2/packages/ui/components/Text/index.ts b/app/client-v2/packages/ui/components/Text/index.ts deleted file mode 100644 index 22e10b675..000000000 --- a/app/client-v2/packages/ui/components/Text/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Text"; diff --git a/app/client-v2/packages/ui/components/temporary/DashboardLayout.tsx b/app/client-v2/packages/ui/components/temporary/DashboardLayout.tsx index b0ed63d88..88abed9d6 100644 --- a/app/client-v2/packages/ui/components/temporary/DashboardLayout.tsx +++ b/app/client-v2/packages/ui/components/temporary/DashboardLayout.tsx @@ -3,10 +3,10 @@ import ForwardIcon from "@mui/icons-material/Forward"; import React from "react"; import { makeStyles } from "../../lib/ThemeProvider"; -import { DashboardSidebar } from "../DashboardSidebar"; -import Footer from "../Footer"; -import { createIcon } from "../Icon"; -import { Toolbar } from "../Toolbar"; +import { createIcon } from "../DataDisplay"; +import { DashboardSidebar } from "../Navigation/DashboardSidebar"; +import Footer from "../Navigation/Footer"; +import { Toolbar } from "../Navigation/Toolbar"; import type { IconId } from "../theme"; interface DashboardLayoutProps { @@ -113,7 +113,9 @@ const DashboardLayout = ({ children }: DashboardLayoutProps) => { <> -
{children}
+
+
{children}
+