Skip to content

Commit

Permalink
add Pagination/Menu wrapper (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
agoelzer authored Oct 18, 2024
1 parent 633d04e commit fad02f0
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 130 deletions.
4 changes: 2 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/roboto": "^5.0.13",
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
"@mui/icons-material": "^6.1.3",
"@mui/material": "^6.1.3",
"@popperjs/core": "^2.11.8",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
Expand Down
21 changes: 20 additions & 1 deletion ui/public/theme/base.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
/* (C) Copyright 2024 Dassault Systemes SE. All Rights Reserved. */
.ContainerSM {
.NuoContainerSM {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.NuoBanner {
width: 100%;
padding-left: 24px;
padding-right: 24px;
background-color: rgb(25, 118, 210);
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px -1px, rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px;
color: white;
position: static;
}

.NuoBannerItems {
flex: 1 0 auto;
display: flex;
}

.NuoBannerSettings {
flex: 0 0 auto;
display: flex;
}
3 changes: 3 additions & 0 deletions ui/public/theme/material.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* (C) Copyright 2024 Dassault Systemes SE. All Rights Reserved. */
.BannerItem {
color: white !important;
}
.NuoBannerMenu>button {
color: white !important;
}
75 changes: 66 additions & 9 deletions ui/public/theme/plain.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
/* (C) Copyright 2024 Dassault Systemes SE. All Rights Reserved. */
.FieldError {
.NuoFieldError {
color: red;
}
.FieldString,
.FieldSelect {
.NuoFieldString,
.NuoFieldSelect {
position: relative;
border: 1px solid;
margin: 5px;
}

.FieldString>label,
.FieldSelect>label {
.NuoFieldString>label,
.NuoFieldSelect>label {
position: absolute;
top: -15px;
left: 10px;
background-color: white;
font-size: 1rem;
}

.FieldString>input,
.FieldSelect>select {
.NuoFieldString>input,
.NuoFieldSelect>select {
border: none;
padding: 10px;
left: 0px;
width: 100%;
}
.BannerItem {
.NuoBannerMenu {
flex-direction: row;
display: flex;
}

.NuoBannerItem,
.NuoBannerMenu>button {
cursor: pointer;
background-color: transparent;
font-family: Roboto, Helvetica, Arial, sans-serif;
Expand All @@ -41,4 +46,56 @@
margin: 16px 0px;
text-decoration: none;
padding: 6px 8px;
}
.NuoPagination {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}

.NuoPaginationItem {
padding: 5px;
border-radius: 10px;
cursor: pointer;
}

.NuoPaginationItemSelected {
background-color: rgba(0, 0, 0, 0.08);
}

.NuoMenuPopup {
list-style: none;
margin: 5px;
padding: 8px 0px;
position: absolute;
outline: 0px;
color: black;
background-color: white;
}

.NuoAlignRight {
left: auto;
right: 0;
}

.NuoAlignLeft {
left: 0;
right: auto;
}

.NuoMenuPopupItem {
margin: 0px;
padding: 5px;
font-family: Roboto, Helvetica, Arial, sans-serif;
font-weight: 400;
font-size: 1rem;
line-height: 1.5;
letter-spacing: 0.00938em;
text-align: center;
cursor: pointer;
}

.NuoMenuPopupItem:hover {
background-color: lightgray;
}
84 changes: 84 additions & 0 deletions ui/src/components/controls/Menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// (C) Copyright 2024 Dassault Systemes SE. All Rights Reserved.

import { ReactNode, useState } from 'react';
import { isMaterial } from '../../utils/Customizations';
import { Menu as MuiMenu } from '@mui/material';
import MenuItem from '@mui/material/MenuItem';
import Button from './Button';

type MenuItemProps = {
id: string,
label: string,
onClick: () => void
}

type MenuItemsProps = MenuItemProps[];

type MenuProps = {
"data-testid"?: string,
align?: "left" | "right",
children?: ReactNode,
items: MenuItemsProps,
className?: string
};

export default function Menu(props: MenuProps): JSX.Element {
const { align, children, items, className } = props;
const [anchor, setAnchor] = useState<Element | null>(null);

function popupMenu(items: MenuItemsProps) {
if (isMaterial()) {
return <MuiMenu
sx={{ mt: '5px' }}
id="menu-appbar"
anchorEl={anchor}
anchorOrigin={{
vertical: 'bottom',
horizontal: align || 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: align || 'right',
}}
open={Boolean(anchor)}
onClose={() => setAnchor(null)}
>
{items.map(item => <MenuItem key={item.id} data-testid={item.id} onClick={() => {
setAnchor(null);
item.onClick();
}}>{item.label}</MenuItem>)}
</MuiMenu>;
}
const rect = anchor?.getBoundingClientRect();
const x = align === "right" ? rect?.right : rect?.left;
return <div style={{ display: anchor ? "block" : "none", position: "fixed", right: 0, left: 0, top: 0, bottom: 0, backgroundColor: "transparent" }} onClick={() => setAnchor(null)}>
<div style={{ position: "absolute", right: x, left: x, top: rect?.bottom, bottom: rect?.bottom }}>
<ul id="NuoMenuPopup" className={"NuoMenuPopup " + (align === "right" ? " NuoAlignRight" : " NuoAlignLeft")}>
{items.map(item => <li key={item.id} className="NuoMenuPopupItem" onClick={() => item.onClick()}>{item.label}</li>)}
</ul></div>
</div>;
}

function listMenu(items: MenuItemsProps) {
return items.map((item, index) => <Button
data-testid={item.id}
key={item.id}
onClick={item.onClick}
>
{item.label}
</Button>);
}

if (children) {
return <>
<div className="NuoMenuToggle" onClick={(event) => {
setAnchor(event.currentTarget)
}}><>{children}</></div>
{popupMenu(items)}
</>;
}
else {
return <div className={className}>{listMenu(items)}</div>;
}
}
48 changes: 48 additions & 0 deletions ui/src/components/controls/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// (C) Copyright 2024 Dassault Systemes SE. All Rights Reserved.

import { isMaterial } from '../../utils/Customizations';
import { Pagination as MuiPagination, Stack as MuiStack } from '@mui/material';

export type PaginationProps = {
"data-testid"?: string,
count: number,
page: number,
setPage: (page: number) => void
}
export default function Pagination(props: PaginationProps): JSX.Element | null {
const { count, page, setPage } = props;

if (count === 0) {
return null;
}

if (isMaterial()) {
return <MuiStack spacing={2} style={{ alignItems: "center" }}>
<MuiPagination count={count} page={page} onChange={(event, page) => {
props.setPage(page);
}} />
</MuiStack>
}
else {
return <div className="NuoPagination">
<div className="NuoPaginationItem NuoPaginationItemFirst" onClick={() => setPage(1)}>&lt;</div>
{Array(count).fill(1).map((_, index) => {
let className = "NuoPaginationItem";
if (page === index + 1) {
className += " NuoPaginationItemSelected";
}
if (page === 1) {
className += " NuoPaginationItemFirst";
}
if (page === count) {
className += " NuoPaginationItemLast";
}

return <div key={index} className={className} onClick={() => {
setPage(index + 1)
}}>{index + 1}</div>
})}
<div className="NuoPaginationItem NuoPaginationItemLast" onClick={() => setPage(count)}>&gt;</div>
</div>;
}
}
2 changes: 1 addition & 1 deletion ui/src/components/controls/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function Select(props: SelectProps): JSX.Element {
</FormControl >;
}
else {
return <div className="FieldBase FieldSelect" key={id}>
return <div className="NuoFieldBase NuoFieldSelect" key={id}>
<label id={"label_" + id}>{id}</label>
<select name={id} {...props}>
{children}
Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/controls/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export default function TextField(props: TextFieldProps): JSX.Element {
}
else {
return <div>
<div className="FieldBase FieldString" key={props.id}>
<div className="NuoFieldBase NuoFieldString" key={props.id}>
<label>{props.id}</label>
<input name={props.id} {...props} />
</div>
{props.error !== "" && <div className="FieldError">{props.error}</div>}
{props.error !== "" && <div className="NuoFieldError">{props.error}</div>}
</div>
}
}
12 changes: 3 additions & 9 deletions ui/src/components/pages/ListResource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import Table from "./parts/Table";
import { getResourceEvents, getCreatePath, getResourceByPath, getFilterField } from "../../utils/schema";
import RestSpinner from "./parts/RestSpinner";
import Button from "../controls/Button";
import Pagination from '@mui/material/Pagination';
import Stack from '@mui/material/Stack';
import Path, { parseSearch } from './parts/Path'
import Auth from "../../utils/auth"
import { SchemaType, TempAny } from "../../utils/types";
import Pagination from "../controls/Pagination";

/**
* handles all the /resource/list/* requests to list a resource
Expand Down Expand Up @@ -96,14 +95,9 @@ export default function ListResource({ schema }: SchemaType) {

function renderPaging() {
const lastPage = Math.ceil(allItems.length / pageSize);
if (lastPage <= 1) {
return null;
}
return <Stack spacing={2} style={{ alignItems: "center" }}>
<Pagination count={lastPage} page={page} onChange={(event, page) => {
return <Pagination count={lastPage} page={page} setPage={(page) => {
setPage(page);
}} />
</Stack>;
}} />;
}

function getFilterValues() {
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/pages/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function LoginForm({ setIsLoggedIn }: Props) {

return (
<React.Fragment>
<div className="ContainerSM">
<div className="NuoContainerSM">
<h3>NuoDB Login</h3>
<form>
<div className="fields">
Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default function Settings() {
type: "select",
enums: [
{ key: "material", label: "Material UI" },
{ key: "plain", label: "plain" },
{ key: "plain", label: "plain" }
]
}

Expand All @@ -71,7 +71,7 @@ export default function Settings() {
}

return (
<div className="ContainerSM">
<div className="NuoContainerSM">
<h1>Settings</h1>
{advanced ? renderAdvanced() : renderBasic()}
<div style={{ color: "red" }}>{error}</div>
Expand Down
Loading

0 comments on commit fad02f0

Please sign in to comment.