diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 4a0c3c4d..98aaeef9 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,11 +1,10 @@ import React, { useState } from "react"; -import SvgDisplay from "./SvgDisplay"; -import MemoryModelsUserInput from "./MemoryModelsUserInput"; +import { configDataPropTypes } from "./UserInput"; +import UserInput from "./UserInput"; +import Header from "./Header"; +import { Box } from "@mui/material"; import { ErrorBoundary } from "react-error-boundary"; -import DownloadSVGButton from "./DownloadSVGButton"; -import { Alert } from "@mui/material"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import MemoryModelsSample from "./MemoryModelsSample"; +import UserOutput from "./UserOutput"; export default function App() { const [textData, setTextData] = useState(""); @@ -34,44 +33,34 @@ export default function App() { return ( <> - {failureBanner && ( - - {failureBanner} - - )} - - -
-

Output

- - - This is valid JSON but not valid Memory Models JSON. - Please refer to the repo for more details. -

- } - key={jsonResult} - > - + + + + + + -
-
+ + ); } diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx deleted file mode 100644 index 8559dfdf..00000000 --- a/demo/src/AppTwo.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState } from "react"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import UserInput from "./UserInput"; -import Header from "./Header"; -import { Box } from "@mui/material"; -import { ErrorBoundary } from "react-error-boundary"; -import DownloadSVGButton from "./DownloadSVGButton"; -import SvgDisplay from "./SvgDisplay"; -import UserOutput from "./UserOutput"; - -export default function AppTwo() { - const [textData, setTextData] = useState(""); - const [configData, setConfigData] = useState({ - useAutomation: true, - overallDrawConfig: { - seed: 0, - }, - }); - const [jsonResult, setJsonResult] = useState(null); - const [svgResult, setSvgResult] = useState(null); - const [failureBanner, setFailureBanner] = useState(""); - - const onTextDataSubmit = (event?) => { - event?.preventDefault(); - try { - setJsonResult(JSON.parse(textData)); - setFailureBanner(""); - } catch (error) { - const errorMessage = `Error parsing inputted JSON: ${error.message}`; - console.error(errorMessage); - setFailureBanner(errorMessage); - setJsonResult(null); - } - }; - - return ( - <> -
- - - - - {/* Put your component here! (And feel free to get rid of the border) */} - - - - ); -} diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx deleted file mode 100644 index 838613a9..00000000 --- a/demo/src/DownloadJSONButton.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -import { Button } from "@mui/material"; - -type DownloadJSONButtonPropTypes = { - jsonResult: string; - sx: object; -}; -export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { - const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { - type: "application/JSON", - }); - - return ( - - ); -} diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx deleted file mode 100644 index 00cf0a96..00000000 --- a/demo/src/DownloadSVGButton.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { Button } from "@mui/material"; - -type DownloadSVGButtonPropTypes = { - svgResult: string; -}; -export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); - - return ( - - ); -} diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx deleted file mode 100644 index fe528583..00000000 --- a/demo/src/MemoryModelsSample.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Card, - CardContent, - Grid, -} from "@mui/material"; -import { ExpandMore } from "@mui/icons-material"; - -import { SAMPLES } from "./sample"; - -type MemoryModelsSamplePropTypes = { - setTextData: React.Dispatch>; - setConfigData: React.Dispatch>; - onTextDataSubmit: () => void; -}; - -export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { - const [clickedBtnIndex, setClickedBtnIndex] = useState(null); - - useEffect(() => { - if (clickedBtnIndex !== null) { - props.onTextDataSubmit(); - } - }, [clickedBtnIndex]); - - const handleButtonClick = (index: Number, sample: Object) => { - // Note: the following conversion to a string is inefficient, as the data is later parsed - // back into JSON for rendering. - // TODO: fix this. - props.setTextData(JSON.stringify(sample["data"], null, 4)); - props.setConfigData((prevConfigData) => ({ - ...prevConfigData, - ...sample["config"], - })); - setClickedBtnIndex(index); - }; - - return ( - - } - data-testid="sample-inputs-accordion" - > - Sample Inputs - - - - - - {SAMPLES.map((sample, index) => ( - - - - ))} - - - - - - ); -} diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx deleted file mode 100644 index 1f392135..00000000 --- a/demo/src/MemoryModelsUserInput.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React, { useState } from "react"; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Card, - CardContent, - Checkbox, - FormControlLabel, - Grid, - Input, - Stack, - TextField, - Tooltip, -} from "@mui/material"; -import DownloadJSONButton from "./DownloadJSONButton"; -import { ExpandMore } from "@mui/icons-material"; - -interface configDataPropTypes { - useAutomation: boolean; - overallDrawConfig: { - [key: string]: any; - }; -} - -type MemoryModelsConfigInputPropTypes = { - configData: configDataPropTypes; - setConfigData: React.Dispatch>; -}; - -type MemoryModelsFileInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; - setFailureBanner: React.Dispatch>; - jsonResult: string | null; -}; - -type MemoryModelsTextInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; -}; - -type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & - MemoryModelsTextInputPropTypes & - MemoryModelsConfigInputPropTypes & { - onTextDataSubmit: (event: React.MouseEvent) => void; - }; - -function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { - const [uploadedFileString, setUploadedFileString] = useState(""); - - const onChange = (event) => { - try { - const uploadedFile = event.target.files[0]; - const fileReader = new global.FileReader(); - fileReader.readAsText(uploadedFile, "UTF-8"); - fileReader.onload = (event) => { - const fileString = event.target.result as string; - setUploadedFileString(fileString); - props.setTextData(fileString); - }; - } catch (error) { - const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`; - console.error(errorMessage); - props.setTextData(null); - props.setFailureBanner(errorMessage); - } - }; - - const onLoadButtonClick = () => { - props.setTextData(uploadedFileString); - }; - - return ( - - - - - - - - ); -} - -function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { - const handleTextFieldChange = (event) => { - props.setTextData(event.target.value); - }; - - return ( - - - - ); -} - -//TODO: Retrieve min and max seeds from memory-viz -function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { - const handleSeedChange = (event) => { - event.preventDefault(); - props.setConfigData({ - ...props.configData, - overallDrawConfig: { - ...props.configData.overallDrawConfig, - seed: Number(event.target.value), - }, - }); - }; - - const handleAutomationChange = (event) => { - // Calling the common (among React event handlers) event.preventDefault() here - // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. - // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work - props.setConfigData({ - ...props.configData, - useAutomation: event.target.checked, - }); - }; - - return ( - - - - - } - label="Use automatic layout" - sx={{ width: "50%" }} - /> - - - ); -} - -export default function MemoryModelsUserInput( - props: MemoryModelsUserInputPropTypes -) { - return ( -
- - - - - - - } - data-testid="rendering-options-accordion" - > - Rendering Options - - - - - - - - - - - - - - - -
- ); -} - -export { MemoryModelsFileInput }; -export type { configDataPropTypes }; diff --git a/demo/src/UserInput.tsx b/demo/src/UserInput.tsx index cd7707dc..18410dfd 100644 --- a/demo/src/UserInput.tsx +++ b/demo/src/UserInput.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Box, Button, Link, Input, Typography, TextField } from "@mui/material"; import SampleInputMenu from "./SampleInputMenu"; -interface configDataPropTypes { +export interface configDataPropTypes { useAutomation: boolean; overallDrawConfig: { [key: string]: any; @@ -33,39 +33,6 @@ type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & }; export default function UserInput(props: MemoryModelsUserInputPropTypes) { - const classes = { - inputBox: { - display: "flex", - flexDirection: "column", - }, - title: { - fontWeight: "600", - mb: "1rem", - }, - button1: { - width: "auto", - textTransform: "none", - }, - fileInputBox: { - display: "flex", - justifyContent: "space-between", - }, - textField: { - height: "auto", - "& .MuiInputBase-input": { - fontFamily: "Consolas, monospace", - background: "none !important", - }, - }, - inputBottomBox: { - display: "flex", - justifyContent: "space-between", - }, - input: { - width: "50%", - }, - }; - const onChange = (event) => { try { const uploadedFile = event.target.files[0]; @@ -92,11 +59,22 @@ export default function UserInput(props: MemoryModelsUserInputPropTypes) { }; return ( - - + <> + Input - + - + Draw Diagram - + ); } diff --git a/demo/src/UserOutput.tsx b/demo/src/UserOutput.tsx index 3497b63e..a390a814 100644 --- a/demo/src/UserOutput.tsx +++ b/demo/src/UserOutput.tsx @@ -1,6 +1,6 @@ import React from "react"; import SvgDisplay from "./SvgDisplay"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; +import { configDataPropTypes } from "./UserInput"; import { Box, Typography, @@ -19,39 +19,6 @@ type OutputPropTypes = { }; export default function Output(props: OutputPropTypes) { - const classes = { - inputBox: { - display: "flex", - flexDirection: "column", - }, - title: { - fontWeight: "600", - mb: "1rem", - }, - button1: { - width: "auto", - textTransform: "none", - }, - fileInputBox: { - display: "flex", - justifyContent: "space-between", - }, - textField: { - height: "auto", - "& .MuiInputBase-input": { - fontFamily: "Consolas, monospace", - background: "none !important", - }, - }, - inputBottomBox: { - display: "flex", - justifyContent: "space-between", - }, - input: { - width: "50%", - }, - }; - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); const handleSeedChange = (event) => { @@ -76,13 +43,12 @@ export default function Output(props: OutputPropTypes) { return ( <> - + Output diff --git a/demo/src/index.tsx b/demo/src/index.tsx index 692f8af3..b3ec1e30 100644 --- a/demo/src/index.tsx +++ b/demo/src/index.tsx @@ -4,7 +4,6 @@ import App from "./App"; import "@picocss/pico"; import "./css/styles"; -import AppTwo from "./AppTwo"; import { ThemeProvider, createTheme } from "@mui/material/styles"; const theme = createTheme({ palette: { @@ -23,7 +22,7 @@ const root = createRoot(document.getElementById("root")); root.render( - + ); diff --git a/demo/src/output.tsx b/demo/src/output.tsx deleted file mode 100644 index f3a3eafe..00000000 --- a/demo/src/output.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, { useRef, useEffect, useState } from "react"; -import SvgDisplay from "./SvgDisplay"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import { - Box, - Typography, - Link, - Grid, - TextField, - FormControlLabel, - Checkbox, -} from "@mui/material"; - -type OutputPropTypes = { - jsonResult: object | null; - configData: configDataPropTypes; - setConfigData: React.Dispatch>; - setSvgResult: React.Dispatch>; - svgResult: string; -}; - -export default function Output(props: OutputPropTypes) { - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); - - const handleSeedChange = (event) => { - props.setConfigData({ - ...props.configData, - overallDrawConfig: { - ...props.configData.overallDrawConfig, - seed: Number(event.target.value), - }, - }); - }; - - const handleAutomationChange = (event) => { - // Calling the common (among React event handlers) event.preventDefault() here - // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. - // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work - props.setConfigData({ - ...props.configData, - useAutomation: event.target.checked, - }); - }; - - return ( - <> - -

Output

-
- - - - } - label="Use automatic layout" - sx={{ marginLeft: 15, marginTop: 6 }} - /> - - - - {"Download SVG"} - - - ); -}