new featuregit status dark mode
This commit is contained in:
parent
9646d716c6
commit
6efc27453e
14 changed files with 189 additions and 149 deletions
|
|
@ -1,61 +1,44 @@
|
||||||
/* details {
|
|
||||||
padding-left: 20;
|
|
||||||
}
|
|
||||||
summary {
|
|
||||||
margin-left: -20;
|
|
||||||
} */
|
|
||||||
|
|
||||||
details:has(+ details) {
|
details:has(+ details) {
|
||||||
border-bottom: 1px lightgrey solid;
|
border-bottom: 1px var(--separator-color) solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.runtimeState {
|
.runtimeState {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
/* padding-left: 4px;
|
|
||||||
padding-right: 4px;
|
|
||||||
padding-top: 2px;
|
|
||||||
padding-bottom: 2px; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.runtimeState:has(+.runtimeState) {
|
.runtimeState:has(+.runtimeState) {
|
||||||
border-bottom: 1px lightgrey solid;
|
border-bottom: 1px var(--separator-color) solid;
|
||||||
}
|
}
|
||||||
.runtimeState:has(+.runtimeState.active) {
|
.runtimeState:has(+.runtimeState.active) {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.runtimeState:hover {
|
.runtimeState:hover {
|
||||||
/* background-color: rgba(255, 140, 0, 0.2); */
|
background-color: var(--light-accent-color);
|
||||||
background-color: rgba(0,0,255,0.2);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.runtimeState.active {
|
.runtimeState.active {
|
||||||
background-color: rgba(0,0,255,0.2);
|
background-color: var(--light-accent-color);
|
||||||
border: solid blue 1px;
|
border: solid var(--accent-border-color) 1px;
|
||||||
}
|
}
|
||||||
.runtimeState.plantStep:not(.active) {
|
.runtimeState.plantStep:not(.active) {
|
||||||
background-color: #f7f7f7;
|
background-color: var(--inactive-bg-color);
|
||||||
}
|
}
|
||||||
.runtimeState.plantStep * {
|
.runtimeState.plantStep * {
|
||||||
color: grey;
|
color: var(--inactive-fg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.runtimeState.runtimeError {
|
.runtimeState.runtimeError {
|
||||||
background-color: lightpink;
|
background-color: var(--error-bg-color);
|
||||||
color: darkred;
|
color: var(--error-color); /* used to be darkred, but this one's a bit lighter */
|
||||||
}
|
}
|
||||||
|
|
||||||
.runtimeState.runtimeError.active {
|
.runtimeState.runtimeError.active {
|
||||||
border-color: darkred;
|
border-color: var(--error-color);/* used to be darkred, but this one's a bit lighter */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* details:not(:has(details)) > summary::marker {
|
|
||||||
color: white;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.readonlyTextBox {
|
.readonlyTextBox {
|
||||||
width: 56;
|
width: 56;
|
||||||
background-color:"#eee";
|
|
||||||
text-align: "right";
|
text-align: "right";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,20 +61,23 @@ details:has(+ details) {
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: #fcfcfc;
|
background-color: var(--button-bg-color);
|
||||||
border: 1px lightgrey solid;
|
border: 1px var(--separator-color) solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:not(:disabled):hover {
|
button:not(:disabled):hover {
|
||||||
background-color: rgba(0, 0, 255, 0.2);
|
background-color: var(--light-accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: var(--inactive-bg-color);
|
||||||
|
color: var(--inactive-fg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.active {
|
button.active {
|
||||||
border: solid blue 1px;
|
border: solid var(--accent-border-color) 1px;
|
||||||
background-color: rgba(0,0,255,0.2);
|
background-color: var(--light-accent-color);
|
||||||
/* margin-right: 1px; */
|
color: var(--text-color);
|
||||||
/* margin-left: 0; */
|
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modalOuter {
|
.modalOuter {
|
||||||
|
|
@ -102,7 +88,7 @@ button.active {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: rgba(200,200,200,0.7);
|
background-color: var(--modal-backdrop-color);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +96,7 @@ button.active {
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: white;
|
background-color: var(--background-color);
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +114,7 @@ div.stackHorizontal {
|
||||||
div.status {
|
div.status {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
background-color: grey;
|
background-color: var(--status-inactive-color);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
|
@ -141,6 +127,6 @@ div.status.violated {
|
||||||
}
|
}
|
||||||
|
|
||||||
div.status.satisfied {
|
div.status.satisfied {
|
||||||
background-color: forestgreen;
|
background-color: var(--status-ok-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { useUrlHashState } from "../hooks/useUrlHashState";
|
||||||
import { plants } from "./plants";
|
import { plants } from "./plants";
|
||||||
import { emptyState } from "@/statecharts/concrete_syntax";
|
import { emptyState } from "@/statecharts/concrete_syntax";
|
||||||
import { ModalOverlay } from "./Modals/ModalOverlay";
|
import { ModalOverlay } from "./Modals/ModalOverlay";
|
||||||
|
import { usePersistentState } from "@/hooks/usePersistentState";
|
||||||
|
|
||||||
export type EditHistory = {
|
export type EditHistory = {
|
||||||
current: VisualEditorState,
|
current: VisualEditorState,
|
||||||
|
|
@ -38,10 +39,14 @@ const defaultAppState: AppState = {
|
||||||
...defaultSideBarState,
|
...defaultSideBarState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LightMode = "light" | "auto" | "dark";
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const [editHistory, setEditHistory] = useState<EditHistory|null>(null);
|
const [editHistory, setEditHistory] = useState<EditHistory|null>(null);
|
||||||
const [modal, setModal] = useState<ReactElement|null>(null);
|
const [modal, setModal] = useState<ReactElement|null>(null);
|
||||||
|
|
||||||
|
const [lightMode, setLightMode] = usePersistentState<LightMode>("lightMode", "auto");
|
||||||
|
|
||||||
const {makeCheckPoint, onRedo, onUndo, onRotate} = useEditor(setEditHistory);
|
const {makeCheckPoint, onRedo, onUndo, onRotate} = useEditor(setEditHistory);
|
||||||
|
|
||||||
const editorState = editHistory && editHistory.current;
|
const editorState = editHistory && editHistory.current;
|
||||||
|
|
@ -135,7 +140,8 @@ export function App() {
|
||||||
|
|
||||||
const plantState = currentBigStep && currentBigStep.state.plant || plant.execution.initial()[1];
|
const plantState = currentBigStep && currentBigStep.state.plant || plant.execution.initial()[1];
|
||||||
|
|
||||||
return <ModalOverlay modal={modal} setModal={setModal}>
|
return <div style={{height:'100%', colorScheme: lightMode!=="auto"?lightMode:undefined}}>
|
||||||
|
<ModalOverlay modal={modal} setModal={setModal}>
|
||||||
{/* top-to-bottom: everything -> bottom panel */}
|
{/* top-to-bottom: everything -> bottom panel */}
|
||||||
<div className="stackVertical" style={{height:'100%'}}>
|
<div className="stackVertical" style={{height:'100%'}}>
|
||||||
|
|
||||||
|
|
@ -150,7 +156,7 @@ export function App() {
|
||||||
style={{flex: '0 0 content'}}
|
style={{flex: '0 0 content'}}
|
||||||
>
|
>
|
||||||
{editHistory && <TopPanel
|
{editHistory && <TopPanel
|
||||||
{...{onUndo, onRedo, onRotate, setModal, editHistory, ...simulator, ...setters, ...appState}}
|
{...{onUndo, onRedo, onRotate, lightMode, setLightMode, setModal, editHistory, ...simulator, ...setters, ...appState}}
|
||||||
/>}
|
/>}
|
||||||
</div>
|
</div>
|
||||||
{/* Editor */}
|
{/* Editor */}
|
||||||
|
|
@ -179,7 +185,8 @@ export function App() {
|
||||||
{syntaxErrors && <BottomPanel {...{errors: syntaxErrors}}/>}
|
{syntaxErrors && <BottomPanel {...{errors: syntaxErrors}}/>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ModalOverlay>;
|
</ModalOverlay>
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom {
|
.bottom {
|
||||||
border-top: 1px lightgrey solid;
|
border-top: 1px var(--separator-color) solid;
|
||||||
background-color: rgb(255, 249, 235);
|
background-color: var(--bottom-panel-bg-color);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ import { TraceableError } from "../../statecharts/parser";
|
||||||
|
|
||||||
import "./BottomPanel.css";
|
import "./BottomPanel.css";
|
||||||
|
|
||||||
import logo from "../../../artwork/logo-playful.svg";
|
|
||||||
import { PersistentDetailsLocalStorage } from "../PersistentDetails";
|
import { PersistentDetailsLocalStorage } from "../PersistentDetails";
|
||||||
|
import { Logo } from "@/Logo/Logo";
|
||||||
|
|
||||||
export function BottomPanel(props: {errors: TraceableError[]}) {
|
export function BottomPanel(props: {errors: TraceableError[]}) {
|
||||||
const [greeting, setGreeting] = useState(
|
const [greeting, setGreeting] = useState(
|
||||||
<div style={{textAlign:'center'}}>
|
<div style={{textAlign:'center'}}>
|
||||||
<span style={{fontSize: 18, fontStyle: 'italic'}}>
|
<span style={{fontSize: 18, fontStyle: 'italic'}}>
|
||||||
Welcome to <img src={logo} style={{maxWidth:'100%'}}/>
|
Welcome to <Logo/>
|
||||||
</span>
|
</span>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
import { Logo } from "@/Logo/Logo";
|
||||||
import { Dispatch, ReactElement, SetStateAction } from "react";
|
import { Dispatch, ReactElement, SetStateAction } from "react";
|
||||||
import logo from "../../../artwork/logo-playful.svg";
|
|
||||||
|
|
||||||
export function About(props: {setModal: Dispatch<SetStateAction<ReactElement|null>>}) {
|
export function About(props: {setModal: Dispatch<SetStateAction<ReactElement|null>>}) {
|
||||||
return <div style={{maxWidth: '500px', padding: 4}}>
|
return <div style={{maxWidth: '500px', padding: 4}}>
|
||||||
<p><img src={logo} style={{maxWidth:'100%'}}/></p>
|
<p><Logo/></p>
|
||||||
|
|
||||||
<p>StateBuddy is an <a target="_blank" href="https://deemz.org/git/research/statebuddy">open source</a> tool for <a target="_blank" href="https://dl.acm.org/doi/10.1016/0167-6423(87)90035-9">Statechart</a> editing, simulation, (omniscient) debugging and testing.</p>
|
<p>StateBuddy is an <a target="_blank" href="https://deemz.org/git/research/statebuddy">open source</a> tool for <a target="_blank" href="https://dl.acm.org/doi/10.1016/0167-6423(87)90035-9">Statechart</a> editing, simulation, (omniscient) debugging and testing.</p>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,51 @@
|
||||||
details.active {
|
|
||||||
border: rgb(192, 125, 0);
|
|
||||||
background-color:rgb(255, 251, 244);
|
|
||||||
filter: drop-shadow( 0px 0px 3px rgba(192, 125, 0, 0.856));
|
|
||||||
}
|
|
||||||
|
|
||||||
details > summary {
|
details > summary {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* these two rules add a bit of padding to an opened <details> node */
|
|
||||||
/* details:open > summary:has(+ *) {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
details:open:has(>summary:has(+ *)) {
|
|
||||||
padding-bottom: 8px;
|
|
||||||
} */
|
|
||||||
|
|
||||||
details > summary:hover {
|
details > summary:hover {
|
||||||
background-color: #eee;
|
background-color: var(--summary-hover-bg-color);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.errorStatus details > summary:hover {
|
.errorStatus details > summary:hover {
|
||||||
background-color: rgb(102, 0, 0);
|
background-color: var(--error-hover-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stateTree > * {
|
.stateTree > * {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
/* border: 1px black solid; */
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
/* margin-bottom: 4px; */
|
|
||||||
/* padding-right: 2px; */
|
|
||||||
/* padding-top: 2px; */
|
|
||||||
/* padding-bottom: 2px; */
|
|
||||||
/* color: black; */
|
|
||||||
/* width: fit-content; */
|
|
||||||
/* border-radius: 10px; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if <details> has no children (besides the obvious <summary> child), then hide the marker */
|
|
||||||
/* details:not(:has(:not(summary))) > summary::marker {
|
|
||||||
content: " ";
|
|
||||||
} */
|
|
||||||
|
|
||||||
.outputEvent {
|
.outputEvent {
|
||||||
border: 1px black solid;
|
cursor: default;
|
||||||
|
border: 1px var(--separator-color) solid;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
/* margin-left: 4px; */
|
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
background-color: rgb(230, 249, 255);
|
background-color: var(--output-event-bg-color);
|
||||||
color: black;
|
color: var(--text-color);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.internalEvent {
|
.internalEvent {
|
||||||
border: 1px black solid;
|
cursor: default;
|
||||||
|
border: 1px var(--separator-color) solid;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
/* margin-left: 4px; */
|
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
background-color: rgb(255, 218, 252);
|
background-color: var(--internal-event-bg-color);
|
||||||
color: black;
|
color: var(--text-color);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputEvent {
|
.inputEvent {
|
||||||
border: 1px black solid;
|
border: 1px var(--separator-color) solid;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
/* margin-left: 4px; */
|
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
background-color: rgb(224, 247, 209);
|
background-color: var(--input-event-bg-color);
|
||||||
color: black;
|
color: var(--text-color);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.inputEvent:disabled {
|
.inputEvent:disabled {
|
||||||
|
|
@ -82,21 +55,24 @@ details > summary:hover {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
button.inputEvent:hover:not(:disabled) {
|
button.inputEvent:hover:not(:disabled) {
|
||||||
background-color: rgb(195, 224, 176);
|
background-color: var(--input-event-hover-bg-color);
|
||||||
}
|
}
|
||||||
button.inputEvent:active:not(:disabled) {
|
button.inputEvent:active:not(:disabled) {
|
||||||
background-color: rgb(176, 204, 158);
|
background-color: var(--input-event-active-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.activeState {
|
.activeState {
|
||||||
border: rgb(192, 125, 0);
|
/* border: rgb(192, 125, 0); */
|
||||||
background-color:rgb(255, 251, 244);
|
/* background-color:rgb(255, 251, 244); */
|
||||||
filter: drop-shadow( 0px 0px 3px rgba(192, 125, 0, 0.856));
|
border: var(--active-state-border-color) 1px solid;
|
||||||
|
background-color: var(--active-state-bg-color);
|
||||||
|
/* filter: drop-shadow( 0px 0px 3px rgba(192, 125, 0, 0.856)); */
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hr {
|
/* hr {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ import { RT_Statechart } from "@/statecharts/runtime_types";
|
||||||
import { Plant } from "../Plant/Plant";
|
import { Plant } from "../Plant/Plant";
|
||||||
import { TraceItem } from "../hooks/useSimulator";
|
import { TraceItem } from "../hooks/useSimulator";
|
||||||
|
|
||||||
// const endpoint = "http://localhost:15478/check_property";
|
const endpoint = "http://localhost:15478/check_property";
|
||||||
const endpoint = "https://deemz.org/apis/mtl-aas/check_property";
|
// const endpoint = "https://deemz.org/apis/mtl-aas/check_property";
|
||||||
|
|
||||||
export type PropertyTrace = {
|
export type PropertyTrace = {
|
||||||
timestamp: number,
|
timestamp: number,
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,19 @@ export function PseudoStateIcon(props: {}) {
|
||||||
${w - 1} ${h / 2},
|
${w - 1} ${h / 2},
|
||||||
${w / 2} ${h - 1},
|
${w / 2} ${h - 1},
|
||||||
${1} ${h / 2},
|
${1} ${h / 2},
|
||||||
`} fill="white" stroke="black" strokeWidth={1.2} />
|
`}
|
||||||
|
style={{
|
||||||
|
fill: 'var(--and-state-bg-color',
|
||||||
|
stroke: 'var(--rountangle-stroke-color',
|
||||||
|
}} strokeWidth={1.2} />
|
||||||
</svg>;
|
</svg>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HistoryIcon(props: { kind: "shallow" | "deep"; }) {
|
export function HistoryIcon(props: { kind: "shallow" | "deep"; }) {
|
||||||
const w = 20, h = 20;
|
const w = 20, h = 20;
|
||||||
const text = props.kind === "shallow" ? "H" : "H*";
|
const text = props.kind === "shallow" ? "H" : "H*";
|
||||||
return <svg width={w} height={h}><circle cx={w / 2} cy={h / 2} r={Math.min(w, h) / 2 - 1} fill="white" stroke="black" /><text x={w / 2} y={h / 2 + 4} textAnchor="middle" fontSize={11} fontWeight={400}>{text}</text></svg>;
|
return <svg width={w} height={h}><circle cx={w / 2} cy={h / 2} r={Math.min(w, h) / 2 - 1} style={{
|
||||||
|
fill: 'var(--and-state-bg-color',
|
||||||
|
stroke: 'var(--rountangle-stroke-color',
|
||||||
|
}}/><text x={w / 2} y={h / 2 + 4} style={{fill: 'var(--rountangle-stroke-color'}} textAnchor="middle" fontSize={11} fontWeight={400}>{text}</text></svg>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ import { TimerElapseEvent, Timers } from "../../statecharts/runtime_types";
|
||||||
import { getSimTime, setPaused, setRealtime, TimeMode } from "../../statecharts/time";
|
import { getSimTime, setPaused, setRealtime, TimeMode } from "../../statecharts/time";
|
||||||
import { InsertMode } from "./InsertModes";
|
import { InsertMode } from "./InsertModes";
|
||||||
import { About } from "../Modals/About";
|
import { About } from "../Modals/About";
|
||||||
import { EditHistory } from "../App";
|
import { EditHistory, LightMode } from "../App";
|
||||||
import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo";
|
import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo";
|
||||||
import { UndoRedoButtons } from "./UndoRedoButtons";
|
import { UndoRedoButtons } from "./UndoRedoButtons";
|
||||||
import { ZoomButtons } from "./ZoomButtons";
|
import { ZoomButtons } from "./ZoomButtons";
|
||||||
import { formatTime } from "../../util/util";
|
import { formatTime } from "../../util/util";
|
||||||
|
|
||||||
|
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||||
|
import LightModeIcon from '@mui/icons-material/LightMode';
|
||||||
|
import BrightnessAutoIcon from '@mui/icons-material/BrightnessAuto';
|
||||||
|
|
||||||
import AccessAlarmIcon from '@mui/icons-material/AccessAlarm';
|
import AccessAlarmIcon from '@mui/icons-material/AccessAlarm';
|
||||||
import CachedIcon from '@mui/icons-material/Cached';
|
import CachedIcon from '@mui/icons-material/Cached';
|
||||||
import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
|
import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
|
||||||
|
|
@ -33,6 +37,8 @@ export type TopPanelProps = {
|
||||||
onInit: () => void,
|
onInit: () => void,
|
||||||
onClear: () => void,
|
onClear: () => void,
|
||||||
onBack: () => void,
|
onBack: () => void,
|
||||||
|
lightMode: LightMode,
|
||||||
|
setLightMode: Dispatch<SetStateAction<LightMode>>,
|
||||||
insertMode: InsertMode,
|
insertMode: InsertMode,
|
||||||
setInsertMode: Dispatch<SetStateAction<InsertMode>>,
|
setInsertMode: Dispatch<SetStateAction<InsertMode>>,
|
||||||
setModal: Dispatch<SetStateAction<ReactElement|null>>,
|
setModal: Dispatch<SetStateAction<ReactElement|null>>,
|
||||||
|
|
@ -45,7 +51,7 @@ export type TopPanelProps = {
|
||||||
|
|
||||||
const ShortCutShowKeys = <kbd>~</kbd>;
|
const ShortCutShowKeys = <kbd>~</kbd>;
|
||||||
|
|
||||||
export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, onRedo, onRotate, onInit, onClear, onBack, insertMode, setInsertMode, setModal, zoom, setZoom, showKeys, setShowKeys, editHistory}: TopPanelProps) {
|
export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, onRedo, onRotate, onInit, onClear, onBack, lightMode, setLightMode, insertMode, setInsertMode, setModal, zoom, setZoom, showKeys, setShowKeys, editHistory}: TopPanelProps) {
|
||||||
const [displayTime, setDisplayTime] = useState("0.000");
|
const [displayTime, setDisplayTime] = useState("0.000");
|
||||||
const [timescale, setTimescale] = usePersistentState("timescale", 1);
|
const [timescale, setTimescale] = usePersistentState("timescale", 1);
|
||||||
|
|
||||||
|
|
@ -146,6 +152,20 @@ export const TopPanel = memo(function TopPanel({trace, time, setTime, onUndo, on
|
||||||
}, [config, time, onInit, onChangePaused, setShowKeys, onSkip, onBack, onClear]);
|
}, [config, time, onInit, onChangePaused, setShowKeys, onSkip, onBack, onClear]);
|
||||||
|
|
||||||
return <div className="toolbar">
|
return <div className="toolbar">
|
||||||
|
{/* light / dark mode */}
|
||||||
|
<div className="toolbarGroup">
|
||||||
|
<button title="force light mode" className={lightMode==="light"?"active":""} onClick={() => setLightMode("light")}>
|
||||||
|
<LightModeIcon fontSize="small"/>
|
||||||
|
</button>
|
||||||
|
<button title="auto light / dark mode (follows system theme)" className={lightMode==="auto"?"active":""} onClick={() => setLightMode("auto")}>
|
||||||
|
<BrightnessAutoIcon fontSize="small"/>
|
||||||
|
</button>
|
||||||
|
<button title="force dark mode" className={lightMode==="dark"?"active":""} onClick={() => setLightMode("dark")}>
|
||||||
|
<DarkModeIcon fontSize="small"/>
|
||||||
|
</button>
|
||||||
|
 
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* shortcuts / about */}
|
{/* shortcuts / about */}
|
||||||
<div className="toolbarGroup">
|
<div className="toolbarGroup">
|
||||||
<KeyInfo keyInfo={ShortCutShowKeys}>
|
<KeyInfo keyInfo={ShortCutShowKeys}>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ export const DiamondShape = memo(function DiamondShape(props: {size: Vec2D, extr
|
||||||
${minSize.x/2} ${minSize.y},
|
${minSize.x/2} ${minSize.y},
|
||||||
${0} ${minSize.y/2}
|
${0} ${minSize.y/2}
|
||||||
`}
|
`}
|
||||||
fill="white"
|
style={{fill: 'var(--and-state-bg-color', stroke: 'var(--rountangle-stroke-color)'}}
|
||||||
|
// fill="white"
|
||||||
stroke="black"
|
stroke="black"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
{...props.extraAttrs}
|
{...props.extraAttrs}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
.svgCanvas {
|
.svgCanvas {
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
background-color: #eee;
|
background-color: var(--or-state-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.svgCanvas.dragging {
|
.svgCanvas.dragging {
|
||||||
|
|
@ -19,16 +19,15 @@
|
||||||
|
|
||||||
/* rectangle drawn while a selection is being made */
|
/* rectangle drawn while a selection is being made */
|
||||||
.selecting {
|
.selecting {
|
||||||
fill: blue;
|
fill: var(--light-accent-color);
|
||||||
fill-opacity: 0.2;
|
|
||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
stroke:black;
|
stroke: var(--accent-border-color);
|
||||||
stroke-dasharray: 7 6;
|
stroke-dasharray: 7 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rountangle {
|
.rountangle {
|
||||||
fill: white;
|
fill: var(--and-state-bg-color);
|
||||||
stroke: black;
|
stroke: var(--rountangle-stroke-color);
|
||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,9 +38,10 @@
|
||||||
stroke: var(--error-color);
|
stroke: var(--error-color);
|
||||||
}
|
}
|
||||||
.rountangle.active {
|
.rountangle.active {
|
||||||
stroke: rgb(205, 133, 0);
|
stroke: var(--active-state-border-color);
|
||||||
/* stroke: none; */
|
/* stroke: none; */
|
||||||
fill:rgb(255, 240, 214);
|
/* fill:rgb(255, 240, 214); */
|
||||||
|
fill: var(--active-state-bg-color);
|
||||||
/* filter: drop-shadow( 2px 2px 2px rgba(124, 37, 10, 0.729)); */
|
/* filter: drop-shadow( 2px 2px 2px rgba(124, 37, 10, 0.729)); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,8 +54,7 @@ line.helper {
|
||||||
stroke-width: 16px;
|
stroke-width: 16px;
|
||||||
}
|
}
|
||||||
line.helper:hover:not(:active) {
|
line.helper:hover:not(:active) {
|
||||||
stroke: blue;
|
stroke: var(--light-accent-color);
|
||||||
stroke-opacity: 0.2;
|
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,8 +64,7 @@ path.helper {
|
||||||
stroke-width: 16px;
|
stroke-width: 16px;
|
||||||
}
|
}
|
||||||
path.helper:hover:not(:active) {
|
path.helper:hover:not(:active) {
|
||||||
stroke: blue;
|
stroke: var(--light-accent-color);
|
||||||
stroke-opacity: 0.2;
|
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,23 +72,22 @@ circle.helper {
|
||||||
fill: rgba(0, 0, 0, 0);
|
fill: rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
circle.helper:hover:not(:active) {
|
circle.helper:hover:not(:active) {
|
||||||
fill: blue;
|
fill: var(--light-accent-color);
|
||||||
fill-opacity: 0.2;
|
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rountangle.or {
|
.rountangle.or {
|
||||||
stroke-dasharray: 7 6;
|
stroke-dasharray: 7 6;
|
||||||
fill: #eee;
|
fill: var(--or-state-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: black;
|
stroke: var(--rountangle-stroke-color);
|
||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
}
|
}
|
||||||
.arrow.selected {
|
.arrow.selected {
|
||||||
stroke: blue;
|
stroke: var(--accent-border-color);
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,34 +107,29 @@ circle.helper:hover:not(:active) {
|
||||||
}
|
}
|
||||||
|
|
||||||
line.selected, circle.selected {
|
line.selected, circle.selected {
|
||||||
fill: rgba(0, 0, 255, 0.2);
|
fill: var(--light-accent-color);
|
||||||
/* stroke-dasharray: 7 6; */
|
stroke: var(--accent-border-color);
|
||||||
stroke: blue;
|
|
||||||
stroke-width: 4px;
|
stroke-width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.draggableText.selected, .draggableText.selected:hover {
|
.draggableText.selected, .draggableText.selected:hover {
|
||||||
fill: blue;
|
fill: var(--accent-border-color);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.draggableText:hover:not(:active) {
|
|
||||||
/* fill: blue; */
|
|
||||||
/* cursor: grab; */
|
|
||||||
}
|
|
||||||
text.helper {
|
text.helper {
|
||||||
fill: rgba(0,0,0,0);
|
fill: rgba(0,0,0,0);
|
||||||
stroke: rgba(0,0,0,0);
|
stroke: rgba(0,0,0,0);
|
||||||
stroke-width: 6px;
|
stroke-width: 6px;
|
||||||
}
|
}
|
||||||
text.helper:hover {
|
text.helper:hover {
|
||||||
stroke: blue;
|
stroke: var(--light-accent-color);
|
||||||
stroke-opacity: 0.2;
|
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
.draggableText, .draggableText.highlight {
|
.draggableText, .draggableText.highlight {
|
||||||
paint-order: stroke;
|
paint-order: stroke;
|
||||||
stroke: white;
|
fill: var(--text-color);
|
||||||
|
stroke: var(--background-color);
|
||||||
stroke-width: 4px;
|
stroke-width: 4px;
|
||||||
stroke-linecap: butt;
|
stroke-linecap: butt;
|
||||||
stroke-linejoin: miter;
|
stroke-linejoin: miter;
|
||||||
|
|
@ -146,12 +138,16 @@ text.helper:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.draggableText.highlight:not(.selected) {
|
.draggableText.highlight:not(.selected) {
|
||||||
fill: green;
|
fill: var(--associated-color);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.draggableText.selected {
|
||||||
|
fill: var(--accent-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.highlight:not(.selected):not(text) {
|
.highlight:not(.selected):not(text) {
|
||||||
stroke: green;
|
stroke: var(--associated-color);
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
fill: none;
|
fill: none;
|
||||||
}
|
}
|
||||||
|
|
@ -160,19 +156,19 @@ text.helper:hover {
|
||||||
stroke: var(--error-color);
|
stroke: var(--error-color);
|
||||||
}
|
}
|
||||||
.arrow.fired {
|
.arrow.fired {
|
||||||
stroke: rgb(160 0 168);
|
stroke: var(--fired-transition-color);
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
animation: blinkTransition 1s;
|
animation: blinkTransition 1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blinkTransition {
|
@keyframes blinkTransition {
|
||||||
0% {
|
0% {
|
||||||
stroke: rgb(255, 128, 9);
|
stroke: var(--firing-transition-color);
|
||||||
stroke-width: 6px;
|
stroke-width: 6px;
|
||||||
filter: drop-shadow(0 0 5px rgba(255, 128, 9, 1));
|
filter: drop-shadow(0 0 5px var(--firing-transition-color));
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
stroke: rgb(160 0 168);
|
stroke: var(--fired-transition-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,5 +187,5 @@ g:hover > .errorHover {
|
||||||
}
|
}
|
||||||
|
|
||||||
text.uid {
|
text.uid {
|
||||||
fill: lightgrey;
|
fill: var(--separator-color);
|
||||||
}
|
}
|
||||||
|
|
@ -11,8 +11,6 @@ export function useMouse(makeCheckPoint: () => void, insertMode: InsertMode, zoo
|
||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
const [shiftOrCtrlPressed, setShiftOrCtrlPressed] = useState(false);
|
const [shiftOrCtrlPressed, setShiftOrCtrlPressed] = useState(false);
|
||||||
|
|
||||||
console.log(shiftOrCtrlPressed);
|
|
||||||
|
|
||||||
// not null while the user is making a selection
|
// not null while the user is making a selection
|
||||||
const [selectingState, setSelectingState] = useState<SelectingState>(null);
|
const [selectingState, setSelectingState] = useState<SelectingState>(null);
|
||||||
|
|
||||||
|
|
@ -347,17 +345,19 @@ export function useMouse(makeCheckPoint: () => void, insertMode: InsertMode, zoo
|
||||||
...state,
|
...state,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
selection: [
|
selection: [
|
||||||
...state.rountangles.map(r => ["left", "top", "right", "bottom"].map(part => ({uid: r.uid, part}))),
|
...state.rountangles.flatMap(r => ["left", "top", "right", "bottom"].map(part => ({uid: r.uid, part}))),
|
||||||
...state.diamonds.map(d => ["left", "top", "right", "bottom"].map(part => ({uid: d.uid, part}))),
|
...state.diamonds.flatMap(d => ["left", "top", "right", "bottom"].map(part => ({uid: d.uid, part}))),
|
||||||
...state.arrows.map(a => ["start", "end"].map(part => ({uid: a.uid, part}))),
|
...state.arrows.flatMap(a => ["start", "end"].map(part => ({uid: a.uid, part}))),
|
||||||
...state.texts.map(t => ({uid: t.uid, part: "text"})),
|
...state.texts.map(t => ({uid: t.uid, part: "text"})),
|
||||||
...state.history.map(h => ({uid: h.uid, part: "history"})),
|
...state.history.map(h => ({uid: h.uid, part: "history"})),
|
||||||
]
|
]
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [makeCheckPoint, deleteSelection, setState, setDragging]);
|
}, [makeCheckPoint, deleteSelection, setState, setDragging]);
|
||||||
|
|
||||||
|
console.log(state.selection);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// mousemove and mouseup are global event handlers so they keep working when pointer is outside of browser window
|
// mousemove and mouseup are global event handlers so they keep working when pointer is outside of browser window
|
||||||
window.addEventListener("mouseup", onMouseUp);
|
window.addEventListener("mouseup", onMouseUp);
|
||||||
|
|
|
||||||
11
src/Logo/Logo.tsx
Normal file
11
src/Logo/Logo.tsx
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -5,9 +5,44 @@ html, body {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
:root {
|
||||||
/* --error-color: darkred; */
|
color-scheme: light dark;
|
||||||
--error-color: rgb(163, 0, 0);
|
|
||||||
|
--background-color: light-dark(white, rgb(26, 26, 26));
|
||||||
|
--text-color: light-dark(black, white);
|
||||||
|
--error-color: light-dark(rgb(163, 0, 0), rgb(255, 82, 82));
|
||||||
|
--error-bg-color: light-dark(lightpink, rgb(75, 0, 0));
|
||||||
|
--error-hover-bg-color: light-dark(rgb(102, 0, 0), rgb(102, 0, 0));
|
||||||
|
--light-accent-color: light-dark(rgba(0,0,255,0.2), rgba(78, 186, 248, 0.377));
|
||||||
|
--accent-border-color: light-dark(blue, rgb(64, 185, 255));
|
||||||
|
--separator-color: light-dark(lightgrey, rgb(44, 44, 44));
|
||||||
|
--inactive-bg-color: light-dark(#f7f7f7, rgb(29, 29, 29));
|
||||||
|
--inactive-fg-color: light-dark(grey, rgb(70, 70, 70));
|
||||||
|
--button-bg-color: light-dark(#fcfcfc, rgb(20, 20, 20));
|
||||||
|
--modal-backdrop-color: light-dark(rgba(200,200,200,0.7), rgba(59, 7, 7, 0.849));
|
||||||
|
--status-inactive-color: light-dark(grey, grey);
|
||||||
|
--status-ok-color: light-dark(forestgreen, forestgreen);
|
||||||
|
--or-state-bg-color: light-dark(#eee, #1a1a1a);
|
||||||
|
--and-state-bg-color: light-dark(white, rgb(0, 0, 0));
|
||||||
|
--rountangle-stroke-color: light-dark(black, #d4d4d4);
|
||||||
|
--active-state-bg-color: light-dark(rgb(255, 240, 214), rgb(53, 37, 18));
|
||||||
|
--active-state-border-color: light-dark(rgb(205, 133, 0), rgb(235, 124, 21));
|
||||||
|
--fired-transition-color: light-dark(rgb(160, 0, 168), rgb(160, 0, 168));
|
||||||
|
--firing-transition-color: light-dark(rgba(255, 128, 9, 1), rgba(255, 128, 9, 1));
|
||||||
|
--associated-color: light-dark(green, rgb(186, 245, 119));
|
||||||
|
--bottom-panel-bg-color: light-dark(rgb(255, 249, 235), rgb(41, 4, 4));
|
||||||
|
--summary-hover-bg-color: light-dark(#eee, #242424);
|
||||||
|
--internal-event-bg-color: light-dark(rgb(255, 218, 252), rgb(99, 27, 94));
|
||||||
|
--input-event-bg-color: light-dark(rgb(224, 247, 209), rgb(59, 95, 37));
|
||||||
|
--input-event-hover-bg-color: light-dark(rgb(195, 224, 176), rgb(59, 88, 40));
|
||||||
|
--input-event-active-bg-color: light-dark(rgb(176, 204, 158), rgb(77, 117, 53));
|
||||||
|
--output-event-bg-color: light-dark(rgb(230, 249, 255), rgb(28, 83, 104));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for some reason i need to add this or some elements are rendered in OS color rather than 'forced' color */
|
||||||
|
div {
|
||||||
|
color: var(--text-color);
|
||||||
|
background-color: var(--background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
div#root {
|
div#root {
|
||||||
|
|
@ -27,17 +62,18 @@ kbd {
|
||||||
box-shadow: inset 0 -1.5px 0 #aaa;
|
box-shadow: inset 0 -1.5px 0 #aaa;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
kbd:active { transform: translateY(1px); }
|
kbd:active { transform: translateY(1px); }
|
||||||
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
/* border: solid blue 2px; */
|
/* border: solid blue 2px; */
|
||||||
accent-color: rgba(0,0,255,0.2);
|
accent-color: var(--light-accent-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
background-color: rgba(0,0,255,0.2);
|
background-color: var(--light-accent-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue