Skip to content

Commit

Permalink
Merge pull request #121 from codytodonnell/main
Browse files Browse the repository at this point in the history
Update cookiecutter and other comments
  • Loading branch information
codytodonnell authored Sep 9, 2024
2 parents 86632e4 + 706254d commit f0c6bc1
Show file tree
Hide file tree
Showing 66 changed files with 1,795 additions and 1,211 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# Test taskflow configs
_*.config.ts
18 changes: 0 additions & 18 deletions strudel-cookiecutter/base/{@cookiecutter.name@}/.eslintrc.cjs

This file was deleted.

2 changes: 0 additions & 2 deletions strudel-cookiecutter/base/{@cookiecutter.name@}/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
:warning: ***This library is in early-stage development. Check back soon for more updates!***

# STRUDEL Kit

STRUDEL Kit is a React-based JavaScript library for building scientific UIs based on the STRUDEL Design System and Task Flows. Visit [strudel.science](https://strudel.science) for more information about the STRUDEL project.
Expand Down
2 changes: 1 addition & 1 deletion strudel-cookiecutter/base/{@cookiecutter.name@}/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon-32x32.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>STRUDEL + React + MUI</title>
<title></title>
</head>
<body>
<div id="root"></div>
Expand Down
9 changes: 8 additions & 1 deletion strudel-cookiecutter/base/{@cookiecutter.name@}/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"private": true,
"version": "0.0.0",
"type": "module",
"homepage": "https://codytodonnell.github.io/strudel-kit/demo/",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"deploy": "gh-pages -d dist -e demo"
},
"dependencies": {
"@emotion/react": "^11.11.4",
Expand All @@ -19,6 +21,7 @@
"@mui/material": "^5.15.14",
"@mui/x-data-grid": "^7.0.0",
"@mui/x-date-pickers": "^7.0.0",
"@tanstack/react-query": "^5.51.23",
"d3-fetch": "^3.0.1",
"dayjs": "^1.11.10",
"plotly.js": "^2.30.1",
Expand All @@ -29,6 +32,7 @@
},
"devDependencies": {
"@types/d3-fetch": "^3.0.7",
"@types/node": "^20.12.12",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react-plotly.js": "^2.6.3",
Expand All @@ -38,6 +42,9 @@
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"gh-pages": "^6.1.1",
"typedoc": "^0.25.13",
"typedoc-plugin-markdown": "^4.0.0",
"typescript": "^5.2.2",
"vite": "^5.2.10"
},
Expand Down
34 changes: 24 additions & 10 deletions strudel-cookiecutter/base/{@cookiecutter.name@}/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { CssBaseline } from '@mui/material';
import { LocalizationProvider } from '@mui/x-date-pickers';
Expand All @@ -8,18 +8,32 @@ import { theme } from './theme';
import { AppProvider } from './context/ContextProvider';
import { ApiModal } from './components/ApiModal';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import { config } from '../strudel.config';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient()

const App: React.FC = () => {

/**
* Set the html title for the app using the title in the config.
*/
useEffect(() => {
document.title = config.title;
}, []);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ThemeProvider theme={theme}>
<CssBaseline />
<AppProvider>
<RouterProvider router={createBrowserRouter(routes)} />
<ApiModal />
</AppProvider>
</ThemeProvider>
</LocalizationProvider>
<QueryClientProvider client={queryClient}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ThemeProvider theme={theme}>
<CssBaseline />
<AppProvider>
<RouterProvider router={createBrowserRouter(routes, { basename: import.meta.env.VITE_BASE_URL })} />
<ApiModal />
</AppProvider>
</ThemeProvider>
</LocalizationProvider>
</QueryClientProvider>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Box, Stack, Chip, Popover, Grid } from "@mui/material";
import { useState } from "react";

interface ArrayWithPopoverProps {
values: string[] | number[]
}

