Add Box component to improve renderers performance
This commit is contained in:
parent
3e6fb8c780
commit
032f9a6792
@ -1,10 +1,18 @@
|
||||
import { Card, Colors, Icon, IconName } from "@blueprintjs/core";
|
||||
import * as React from "react";
|
||||
import { Colors, Icon, IconName } from "@blueprintjs/core";
|
||||
import { RendererProps } from "../types";
|
||||
import { Box } from "../ui-utils";
|
||||
import { Bfg93Direction, Bfg93RS } from "./constants";
|
||||
|
||||
/** Common border color for dark and light, using transparency */
|
||||
export const BorderColor = Colors.GRAY3 + "55";
|
||||
|
||||
// Parameters for cell sizing, balanced to span the full row width
|
||||
// Constraint: `(width% + 2 * margin%) * ROWSIZE = 100%`
|
||||
const ROWSIZE = 8;
|
||||
const CELL_WIDTH = "12%";
|
||||
const CELL_MARGIN = "5px 0.25%";
|
||||
|
||||
const styles = {
|
||||
placeholderDiv: {
|
||||
height: "100%",
|
||||
@ -33,9 +41,9 @@ const styles = {
|
||||
},
|
||||
stackItem: {
|
||||
// Sizing
|
||||
width: "10%",
|
||||
height: "40px",
|
||||
margin: "5px 0.25%",
|
||||
width: CELL_WIDTH,
|
||||
margin: CELL_MARGIN,
|
||||
height: "50px",
|
||||
// Center-align values
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
@ -50,10 +58,10 @@ const DirectionIcons: { [k: string]: IconName } = {
|
||||
[Bfg93Direction.DOWN]: "arrow-down",
|
||||
};
|
||||
|
||||
const StackItem = ({ value }: { value: number }) => {
|
||||
const cellStyle = { ...styles.stackItem };
|
||||
return <Card style={cellStyle}>{value}</Card>;
|
||||
};
|
||||
/** Component for displaying a single stack item */
|
||||
const StackItem = React.memo(({ value }: { value: number }) => {
|
||||
return <Box style={styles.stackItem}>{value}</Box>;
|
||||
});
|
||||
|
||||
export const Renderer = ({ state }: RendererProps<Bfg93RS>) => {
|
||||
if (state == null)
|
||||
@ -64,7 +72,6 @@ export const Renderer = ({ state }: RendererProps<Bfg93RS>) => {
|
||||
<div style={styles.dirnContainer}>
|
||||
<span style={{ fontWeight: "bold", marginRight: 5 }}>Direction: </span>
|
||||
<Icon icon={DirectionIcons[state.direction]} />
|
||||
{/* <span style={{ marginLeft: 10 }} /> */}
|
||||
<span style={{ marginLeft: 30, fontWeight: "bold", marginRight: 5 }}>
|
||||
String mode:{" "}
|
||||
</span>
|
||||
|
@ -81,9 +81,12 @@ export const editorTokensProvider: MonacoTokensProvider = {
|
||||
};
|
||||
|
||||
/** Serialize tape from object format into linear array */
|
||||
export const serializeTapeMap = (tape: BFRS["tape"]): number[] => {
|
||||
export const serializeTapeMap = (
|
||||
tape: BFRS["tape"],
|
||||
minCells: number = 0
|
||||
): number[] => {
|
||||
const cellIdxs = Object.keys(tape).map((s) => parseInt(s, 10));
|
||||
const maxCellIdx = Math.max(15, ...cellIdxs);
|
||||
const maxCellIdx = Math.max(minCells - 1, ...cellIdxs);
|
||||
const linearTape: number[] = Array(maxCellIdx + 1).fill(0);
|
||||
cellIdxs.forEach((i) => (linearTape[i] = tape[i] || 0));
|
||||
return linearTape;
|
||||
|
@ -1,14 +1,17 @@
|
||||
import { Card, Colors } from "@blueprintjs/core";
|
||||
import { CSSProperties } from "react";
|
||||
import { useDarkMode } from "../../ui/providers/dark-mode-provider";
|
||||
import * as React from "react";
|
||||
import { RendererProps } from "../types";
|
||||
import { Box } from "../ui-utils";
|
||||
import { BFRS, serializeTapeMap } from "./common";
|
||||
|
||||
// Colors used as background of active cells
|
||||
const darkActiveBG = Colors.DARK_GRAY2;
|
||||
const lightActiveBG = Colors.LIGHT_GRAY3;
|
||||
/** Number of cells shown in a single row */
|
||||
const ROWSIZE = 8;
|
||||
|
||||
const styles: { [k: string]: CSSProperties } = {
|
||||
// Parameters for cell sizing, balanced to span the full row width
|
||||
// Constraint: `(width% + 2 * margin%) * ROWSIZE = 100%`
|
||||
const CELL_WIDTH = "12%";
|
||||
const CELL_MARGIN = "5px 0.25%";
|
||||
|
||||
const styles: { [k: string]: React.CSSProperties } = {
|
||||
container: {
|
||||
padding: 10,
|
||||
height: "100%",
|
||||
@ -19,9 +22,9 @@ const styles: { [k: string]: CSSProperties } = {
|
||||
},
|
||||
cell: {
|
||||
// Sizing
|
||||
width: "12%",
|
||||
width: CELL_WIDTH,
|
||||
margin: CELL_MARGIN,
|
||||
height: "50px",
|
||||
margin: "5px 0.25%",
|
||||
// Center-align values
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
@ -30,22 +33,24 @@ const styles: { [k: string]: CSSProperties } = {
|
||||
};
|
||||
|
||||
/** Component for displaying a single tape cell */
|
||||
const Cell = ({ value, active }: { value: number; active: boolean }) => {
|
||||
const { isDark } = useDarkMode();
|
||||
const cellStyle = { ...styles.cell };
|
||||
const activeBg = isDark ? darkActiveBG : lightActiveBG;
|
||||
if (active) {
|
||||
cellStyle.backgroundColor = activeBg;
|
||||
cellStyle.fontWeight = "bold";
|
||||
const Cell = React.memo(
|
||||
({ value, active }: { value: number; active: boolean }) => {
|
||||
return (
|
||||
<Box
|
||||
intent={active ? "active" : "plain"}
|
||||
style={{ ...styles.cell, fontWeight: active ? "bold" : undefined }}
|
||||
>
|
||||
{value}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return <Card style={cellStyle}>{value}</Card>;
|
||||
};
|
||||
);
|
||||
|
||||
/** Renderer for Brainfuck */
|
||||
export const Renderer = ({ state }: RendererProps<BFRS>) => {
|
||||
return (
|
||||
<div style={styles.container}>
|
||||
{serializeTapeMap(state?.tape || {}).map((num, i) => (
|
||||
{serializeTapeMap(state?.tape || {}, 2 * ROWSIZE).map((num, i) => (
|
||||
<Cell value={num} key={i} active={(state?.pointer || 0) === i} />
|
||||
))}
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box } from "../../ui-utils";
|
||||
import { CharacterValue } from "../common";
|
||||
import { SimpleTag } from "./utils";
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
@ -13,9 +13,9 @@ export const CharacterRow = (props: Props) => {
|
||||
<div style={{ margin: "20px 10px" }}>
|
||||
<div>
|
||||
<b style={{ marginRight: 5 }}>{name}:</b>{" "}
|
||||
<pre style={{ display: "inline" }}>{value.value}</pre>
|
||||
<pre style={{ display: "inline", marginRight: 15 }}>{value.value}</pre>
|
||||
{value.stack.map((v, i) => (
|
||||
<SimpleTag key={i}>{v}</SimpleTag>
|
||||
<Box key={i}>{v}</Box>
|
||||
))}
|
||||
</div>
|
||||
<div></div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Tag, Text } from "@blueprintjs/core";
|
||||
import { SimpleTag } from "./utils";
|
||||
import React from "react";
|
||||
import { Text } from "@blueprintjs/core";
|
||||
import { Box } from "../../ui-utils";
|
||||
|
||||
const styles = {
|
||||
charChip: {
|
||||
@ -22,20 +23,16 @@ export const TopBar = (props: Props) => {
|
||||
|
||||
const characterChips =
|
||||
charactersOnStage.length === 0 ? (
|
||||
<Tag large minimal>
|
||||
The stage is empty
|
||||
</Tag>
|
||||
<Box>The stage is empty</Box>
|
||||
) : (
|
||||
charactersOnStage.map((character) => {
|
||||
return (
|
||||
<SimpleTag
|
||||
key={character}
|
||||
intent={character === currSpeaker ? "active" : undefined}
|
||||
>
|
||||
{character}
|
||||
</SimpleTag>
|
||||
);
|
||||
})
|
||||
charactersOnStage.map((character) => (
|
||||
<Box
|
||||
key={character}
|
||||
intent={character === currSpeaker ? "active" : "plain"}
|
||||
>
|
||||
{character}
|
||||
</Box>
|
||||
))
|
||||
);
|
||||
|
||||
return (
|
||||
@ -46,9 +43,9 @@ export const TopBar = (props: Props) => {
|
||||
<Text tagName="span" style={styles.questionText}>
|
||||
Answer to question:
|
||||
</Text>
|
||||
<SimpleTag intent={questionState ? "success" : "danger"}>
|
||||
<Box intent={questionState ? "success" : "danger"}>
|
||||
{questionState ? "yes" : "no"}
|
||||
</SimpleTag>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,41 +1,43 @@
|
||||
import { CSSProperties } from "react";
|
||||
import { Colors } from "@blueprintjs/core";
|
||||
import { useDarkMode } from "../../../ui/providers/dark-mode-provider";
|
||||
import { useDarkMode } from "../ui/providers/dark-mode-provider";
|
||||
|
||||
const backgroundColorsLight = {
|
||||
success: Colors.GREEN3,
|
||||
danger: Colors.RED3,
|
||||
plain: Colors.GRAY3,
|
||||
active: Colors.DARK_GRAY1,
|
||||
success: Colors.GREEN5,
|
||||
danger: Colors.RED5,
|
||||
plain: Colors.LIGHT_GRAY1,
|
||||
active: Colors.GRAY4,
|
||||
};
|
||||
|
||||
const backgroundColorsDark = {
|
||||
success: Colors.GREEN3,
|
||||
danger: Colors.RED3,
|
||||
plain: Colors.GRAY3,
|
||||
active: Colors.LIGHT_GRAY5,
|
||||
success: Colors.GREEN1,
|
||||
danger: Colors.RED1,
|
||||
plain: Colors.DARK_GRAY5,
|
||||
active: Colors.GRAY1,
|
||||
};
|
||||
|
||||
const foregroundColorsLight = {
|
||||
success: Colors.GREEN2,
|
||||
danger: Colors.RED2,
|
||||
success: Colors.GREEN1,
|
||||
danger: Colors.RED1,
|
||||
plain: Colors.DARK_GRAY1,
|
||||
active: Colors.LIGHT_GRAY5,
|
||||
active: Colors.DARK_GRAY1,
|
||||
};
|
||||
|
||||
const foregroundColorsDark = {
|
||||
success: Colors.GREEN5,
|
||||
danger: Colors.RED5,
|
||||
plain: Colors.LIGHT_GRAY5,
|
||||
active: Colors.DARK_GRAY1,
|
||||
active: Colors.LIGHT_GRAY5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility component that renders a tag similar to BlueprintJS tags, but underneath
|
||||
* is just a single span tag with no frills and high performance.
|
||||
* Utility component for rendering a simple general-purpose stylable box. Useful
|
||||
* for performance-critical components in visualisation renderers.
|
||||
*/
|
||||
export const SimpleTag = (props: {
|
||||
export const Box = (props: {
|
||||
children: React.ReactNode;
|
||||
intent?: "success" | "danger" | "active";
|
||||
intent?: "plain" | "success" | "danger" | "active";
|
||||
style?: CSSProperties;
|
||||
}) => {
|
||||
const { isDark } = useDarkMode();
|
||||
const intent = props.intent == null ? "plain" : props.intent;
|
||||
@ -49,9 +51,9 @@ export const SimpleTag = (props: {
|
||||
margin: 5,
|
||||
padding: "5px 10px",
|
||||
borderRadius: 3,
|
||||
backgroundColor:
|
||||
backgroundMap[intent] + (intent === "active" ? "aa" : "55"),
|
||||
backgroundColor: backgroundMap[intent],
|
||||
color: foregroundMap[intent],
|
||||
...props.style,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
Loading…
x
Reference in New Issue
Block a user