Add Material UI demo (#173)

Adds working example with Material UI
This commit is contained in:
h-contributeur
2023-03-10 21:01:46 +01:00
committed by GitHub
parent 7fd979aed8
commit f9a1d02588
11 changed files with 1032 additions and 138 deletions
+793 -138
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -34,6 +34,9 @@
"npm": ">=6.0.0" "npm": ">=6.0.0"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@mui/material": "^5.11.11",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.4.0", "react-bootstrap": "^2.4.0",
@@ -0,0 +1,66 @@
import React, { useState, ChangeEvent, FormEvent } from 'react';
import { Button, Grid, TextField, Typography } from '@mui/material';
interface FormInputProps {
submitNewSheet: (sheetName: string) => {
name: string;
index: number;
isActive: boolean;
};
}
const FormInput = ({ submitNewSheet }: FormInputProps) => {
const [newSheetName, setNewSheetName] = useState('');
const handleChange = (event: ChangeEvent<HTMLInputElement>) =>
setNewSheetName(event.target.value);
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (newSheetName.length === 0) return;
submitNewSheet(newSheetName);
setNewSheetName('');
};
return (
<form
onSubmit={handleSubmit}
>
<Grid container spacing={2}>
<Grid item xs={10}>
<TextField
id="sheet-name"
label="New Sheet Name"
variant="outlined"
value={newSheetName}
onChange={handleChange}
name="newSheetName"
fullWidth
size="small"
/>
</Grid>
<Grid
item
xs={2}
container
direction="row"
justifyContent="center"
alignItems="center"
>
<Button variant="contained" type="submit">
Submit
</Button>
</Grid>
</Grid>
<Typography variant="caption" gutterBottom>
Enter the name for your new sheet.
</Typography>
<br />
<Typography variant="caption" gutterBottom sx={{ fontStyle: 'italic' }}>
This component is written in typescript!
</Typography>
</form>
);
};
export default FormInput;
@@ -0,0 +1,70 @@
import React, { useState, useEffect } from 'react';
import { Button, Typography } from '@mui/material';
import FormInput from './FormInput';
import SheetTable from './SheetTable';
// This is a wrapper for google.script.run that lets us use promises.
import { serverFunctions } from '../../utils/serverFunctions';
const SheetEditor = () => {
const [names, setNames] = useState([]);
useEffect(() => {
serverFunctions.getSheetsData().then(setNames).catch(alert);
}, []);
const deleteSheet = (sheetIndex) => {
serverFunctions.deleteSheet(sheetIndex).then(setNames).catch(alert);
};
const setActiveSheet = (sheetName) => {
serverFunctions.setActiveSheet(sheetName).then(setNames).catch(alert);
};
const submitNewSheet = async (newSheetName) => {
try {
const response = await serverFunctions.addSheet(newSheetName);
setNames(response);
} catch (error) {
// eslint-disable-next-line no-alert
alert(error);
}
};
return (
<div style={{ padding: '3px', overflowX: 'hidden' }}>
<Typography variant="h4" gutterBottom>
☀️ MUI demo! ☀️
</Typography>
<Typography variant="body1" gutterBottom sx={{ marginBottom: '30px' }}>
This is a sample app that uses the <code>mui</code> library
to help us build a simple React app. Enter a name for a new sheet, hit
enter and the new sheet will be created. Click the red button next to the sheet name to
delete it.
</Typography>
<FormInput submitNewSheet={submitNewSheet} />
{names.length > 0 &&
<SheetTable rows={names.map((name) => {
return {
sheetName: name.name,
goToButton: <Button
variant="outlined"
disabled={name?.isActive}
onClick={() => setActiveSheet(name.name)}
>Go To Sheet</Button>,
deleteButton: <Button
variant="contained"
color="error"
onClick={() => deleteSheet(name.index)}
>Delete</Button>
}
})} />}
</div>
);
};
export default SheetEditor;
@@ -0,0 +1,38 @@
import * as React from 'react';
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
type sheetRow = {
sheetName: string;
goToButton: React.ReactNode;
deleteButton: React.ReactNode;
};
export default function SheetTable({ rows }: { rows: Array<sheetRow> }) {
return (
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Sheet Name</TableCell>
<TableCell align="center">Go To</TableCell>
<TableCell align="center">Delete</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row: sheetRow) => (
<TableRow
key={row.sheetName}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component="th" scope="row">
{row.sheetName}
</TableCell>
<TableCell align="center">{row.goToButton}</TableCell>
<TableCell align="center">{row.deleteButton}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<base target="_top" />
<!-- Add any external scripts and stylesheets here -->
</head>
<body>
<section id="index">
<!-- bundled js and css will get inlined here during build-->
</section>
</body>
</html>
+7
View File
@@ -0,0 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import SheetEditor from './components/SheetEditor';
import './styles.css';
ReactDOM.render(<SheetEditor />, document.getElementById('index'));
+4
View File
@@ -0,0 +1,4 @@
/* needed to make consistent test snapshots across OSs */
body {
font-family: Arial !important;
}
+2
View File
@@ -2,6 +2,7 @@ import {
onOpen, onOpen,
openDialog, openDialog,
openDialogBootstrap, openDialogBootstrap,
openDialogMUI,
openDialogTailwindCSS, openDialogTailwindCSS,
openAboutSidebar, openAboutSidebar,
} from './ui'; } from './ui';
@@ -13,6 +14,7 @@ export {
onOpen, onOpen,
openDialog, openDialog,
openDialogBootstrap, openDialogBootstrap,
openDialogMUI,
openDialogTailwindCSS, openDialogTailwindCSS,
openAboutSidebar, openAboutSidebar,
getSheetsData, getSheetsData,
+8
View File
@@ -3,6 +3,7 @@ export const onOpen = () => {
.createMenu('My Sample React Project') // edit me! .createMenu('My Sample React Project') // edit me!
.addItem('Sheet Editor', 'openDialog') .addItem('Sheet Editor', 'openDialog')
.addItem('Sheet Editor (Bootstrap)', 'openDialogBootstrap') .addItem('Sheet Editor (Bootstrap)', 'openDialogBootstrap')
.addItem('Sheet Editor (MUI)', 'openDialogMUI')
.addItem('Sheet Editor (Tailwind CSS)', 'openDialogTailwindCSS') .addItem('Sheet Editor (Tailwind CSS)', 'openDialogTailwindCSS')
.addItem('About me', 'openAboutSidebar'); .addItem('About me', 'openAboutSidebar');
@@ -23,6 +24,13 @@ export const openDialogBootstrap = () => {
SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor (Bootstrap)'); SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor (Bootstrap)');
}; };
export const openDialogMUI = () => {
const html = HtmlService.createHtmlOutputFromFile('dialog-demo-mui')
.setWidth(600)
.setHeight(600);
SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor (MUI)');
};
export const openDialogTailwindCSS = () => { export const openDialogTailwindCSS = () => {
const html = HtmlService.createHtmlOutputFromFile('dialog-demo-tailwindcss') const html = HtmlService.createHtmlOutputFromFile('dialog-demo-tailwindcss')
.setWidth(600) .setWidth(600)
+29
View File
@@ -58,6 +58,12 @@ const clientEntrypoints = [
filename: 'dialog-demo-bootstrap', filename: 'dialog-demo-bootstrap',
template: './src/client/dialog-demo-bootstrap/index.html', template: './src/client/dialog-demo-bootstrap/index.html',
}, },
{
name: 'CLIENT - Dialog Demo MUI',
entry: './src/client/dialog-demo-mui/index.js',
filename: 'dialog-demo-mui',
template: './src/client/dialog-demo-mui/index.html',
},
{ {
name: 'CLIENT - Dialog Demo Tailwind CSS', name: 'CLIENT - Dialog Demo Tailwind CSS',
entry: './src/client/dialog-demo-tailwindcss/index.js', entry: './src/client/dialog-demo-tailwindcss/index.js',
@@ -209,6 +215,29 @@ const DynamicCdnWebpackPluginConfig = {
version: packageVersion, version: packageVersion,
url: `https://unpkg.com/react-bootstrap@${packageVersion}/dist/react-bootstrap${packageSuffix}`, url: `https://unpkg.com/react-bootstrap@${packageVersion}/dist/react-bootstrap${packageSuffix}`,
}; };
case '@mui/material':
return {
name: packageName,
var: 'MaterialUI',
version: packageVersion,
url: `https://unpkg.com/@mui/material@${packageVersion}/umd/material-ui.${
isProd ? 'production.min.js' : 'development.js'
}`,
};
case '@emotion/react':
return {
name: packageName,
var: 'emotionReact',
version: packageVersion,
url: `https://unpkg.com/@emotion/react@${packageVersion}/dist/emotion-react.umd.min.js`,
};
case '@emotion/styled':
return {
name: packageName,
var: 'emotionStyled',
version: packageVersion,
url: `https://unpkg.com/@emotion/styled@${packageVersion}/dist/emotion-styled.umd.min.js`,
};
// externalize gas-client to keep bundle size even smaller // externalize gas-client to keep bundle size even smaller
case 'gas-client': case 'gas-client':
return { return {