/**
* Array of Chips with a popover to show the full list.
* This is used to render arrays in table cells where the
* list is cut off by the edge of the cell.
*/
export const ArrayWithPopover: React.FC<ArrayWithPopoverProps> = ({ values }) => {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

const handlePopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

const handlePopoverClose = () => {
setAnchorEl(null);
};

const open = Boolean(anchorEl);
return (
<Box
sx={{ height: '100%' }}
>
<Stack
direction="row"
spacing={1}
alignItems="center"
onMouseEnter={handlePopoverOpen}
onMouseLeave={handlePopoverClose}
sx={{ height: '100%' }}
>
{values.map((v) => (
<Chip key={v} label={v} size="small" />
))}
</Stack>
<Popover
id="mouse-over-popover"
sx={{
pointerEvents: 'none',
}}
open={open}
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
onClose={handlePopoverClose}
disableRestoreFocus
>
<Grid
container
rowGap={1}
columnGap={1}
sx={{
maxWidth: '300px',
padding: 2,
}}
>
{values.map((v) => (
<Grid key={v} item>
<Chip label={v} size="small" />
</Grid>
))}
</Grid>
</Popover>
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Box, Popover } from "@mui/material";
import { PropsWithChildren, useState } from "react";

/**
* Generic inner cell content with a popover to show the full contents.
* This is used to render cells with too much content to display
* inside a single cell. Full content is displayed on hover in a popover box.
*/
export const CellWithPopover: React.FC<PropsWithChildren> = ({ children }) => {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

const handlePopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

const handlePopoverClose = () => {
setAnchorEl(null);
};

const open = Boolean(anchorEl);
return (
<Box
sx={{ height: '100%' }}
>
<Box
onMouseEnter={handlePopoverOpen}
onMouseLeave={handlePopoverClose}
sx={{
height: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{children}
</Box>
<Popover
id="mouse-over-popover"
sx={{
pointerEvents: 'none',
}}
open={open}
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
onClose={handlePopoverClose}
disableRestoreFocus
>
<Box
sx={{
maxWidth: '300px',
padding: 2,
}}
>
{children}
</Box>
</Popover>
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -1,58 +1,73 @@
import React, { ReactNode, useEffect, useState } from 'react';
import { Box, Button, Checkbox, FormControlLabel, FormGroup, FormGroupProps, FormLabel, IconButton, Paper, PaperProps, Stack, TextField, TextFieldProps, Typography } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { Checkbox, FormControlLabel, FormGroup, FormGroupProps } from '@mui/material';
import React, { useEffect, useState } from 'react';

type CheckboxOptionValue = string | number;
export type CheckboxOptionValue = string | number;

export interface CheckboxOption {
label: string;
value: CheckboxOptionValue;
}

interface CheckboxListProps extends Omit<FormGroupProps, 'onChange'> {
values: CheckboxOptionValue[] | null;
options: CheckboxOption[];
onChange?: (values: CheckboxOptionValue[] | null) => any;
}

export const CheckboxList: React.FC<CheckboxListProps> = ({
options = [],
onChange,
values,
sx,
...rest
}) => {
const [values, setValues] = useState<CheckboxOptionValue[] | null>(null);
const [checkValues, setCheckValues] = useState<CheckboxOptionValue[] | null>(values);

const handleChange = (checked: boolean, value: CheckboxOption['value']) => {
if (values === null && checked) {
setValues([value]);
} else if (values !== null && checked) {
setValues([...values, value]);
} else if (values !== null && !checked) {
const newValues = values.filter((v) => v !== value);
if (checkValues === null && checked) {
setCheckValues([value]);
} else if (checkValues !== null && checked) {
setCheckValues([...checkValues, value]);
} else if (checkValues !== null && !checked) {
const newValues = checkValues.filter((v) => v !== value);
if (newValues.length > 0) {
setValues(newValues);
setCheckValues(newValues);
} else {
setValues(null);
setCheckValues(null);
}
}
};

useEffect(() => {
if (onChange) onChange(values);
if (onChange && checkValues?.length !== values?.length) {
onChange(checkValues);
}
}, [checkValues]);

useEffect(() => {
setCheckValues(values);
}, [values]);

return (
<FormGroup {...rest}>
<FormGroup
sx={{
display: 'inline-flex',
...sx
}}
{...rest}
>
{options.map((option, i) => (
<FormControlLabel
key={`${option}-${i}`}
label={option.label}
control={
<Checkbox
<Checkbox
checked={!!checkValues && checkValues.indexOf(option.value) > -1}
value={option.value}
onChange={(e, checked) => handleChange(checked, option.value)}
sx={{
pr: 1,
pl: 0,
pl: 1,
pb: 0,
pt: 0
}}
Expand Down
Loading

0 comments on commit f0c6bc1

Please sign in to comment.