From d9712907ed5705c86f16e2bfa51306e14505c346 Mon Sep 17 00:00:00 2001
From: yoonieaj <144498960+yoonieaj@users.noreply.github.com>
Date: Mon, 19 Aug 2024 08:04:54 -0400
Subject: [PATCH] Improve website layout (#69)
* Adopt horizontal layout
* Display MemoryViz logo
* Change sample input and rendering options sections into dropdown menus
---
CHANGELOG.md | 2 +
demo/jest.config.ts | 3 +
demo/src/App.tsx | 70 +++---
demo/src/DownloadJSONButton.tsx | 7 +-
demo/src/DownloadSVGButton.tsx | 4 +-
demo/src/Header.tsx | 42 ++++
demo/src/MemoryModelsMenu.tsx | 37 +++
demo/src/MemoryModelsSample.tsx | 58 ++---
demo/src/MemoryModelsUserInput.tsx | 218 ++++++++----------
demo/src/SvgDisplay.tsx | 23 +-
.../src/__tests__/DownloadJSONButton.spec.tsx | 2 +-
demo/src/__tests__/DownloadSVGButton.spec.tsx | 2 +-
.../src/__tests__/MemoryModelsSample.spec.tsx | 20 +-
.../__tests__/MemoryModelsUserInput.spec.tsx | 7 +-
demo/src/css/styles.css | 14 ++
demo/src/declarations.d.ts | 5 +
demo/src/html/index.html | 17 +-
demo/src/index.tsx | 17 +-
demo/src/mocks/fileMock.js | 2 +
demo/webpack.common.js | 4 +
20 files changed, 318 insertions(+), 236 deletions(-)
create mode 100644 demo/src/Header.tsx
create mode 100644 demo/src/MemoryModelsMenu.tsx
create mode 100644 demo/src/declarations.d.ts
create mode 100644 demo/src/mocks/fileMock.js
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81e3e745..775e2e5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,8 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### 📚 Documentation and demo website changes
+- Reformatted demo website to horizontal layout.
+
### 🔧 Internal changes
## [0.3.0] - 2024-08-02
diff --git a/demo/jest.config.ts b/demo/jest.config.ts
index 2b313f7c..76676a39 100644
--- a/demo/jest.config.ts
+++ b/demo/jest.config.ts
@@ -93,6 +93,9 @@ const config: Config = {
// Force module roughjs to resolve with the CJS entry point, because Jest does not support package.json.exports. Elaborated in PR#15.
roughjs: require.resolve("roughjs"),
"memory-viz": require.resolve("../memory-viz/src"),
+ // Mocks a file (see fileMock.js) each time any of the below file types are imported.
+ "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css|less|sass|scss)$":
+ "./mocks/fileMock.js",
},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
diff --git a/demo/src/App.tsx b/demo/src/App.tsx
index 4a0c3c4d..ac85dca4 100644
--- a/demo/src/App.tsx
+++ b/demo/src/App.tsx
@@ -1,11 +1,12 @@
import React, { useState } from "react";
+import { Box, Stack } from "@mui/material";
import SvgDisplay from "./SvgDisplay";
import MemoryModelsUserInput from "./MemoryModelsUserInput";
import { ErrorBoundary } from "react-error-boundary";
import DownloadSVGButton from "./DownloadSVGButton";
import { Alert } from "@mui/material";
import { configDataPropTypes } from "./MemoryModelsUserInput";
-import MemoryModelsSample from "./MemoryModelsSample";
+import Header from "./Header";
export default function App() {
const [textData, setTextData] = useState("");
@@ -33,45 +34,46 @@ 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}
- >
-
+
+ Input
+
-
-
- >
+
+
+ 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/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx
index 838613a9..bbbfd8bf 100644
--- a/demo/src/DownloadJSONButton.tsx
+++ b/demo/src/DownloadJSONButton.tsx
@@ -3,7 +3,6 @@ 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)], {
@@ -12,7 +11,7 @@ export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) {
return (
);
}
diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx
index 00cf0a96..2ca8ba0d 100644
--- a/demo/src/DownloadSVGButton.tsx
+++ b/demo/src/DownloadSVGButton.tsx
@@ -9,8 +9,8 @@ export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) {
return (
);
}
diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx
new file mode 100644
index 00000000..36f96777
--- /dev/null
+++ b/demo/src/Header.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import { Box, Link, Stack, Typography } from "@mui/material";
+import image from "../../assets/logo_square.png";
+
+export default function Header() {
+ return (
+
+
+
+ MemoryViz Demo
+
+ Demos of the{" "}
+
+ MemoryViz
+ {" "}
+ Javascript library for visualizing Python memory. Click{" "}
+
+ here
+ {" "}
+ for documentation.
+
+
+
+
+
+ );
+}
diff --git a/demo/src/MemoryModelsMenu.tsx b/demo/src/MemoryModelsMenu.tsx
new file mode 100644
index 00000000..26d03c4b
--- /dev/null
+++ b/demo/src/MemoryModelsMenu.tsx
@@ -0,0 +1,37 @@
+import React, { ReactNode, useState } from "react";
+import { Box, Button, Menu } from "@mui/material";
+import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded";
+import "./css/styles.css";
+
+type MemoryModelsMenuPropTypes = {
+ menuName: string;
+ testId: string;
+ menuItems: ReactNode;
+};
+
+export default function MemoryModelsMenu(props: MemoryModelsMenuPropTypes) {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx
index fe528583..04a89ff8 100644
--- a/demo/src/MemoryModelsSample.tsx
+++ b/demo/src/MemoryModelsSample.tsx
@@ -1,14 +1,6 @@
import React, { useEffect, useState } from "react";
-import {
- Accordion,
- AccordionDetails,
- AccordionSummary,
- Button,
- Card,
- CardContent,
- Grid,
-} from "@mui/material";
-import { ExpandMore } from "@mui/icons-material";
+import { Box, MenuItem } from "@mui/material";
+import MemoryModelsMenu from "./MemoryModelsMenu";
import { SAMPLES } from "./sample";
@@ -40,39 +32,17 @@ export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) {
};
return (
-
- }
- data-testid="sample-inputs-accordion"
- >
- Sample Inputs
-
-
-
-
-
- {SAMPLES.map((sample, index) => (
-
-
-
- ))}
-
-
-
-
-
+ (
+
+ ))}
+ />
);
}
diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx
index 1f392135..eba69408 100644
--- a/demo/src/MemoryModelsUserInput.tsx
+++ b/demo/src/MemoryModelsUserInput.tsx
@@ -1,21 +1,18 @@
import React, { useState } from "react";
import {
- Accordion,
- AccordionDetails,
- AccordionSummary,
+ Box,
Button,
- Card,
- CardContent,
Checkbox,
FormControlLabel,
- Grid,
Input,
- Stack,
TextField,
Tooltip,
+ MenuItem,
+ Stack,
} from "@mui/material";
import DownloadJSONButton from "./DownloadJSONButton";
-import { ExpandMore } from "@mui/icons-material";
+import MemoryModelsMenu from "./MemoryModelsMenu";
+import MemoryModelsSample from "./MemoryModelsSample";
interface configDataPropTypes {
useAutomation: boolean;
@@ -44,7 +41,7 @@ type MemoryModelsTextInputPropTypes = {
type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes &
MemoryModelsTextInputPropTypes &
MemoryModelsConfigInputPropTypes & {
- onTextDataSubmit: (event: React.MouseEvent) => void;
+ onTextDataSubmit: (event?: React.MouseEvent) => void;
};
function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) {
@@ -73,36 +70,26 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) {
};
return (
-
-
+
+
-
+ Load file data
+
+
);
}
@@ -112,24 +99,17 @@ function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) {
};
return (
-
-
-
+
);
}
@@ -157,36 +137,42 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) {
};
return (
-
-
-
-
+
-
+
+
+ >
+ }
+ />
);
}
@@ -195,36 +181,34 @@ export default function MemoryModelsUserInput(
) {
return (
);
}
diff --git a/demo/src/SvgDisplay.tsx b/demo/src/SvgDisplay.tsx
index 5dbdcb76..cfede943 100644
--- a/demo/src/SvgDisplay.tsx
+++ b/demo/src/SvgDisplay.tsx
@@ -1,5 +1,6 @@
import React, { useRef, useEffect } from "react";
import mem from "memory-viz";
+import { Paper } from "@mui/material";
import { configDataPropTypes } from "./MemoryModelsUserInput";
type SvgDisplayPropTypes = {
@@ -29,11 +30,21 @@ export default function SvgDisplay(props: SvgDisplayPropTypes) {
}, [props.jsonResult]);
return (
-
+
+
+
);
}
+
+export type { SvgDisplayPropTypes };
diff --git a/demo/src/__tests__/DownloadJSONButton.spec.tsx b/demo/src/__tests__/DownloadJSONButton.spec.tsx
index 82b5d00b..8313fce9 100644
--- a/demo/src/__tests__/DownloadJSONButton.spec.tsx
+++ b/demo/src/__tests__/DownloadJSONButton.spec.tsx
@@ -10,7 +10,7 @@ describe("DownloadJSONButton", () => {
});
test("renders with correct text", () => {
- const downloadButton = screen.getByText("Download This JSON");
+ const downloadButton = screen.getByText("Download JSON");
expect(downloadButton).toBeDefined();
});
});
diff --git a/demo/src/__tests__/DownloadSVGButton.spec.tsx b/demo/src/__tests__/DownloadSVGButton.spec.tsx
index 00bc9d97..fe4d0baa 100644
--- a/demo/src/__tests__/DownloadSVGButton.spec.tsx
+++ b/demo/src/__tests__/DownloadSVGButton.spec.tsx
@@ -9,7 +9,7 @@ describe("DownloadSVGButton", () => {
});
test("renders with correct text", () => {
- const downloadButton = screen.getByText("Download This SVG");
+ const downloadButton = screen.getByText("Download SVG");
expect(downloadButton).toBeDefined();
});
});
diff --git a/demo/src/__tests__/MemoryModelsSample.spec.tsx b/demo/src/__tests__/MemoryModelsSample.spec.tsx
index 933207c7..6871c7c6 100644
--- a/demo/src/__tests__/MemoryModelsSample.spec.tsx
+++ b/demo/src/__tests__/MemoryModelsSample.spec.tsx
@@ -37,23 +37,27 @@ describe("MemoryModelsSample", () => {
);
});
- it("renders Accordion", () => {
- expect(
- screen.getByTestId("sample-inputs-accordion").textContent
- ).toEqual("Sample Inputs");
+ it("renders Menu", () => {
+ expect(screen.getByTestId("sample-inputs-menu").textContent).toEqual(
+ "Sample Inputs"
+ );
expect(screen.getByText("Sample Inputs")).toBeDefined();
});
- it("renders all sample buttons", () => {
+ it("renders all sample buttons", async () => {
// sx for MUI comps or non-inline CSS in general will not be loaded into Jest by default
// might be achievable with some libs but this test makes sure the base texts are present.
// Therefore, we can't test for capitalization (via sx) here
- SAMPLES.map((sample) =>
- expect(screen.getByText(sample["name"])).toBeDefined()
- );
+ fireEvent.click(screen.getByText("Sample Inputs"));
+ await waitFor(() => {
+ SAMPLES.map((sample) =>
+ expect(screen.getByText(sample["name"])).toBeDefined()
+ );
+ });
});
it("handles sample button click", async () => {
+ fireEvent.click(screen.getByText("Sample Inputs"));
const button = screen.getByText("Automated Layout");
fireEvent.click(button);
diff --git a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
index 9f580016..924d6ec7 100644
--- a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
+++ b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
@@ -21,7 +21,7 @@ describe("MemoryModelsUserInput", () => {
textDataMock = "";
});
- it("renders Accordion for MemoryModelsConfigInput", () => {
+ it("renders Menu for MemoryModelsConfigInput", () => {
render(
{
/>
);
expect(
- screen.getByTestId("rendering-options-accordion").textContent
+ screen.getByTestId("rendering-options-menu").textContent
).toEqual("Rendering Options");
});
@@ -223,6 +223,7 @@ describe("MemoryModelsUserInput", () => {
});
it("renders a number input with correct props and checkbox that is checked by default", () => {
+ fireEvent.click(screen.getByText("Rendering Options"));
const seedInput: HTMLInputElement =
screen.getByTestId("config-seed");
[
@@ -242,6 +243,7 @@ describe("MemoryModelsUserInput", () => {
});
it("handles seed change", () => {
+ fireEvent.click(screen.getByText("Rendering Options"));
const seedInput: HTMLInputElement =
screen.getByTestId("config-seed");
const mockSeed = "123";
@@ -256,6 +258,7 @@ describe("MemoryModelsUserInput", () => {
});
it("handles automation change", () => {
+ fireEvent.click(screen.getByText("Rendering Options"));
const automationCheckbox: HTMLInputElement = screen.getByLabelText(
"Use automatic layout"
);
diff --git a/demo/src/css/styles.css b/demo/src/css/styles.css
index 61ac33e6..43c1785e 100644
--- a/demo/src/css/styles.css
+++ b/demo/src/css/styles.css
@@ -6,3 +6,17 @@ input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
+
+.menu-button {
+ text-transform: none !important;
+}
+
+.menu-button .MuiSvgIcon-root {
+ transition: transform 0.2s ease-in-out;
+ transform: rotate(0deg);
+}
+
+.menu-button.open .MuiSvgIcon-root {
+ transition: transform 0.2s ease-in-out;
+ transform: rotate(180deg);
+}
diff --git a/demo/src/declarations.d.ts b/demo/src/declarations.d.ts
new file mode 100644
index 00000000..a860a74b
--- /dev/null
+++ b/demo/src/declarations.d.ts
@@ -0,0 +1,5 @@
+// Prevents module not found errors when importing images
+declare module "*.png" {
+ const value: any;
+ export default value;
+}
diff --git a/demo/src/html/index.html b/demo/src/html/index.html
index cfe91ced..417cd489 100644
--- a/demo/src/html/index.html
+++ b/demo/src/html/index.html
@@ -4,21 +4,8 @@
<%= htmlWebpackPlugin.options.title %>
+
-
-
-
-
+