From 3e192f8e26597918d4b1a226478129a0fbb3909e Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 24 Oct 2025 11:09:21 +0200 Subject: [PATCH] remove dependency on MUI --- bun.lock | 2 - package.json | 2 - src/App/App.css | 10 ++++ src/App/App.tsx | 67 +++++++++++++-------------- src/App/BottomPanel.tsx | 9 +++- src/statecharts/detect_connections.ts | 6 +++ src/statecharts/parser.ts | 7 +++ todo.txt | 13 ++++-- 8 files changed, 72 insertions(+), 44 deletions(-) diff --git a/bun.lock b/bun.lock index 7bb152c..60c8a0c 100644 --- a/bun.lock +++ b/bun.lock @@ -4,10 +4,8 @@ "": { "name": "bun-react-template", "dependencies": { - "@emotion/styled": "^11.14.1", "@fontsource/roboto": "^5.2.8", "@mui/icons-material": "^7.3.4", - "@mui/material": "^7.3.4", "react": "^19", "react-dom": "^19", }, diff --git a/package.json b/package.json index ac5cb33..4703ebe 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,8 @@ "start": "NODE_ENV=production bun src/index.tsx" }, "dependencies": { - "@emotion/styled": "^11.14.1", "@fontsource/roboto": "^5.2.8", "@mui/icons-material": "^7.3.4", - "@mui/material": "^7.3.4", "react": "^19", "react-dom": "^19" }, diff --git a/src/App/App.css b/src/App/App.css index a073dd9..133cb7a 100644 --- a/src/App/App.css +++ b/src/App/App.css @@ -94,3 +94,13 @@ button.active { max-height: 100vh; overflow: auto; } + +div.stackVertical { + display: flex; + flex-direction: column; +} + +div.stackHorizontal { + display: flex; + flex-direction: row; +} diff --git a/src/App/App.tsx b/src/App/App.tsx index fc600d7..f79a9f3 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -8,8 +8,6 @@ import { getSimTime, getWallClkDelay, TimeMode } from "../statecharts/time"; import "../index.css"; import "./App.css"; -import Stack from "@mui/material/Stack"; -import Box from "@mui/material/Box"; import { TopPanel } from "./TopPanel"; import { ShowAST, ShowInputEvents, ShowInternalEvents, ShowOutputEvents } from "./ShowAST"; import { parseStatechart } from "../statecharts/parser"; @@ -92,6 +90,7 @@ export function App() { console.log('recovering state...'); const compressedState = window.location.hash.slice(1); if (compressedState.length === 0) { + // empty URL hash console.log("no state to recover"); setEditHistory(() => ({current: emptyState, history: [], future: []})); return; @@ -100,6 +99,7 @@ export function App() { try { compressedBuffer = Uint8Array.fromBase64(compressedState); // may throw } catch (e) { + // probably invalid base64 console.error("failed to recover state:", e); setEditHistory(() => ({current: emptyState, history: [], future: []})); return; @@ -114,6 +114,7 @@ export function App() { setEditHistory(() => ({current: recoveredState, history: [], future: []})); }) .catch(e => { + // any other error: invalid JSON, or decompression failed. console.error("failed to recover state:", e); setEditHistory({current: emptyState, history: [], future: []}); }); @@ -370,16 +371,16 @@ export function App() { } - - +
+
{/* Left: top bar and main editor */} - - +
+
{/* Top bar */} - } - +
{/* Below the top bar: Editor */} - +
{editorState && conns && syntaxErrors && } - - - +
+
+
{/* Right: sidebar */} - - - +
state tree @@ -447,36 +448,34 @@ export function App() { plant.render(trace.trace[trace.idx].plantState, event => onRaise(event.name, event.param))}
setShowExecutionTrace(e.newState === "open")}>execution trace
- +
+ {/* We cheat a bit, and render the execution trace depending on whether the
above is 'open' or not, rather than putting it as a child of the
. We do this because only then can we get the execution trace to scroll without the rest scrolling as well. */} {showExecutionTrace && - - {/* */} - {/* execution trace */} -
- {ast && } -
- {/*
*/} -
} +
+ {ast && } +
+
} - - -
- +
+
+ + -
+ {/* Bottom panel */} - +
{syntaxErrors && } - - +
+ ; } diff --git a/src/App/BottomPanel.tsx b/src/App/BottomPanel.tsx index 3bd47f2..4533f24 100644 --- a/src/App/BottomPanel.tsx +++ b/src/App/BottomPanel.tsx @@ -3,11 +3,16 @@ import { TraceableError } from "../statecharts/parser"; import "./BottomPanel.css"; -import head from "../head.svg" ; +import logo from "../../artwork/logo-playful.svg"; import { PersistentDetails } from "./PersistentDetails"; export function BottomPanel(props: {errors: TraceableError[]}) { - const [greeting, setGreeting] = useState(<> "Welcome to StateBuddy, buddy!"
); + const [greeting, setGreeting] = useState( +
+ + Welcome to + +
); useEffect(() => { setTimeout(() => { diff --git a/src/statecharts/detect_connections.ts b/src/statecharts/detect_connections.ts index 37a9167..9465eca 100644 --- a/src/statecharts/detect_connections.ts +++ b/src/statecharts/detect_connections.ts @@ -13,6 +13,7 @@ export type Connections = { } export function detectConnections(state: VisualEditorState): Connections { + const startTime = performance.now(); // detect what is 'connected' const arrow2SideMap = new Map(); const side2ArrowMap = new Map>(); @@ -72,6 +73,11 @@ export function detectConnections(state: VisualEditorState): Connections { } } + const endTime = performance.now(); + + // rather slow, about 10ms for a large model: + // console.debug("connection detection took", endTime-startTime); + return { arrow2SideMap, side2ArrowMap, diff --git a/src/statecharts/parser.ts b/src/statecharts/parser.ts index 099272d..d53388a 100644 --- a/src/statecharts/parser.ts +++ b/src/statecharts/parser.ts @@ -78,6 +78,8 @@ export function parseStatechart(state: VisualEditorState, conns: Connections): [ // step 1: figure out state hierarchy + const startTime = performance.now(); + // IMPORTANT ASSUMPTION: state.rountangles is sorted from big to small surface area: for (const rt of state.rountangles) { const parent = findParent(rt); @@ -132,6 +134,11 @@ export function parseStatechart(state: VisualEditorState, conns: Connections): [ historyStates.push(historyState); } + const endTime = performance.now(); + + // currently seems to be quite fast: + // console.log('built state tree', endTime-startTime); + // step 2: figure out transitions const transitions = new Map(); diff --git a/todo.txt b/todo.txt index b18377b..73444e0 100644 --- a/todo.txt +++ b/todo.txt @@ -27,8 +27,9 @@ TODO -- digital watch: - highlight when watch button pressed/released +- testing + use STL for testing + https://github.com/mvcisback/py-metric-temporal-logic - maybe support: - explicit order of: @@ -51,17 +52,21 @@ TODO don't crash and show the error - buttons to rotate selection 90 degrees +- performance: + maybe try this for rendering the execution trace: + https://legacy.reactjs.org/docs/optimizing-performance.html#virtualize-long-lists + - experimental features: - multiverse execution history stable tree layout? https://pub.dev/packages/ploeg_tree_layout - local scopes - - for the assignment: *ALL* features add history (look at original Harel paper) + add microwave oven + add traffic light Publish StateBuddy paper(s): compare CS approach to other tools, not only YAKINDU