add about dialog

This commit is contained in:
Joeri Exelmans 2025-10-19 20:03:06 +02:00
parent 20a36825d4
commit 20f28d8382
5 changed files with 39 additions and 6 deletions

Binary file not shown.

11
src/App/About.tsx Normal file
View file

@ -0,0 +1,11 @@
import logo from "../../artwork/logo.svg";
export function About() {
return <div style={{display: 'inline-block', backgroundColor: 'white', width: 500, padding: 4}}>
<p><img src={logo}/></p>
<p>StateBuddy is a <a href="https://dl.acm.org/doi/10.1016/0167-6423(87)90035-9">statechart</a> editing, simulation, debugging and testing environment inspired by <a href="https://dl.acm.org/doi/10.1145/3417990.3421401">CouchEdit</a>.</p>
<p>It was originally created for teaching Statecharts to university students, but likely is a useful tool for other purposes as well.</p>
<p>StateBuddy is <a href="https://deemz.org/git/research/statebuddy">open source</a>.</p>
<p>For commerical use, <a href="mailto:joeri.exelmans@gmail.com">e&#x2011;mail me</a> for permission.</p>
</div>;
}

View file

@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react"; import { ReactElement, useEffect, useRef, useState } from "react";
import { emptyStatechart, Statechart } from "../statecharts/abstract_syntax"; import { emptyStatechart, Statechart } from "../statecharts/abstract_syntax";
import { handleInputEvent, initialize } from "../statecharts/interpreter"; import { handleInputEvent, initialize } from "../statecharts/interpreter";
@ -25,6 +25,8 @@ export function App() {
const [rtIdx, setRTIdx] = useState<number|undefined>(); const [rtIdx, setRTIdx] = useState<number|undefined>();
const [time, setTime] = useState<TimeMode>({kind: "paused", simtime: 0}); const [time, setTime] = useState<TimeMode>({kind: "paused", simtime: 0});
const [modal, setModal] = useState<ReactElement|null>(null);
const refRightSideBar = useRef<HTMLDivElement>(null); const refRightSideBar = useRef<HTMLDivElement>(null);
function onInit() { function onInit() {
@ -144,7 +146,19 @@ export function App() {
console.log(ast); console.log(ast);
return <Stack sx={{height:'100vh'}}> return <>
{/* Modal dialog */}
{modal && <div
onMouseDown={() => setModal(null)}
style={{width: '100%', height: '100%', position:'absolute', textAlign: 'center', backgroundColor: 'rgba(127,127,127,0.5)' }}>
<div
style={{position: 'relative', top: '50%', transform: 'translateY(-50%)'}}>
<span onMouseDown={e => e.stopPropagation()}>
{modal}
</span>
</div>
</div>}
<Stack sx={{height:'100vh'}}>
{/* Top bar */} {/* Top bar */}
<Box <Box
sx={{ sx={{
@ -156,7 +170,7 @@ export function App() {
}}> }}>
<TopPanel <TopPanel
rt={rtIdx === undefined ? undefined : rt[rtIdx]} rt={rtIdx === undefined ? undefined : rt[rtIdx]}
{...{rtIdx, ast, time, setTime, onInit, onClear, onRaise, onBack, mode, setMode}} {...{rtIdx, ast, time, setTime, onInit, onClear, onRaise, onBack, mode, setMode, setModal}}
/> />
</Box> </Box>
@ -195,7 +209,8 @@ export function App() {
}}> }}>
<BottomPanel {...{errors}}/> <BottomPanel {...{errors}}/>
</Box> </Box>
</Stack>; </Stack>
</>;
} }
export default App; export default App;

View file

@ -6,7 +6,7 @@ import "./BottomPanel.css";
import head from "../head.svg" ; import head from "../head.svg" ;
export function BottomPanel(props: {errors: TraceableError[]}) { export function BottomPanel(props: {errors: TraceableError[]}) {
const [greeting, setGreeting] = useState(<b><img src={head}/>&emsp;"Welcome to StateBuddy, buddy!"</b>); const [greeting, setGreeting] = useState(<><b><img src={head}/>&emsp;"Welcome to StateBuddy, buddy!"</b></>);
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {

View file

@ -13,10 +13,12 @@ import AccessAlarmIcon from '@mui/icons-material/AccessAlarm';
import StopIcon from '@mui/icons-material/Stop'; import StopIcon from '@mui/icons-material/Stop';
import UndoIcon from '@mui/icons-material/Undo'; import UndoIcon from '@mui/icons-material/Undo';
import RedoIcon from '@mui/icons-material/Redo'; import RedoIcon from '@mui/icons-material/Redo';
import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
import { formatTime } from "./util"; import { formatTime } from "./util";
import { InsertMode } from "../VisualEditor/VisualEditor"; import { InsertMode } from "../VisualEditor/VisualEditor";
import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo"; import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo";
import { About } from "./About";
export type TopPanelProps = { export type TopPanelProps = {
rt?: BigStep, rt?: BigStep,
@ -30,6 +32,7 @@ export type TopPanelProps = {
ast: Statechart, ast: Statechart,
mode: InsertMode, mode: InsertMode,
setMode: Dispatch<SetStateAction<InsertMode>>, setMode: Dispatch<SetStateAction<InsertMode>>,
setModal: Dispatch<SetStateAction<ReactElement>>,
} }
function RountangleIcon(props: {kind: string}) { function RountangleIcon(props: {kind: string}) {
@ -63,7 +66,7 @@ function HistoryIcon(props: {kind: "shallow"|"deep"}) {
} }
export function TopPanel({rt, rtIdx, time, setTime, onInit, onClear, onRaise, onBack, ast, mode, setMode}: TopPanelProps) { export function TopPanel({rt, rtIdx, time, setTime, onInit, onClear, onRaise, onBack, ast, mode, setMode, setModal}: TopPanelProps) {
const [displayTime, setDisplayTime] = useState("0.000"); const [displayTime, setDisplayTime] = useState("0.000");
const [timescale, setTimescale] = useState(1); const [timescale, setTimescale] = useState(1);
const [showKeys, setShowKeys] = useState(true); const [showKeys, setShowKeys] = useState(true);
@ -322,5 +325,9 @@ export function TopPanel({rt, rtIdx, time, setTime, onInit, onClear, onRaise, on
</div> </div>
&emsp;
<button onClick={() => setModal(<About setModal={setModal}/>)}><InfoOutlineIcon fontSize="small"/></button>
</div></>; </div></>;
} }