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) {
|
||||
border-bottom: 1px lightgrey solid;
|
||||
border-bottom: 1px var(--separator-color) solid;
|
||||
}
|
||||
|
||||
.runtimeState {
|
||||
padding: 4px;
|
||||
/* padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px; */
|
||||
}
|
||||
|
||||
.runtimeState:has(+.runtimeState) {
|
||||
border-bottom: 1px lightgrey solid;
|
||||
border-bottom: 1px var(--separator-color) solid;
|
||||
}
|
||||
.runtimeState:has(+.runtimeState.active) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.runtimeState:hover {
|
||||
/* background-color: rgba(255, 140, 0, 0.2); */
|
||||
background-color: rgba(0,0,255,0.2);
|
||||
background-color: var(--light-accent-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.runtimeState.active {
|
||||
background-color: rgba(0,0,255,0.2);
|
||||
border: solid blue 1px;
|
||||
background-color: var(--light-accent-color);
|
||||
border: solid var(--accent-border-color) 1px;
|
||||
}
|
||||
.runtimeState.plantStep:not(.active) {
|
||||
background-color: #f7f7f7;
|
||||
background-color: var(--inactive-bg-color);
|
||||
}
|
||||
.runtimeState.plantStep * {
|
||||
color: grey;
|
||||
color: var(--inactive-fg-color);
|
||||
}
|
||||
|
||||
.runtimeState.runtimeError {
|
||||
background-color: lightpink;
|
||||
color: darkred;
|
||||
background-color: var(--error-bg-color);
|
||||
color: var(--error-color); /* used to be darkred, but this one's a bit lighter */
|
||||
}
|
||||
|
||||
.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 {
|
||||
width: 56;
|
||||
background-color:"#eee";
|
||||
text-align: "right";
|
||||
}
|
||||
|
||||
|
|
@ -78,20 +61,23 @@ details:has(+ details) {
|
|||
}
|
||||
|
||||
button {
|
||||
background-color: #fcfcfc;
|
||||
border: 1px lightgrey solid;
|
||||
background-color: var(--button-bg-color);
|
||||
border: 1px var(--separator-color) solid;
|
||||
}
|
||||
|
||||
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 {
|
||||
border: solid blue 1px;
|
||||
background-color: rgba(0,0,255,0.2);
|
||||
/* margin-right: 1px; */
|
||||
/* margin-left: 0; */
|
||||
color: black;
|
||||
border: solid var(--accent-border-color) 1px;
|
||||
background-color: var(--light-accent-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.modalOuter {
|
||||
|
|
@ -102,7 +88,7 @@ button.active {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background-color: rgba(200,200,200,0.7);
|
||||
background-color: var(--modal-backdrop-color);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +96,7 @@ button.active {
|
|||
position: relative;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
background-color: white;
|
||||
background-color: var(--background-color);
|
||||
max-height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
@ -128,7 +114,7 @@ div.stackHorizontal {
|
|||
div.status {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-color: grey;
|
||||
background-color: var(--status-inactive-color);
|
||||
border-radius: 50%;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
|
|
@ -141,6 +127,6 @@ div.status.violated {
|
|||
}
|
||||
|
||||
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 { emptyState } from "@/statecharts/concrete_syntax";
|
||||
import { ModalOverlay } from "./Modals/ModalOverlay";
|
||||
import { usePersistentState } from "@/hooks/usePersistentState";
|
||||
|
||||
export type EditHistory = {
|
||||
current: VisualEditorState,
|
||||
|
|
@ -38,10 +39,14 @@ const defaultAppState: AppState = {
|
|||
...defaultSideBarState,
|
||||
}
|
||||
|
||||
export type LightMode = "light" | "auto" | "dark";
|
||||
|
||||
export function App() {
|
||||
const [editHistory, setEditHistory] = useState<EditHistory|null>(null);
|
||||
const [modal, setModal] = useState<ReactElement|null>(null);
|
||||
|
||||
const [lightMode, setLightMode] = usePersistentState<LightMode>("lightMode", "auto");
|
||||
|
||||
const {makeCheckPoint, onRedo, onUndo, onRotate} = useEditor(setEditHistory);
|
||||
|
||||
const editorState = editHistory && editHistory.current;
|
||||
|
|
@ -135,7 +140,8 @@ export function App() {
|
|||
|
||||
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 */}
|
||||
<div className="stackVertical" style={{height:'100%'}}>
|
||||
|
||||
|
|
@ -150,7 +156,7 @@ export function App() {
|
|||
style={{flex: '0 0 content'}}
|
||||
>
|
||||
{editHistory && <TopPanel
|
||||
{...{onUndo, onRedo, onRotate, setModal, editHistory, ...simulator, ...setters, ...appState}}
|
||||
{...{onUndo, onRedo, onRotate, lightMode, setLightMode, setModal, editHistory, ...simulator, ...setters, ...appState}}
|
||||
/>}
|
||||
</div>
|
||||
{/* Editor */}
|
||||
|
|
@ -179,7 +185,8 @@ export function App() {
|
|||
{syntaxErrors && <BottomPanel {...{errors: syntaxErrors}}/>}
|
||||
</div>
|
||||
</div>
|
||||
</ModalOverlay>;
|
||||
</ModalOverlay>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
}
|
||||
|
||||
.bottom {
|
||||
border-top: 1px lightgrey solid;
|
||||
background-color: rgb(255, 249, 235);
|
||||
}
|
||||
border-top: 1px var(--separator-color) solid;
|
||||
background-color: var(--bottom-panel-bg-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { TraceableError } from "../../statecharts/parser";
|
|||
|
||||
import "./BottomPanel.css";
|
||||
|
||||
import logo from "../../../artwork/logo-playful.svg";
|
||||
import { PersistentDetailsLocalStorage } from "../PersistentDetails";
|
||||
import { Logo } from "@/Logo/Logo";
|
||||
|
||||
export function BottomPanel(props: {errors: TraceableError[]}) {
|
||||
const [greeting, setGreeting] = useState(
|
||||
<div style={{textAlign:'center'}}>
|
||||
<span style={{fontSize: 18, fontStyle: 'italic'}}>
|
||||
Welcome to <img src={logo} style={{maxWidth:'100%'}}/>
|
||||
Welcome to <Logo/>
|
||||
</span>
|
||||
</div>);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Logo } from "@/Logo/Logo";
|
||||
import { Dispatch, ReactElement, SetStateAction } from "react";
|
||||
import logo from "../../../artwork/logo-playful.svg";
|
||||
|
||||
export function About(props: {setModal: Dispatch<SetStateAction<ReactElement|null>>}) {
|
||||
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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
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 {
|
||||
background-color: #eee;
|
||||
background-color: var(--summary-hover-bg-color);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.errorStatus details > summary:hover {
|
||||
background-color: rgb(102, 0, 0);
|
||||
background-color: var(--error-hover-bg-color);
|
||||
}
|
||||
|
||||
.stateTree > * {
|
||||
padding-left: 10px;
|
||||
/* border: 1px black solid; */
|
||||
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 {
|
||||
border: 1px black solid;
|
||||
cursor: default;
|
||||
border: 1px var(--separator-color) solid;
|
||||
border-radius: 6px;
|
||||
/* margin-left: 4px; */
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
background-color: rgb(230, 249, 255);
|
||||
color: black;
|
||||
background-color: var(--output-event-bg-color);
|
||||
color: var(--text-color);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.internalEvent {
|
||||
border: 1px black solid;
|
||||
cursor: default;
|
||||
border: 1px var(--separator-color) solid;
|
||||
border-radius: 6px;
|
||||
/* margin-left: 4px; */
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
background-color: rgb(255, 218, 252);
|
||||
color: black;
|
||||
background-color: var(--internal-event-bg-color);
|
||||
color: var(--text-color);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.inputEvent {
|
||||
border: 1px black solid;
|
||||
border: 1px var(--separator-color) solid;
|
||||
border-radius: 6px;
|
||||
/* margin-left: 4px; */
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
background-color: rgb(224, 247, 209);
|
||||
color: black;
|
||||
background-color: var(--input-event-bg-color);
|
||||
color: var(--text-color);
|
||||
display: inline-block;
|
||||
}
|
||||
.inputEvent:disabled {
|
||||
|
|
@ -82,21 +55,24 @@ details > summary:hover {
|
|||
vertical-align: middle;
|
||||
}
|
||||
button.inputEvent:hover:not(:disabled) {
|
||||
background-color: rgb(195, 224, 176);
|
||||
background-color: var(--input-event-hover-bg-color);
|
||||
}
|
||||
button.inputEvent:active:not(:disabled) {
|
||||
background-color: rgb(176, 204, 158);
|
||||
background-color: var(--input-event-active-bg-color);
|
||||
}
|
||||
|
||||
.activeState {
|
||||
border: rgb(192, 125, 0);
|
||||
background-color:rgb(255, 251, 244);
|
||||
filter: drop-shadow( 0px 0px 3px rgba(192, 125, 0, 0.856));
|
||||
/* border: rgb(192, 125, 0); */
|
||||
/* background-color:rgb(255, 251, 244); */
|
||||
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;
|
||||
margin-left: 4px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
display: inline-block;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* hr {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { RT_Statechart } from "@/statecharts/runtime_types";
|
|||
import { Plant } from "../Plant/Plant";
|
||||
import { TraceItem } from "../hooks/useSimulator";
|
||||
|
||||
// const endpoint = "http://localhost:15478/check_property";
|
||||
const endpoint = "https://deemz.org/apis/mtl-aas/check_property";
|
||||
const endpoint = "http://localhost:15478/check_property";
|
||||
// const endpoint = "https://deemz.org/apis/mtl-aas/check_property";
|
||||
|
||||
export type PropertyTrace = {
|
||||
timestamp: number,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,19 @@ export function PseudoStateIcon(props: {}) {
|
|||
${w - 1} ${h / 2},
|
||||
${w / 2} ${h - 1},
|
||||
${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>;
|
||||
}
|
||||
|
||||
export function HistoryIcon(props: { kind: "shallow" | "deep"; }) {
|
||||
const w = 20, h = 20;
|
||||
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 { InsertMode } from "./InsertModes";
|
||||
import { About } from "../Modals/About";
|
||||
import { EditHistory } from "../App";
|
||||
import { EditHistory, LightMode } from "../App";
|
||||
import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo";
|
||||
import { UndoRedoButtons } from "./UndoRedoButtons";
|
||||
import { ZoomButtons } from "./ZoomButtons";
|
||||
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 CachedIcon from '@mui/icons-material/Cached';
|
||||
import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
|
||||
|
|
@ -33,6 +37,8 @@ export type TopPanelProps = {
|
|||
onInit: () => void,
|
||||
onClear: () => void,
|
||||
onBack: () => void,
|
||||
lightMode: LightMode,
|
||||
setLightMode: Dispatch<SetStateAction<LightMode>>,
|
||||
insertMode: InsertMode,
|
||||
setInsertMode: Dispatch<SetStateAction<InsertMode>>,
|
||||
setModal: Dispatch<SetStateAction<ReactElement|null>>,
|
||||
|
|
@ -45,7 +51,7 @@ export type TopPanelProps = {
|
|||
|
||||
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 [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]);
|
||||
|
||||
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 */}
|
||||
<div className="toolbarGroup">
|
||||
<KeyInfo keyInfo={ShortCutShowKeys}>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ export const DiamondShape = memo(function DiamondShape(props: {size: Vec2D, extr
|
|||
${minSize.x/2} ${minSize.y},
|
||||
${0} ${minSize.y/2}
|
||||
`}
|
||||
fill="white"
|
||||
style={{fill: 'var(--and-state-bg-color', stroke: 'var(--rountangle-stroke-color)'}}
|
||||
// fill="white"
|
||||
stroke="black"
|
||||
strokeWidth={2}
|
||||
{...props.extraAttrs}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.svgCanvas {
|
||||
cursor: crosshair;
|
||||
background-color: #eee;
|
||||
background-color: var(--or-state-bg-color);
|
||||
}
|
||||
|
||||
.svgCanvas.dragging {
|
||||
|
|
@ -19,16 +19,15 @@
|
|||
|
||||
/* rectangle drawn while a selection is being made */
|
||||
.selecting {
|
||||
fill: blue;
|
||||
fill-opacity: 0.2;
|
||||
fill: var(--light-accent-color);
|
||||
stroke-width: 1px;
|
||||
stroke:black;
|
||||
stroke: var(--accent-border-color);
|
||||
stroke-dasharray: 7 6;
|
||||
}
|
||||
|
||||
.rountangle {
|
||||
fill: white;
|
||||
stroke: black;
|
||||
fill: var(--and-state-bg-color);
|
||||
stroke: var(--rountangle-stroke-color);
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
|
|
@ -39,9 +38,10 @@
|
|||
stroke: var(--error-color);
|
||||
}
|
||||
.rountangle.active {
|
||||
stroke: rgb(205, 133, 0);
|
||||
stroke: var(--active-state-border-color);
|
||||
/* 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)); */
|
||||
}
|
||||
|
||||
|
|
@ -54,8 +54,7 @@ line.helper {
|
|||
stroke-width: 16px;
|
||||
}
|
||||
line.helper:hover:not(:active) {
|
||||
stroke: blue;
|
||||
stroke-opacity: 0.2;
|
||||
stroke: var(--light-accent-color);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
|
|
@ -65,8 +64,7 @@ path.helper {
|
|||
stroke-width: 16px;
|
||||
}
|
||||
path.helper:hover:not(:active) {
|
||||
stroke: blue;
|
||||
stroke-opacity: 0.2;
|
||||
stroke: var(--light-accent-color);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
|
|
@ -74,23 +72,22 @@ circle.helper {
|
|||
fill: rgba(0, 0, 0, 0);
|
||||
}
|
||||
circle.helper:hover:not(:active) {
|
||||
fill: blue;
|
||||
fill-opacity: 0.2;
|
||||
fill: var(--light-accent-color);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.rountangle.or {
|
||||
stroke-dasharray: 7 6;
|
||||
fill: #eee;
|
||||
fill: var(--or-state-bg-color);
|
||||
}
|
||||
|
||||
.arrow {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke: var(--rountangle-stroke-color);
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.arrow.selected {
|
||||
stroke: blue;
|
||||
stroke: var(--accent-border-color);
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
|
|
@ -110,34 +107,29 @@ circle.helper:hover:not(:active) {
|
|||
}
|
||||
|
||||
line.selected, circle.selected {
|
||||
fill: rgba(0, 0, 255, 0.2);
|
||||
/* stroke-dasharray: 7 6; */
|
||||
stroke: blue;
|
||||
fill: var(--light-accent-color);
|
||||
stroke: var(--accent-border-color);
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
.draggableText.selected, .draggableText.selected:hover {
|
||||
fill: blue;
|
||||
fill: var(--accent-border-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
.draggableText:hover:not(:active) {
|
||||
/* fill: blue; */
|
||||
/* cursor: grab; */
|
||||
}
|
||||
text.helper {
|
||||
fill: rgba(0,0,0,0);
|
||||
stroke: rgba(0,0,0,0);
|
||||
stroke-width: 6px;
|
||||
}
|
||||
text.helper:hover {
|
||||
stroke: blue;
|
||||
stroke-opacity: 0.2;
|
||||
stroke: var(--light-accent-color);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.draggableText, .draggableText.highlight {
|
||||
paint-order: stroke;
|
||||
stroke: white;
|
||||
fill: var(--text-color);
|
||||
stroke: var(--background-color);
|
||||
stroke-width: 4px;
|
||||
stroke-linecap: butt;
|
||||
stroke-linejoin: miter;
|
||||
|
|
@ -146,12 +138,16 @@ text.helper:hover {
|
|||
}
|
||||
|
||||
.draggableText.highlight:not(.selected) {
|
||||
fill: green;
|
||||
fill: var(--associated-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.draggableText.selected {
|
||||
fill: var(--accent-border-color);
|
||||
}
|
||||
|
||||
.highlight:not(.selected):not(text) {
|
||||
stroke: green;
|
||||
stroke: var(--associated-color);
|
||||
stroke-width: 3px;
|
||||
fill: none;
|
||||
}
|
||||
|
|
@ -160,19 +156,19 @@ text.helper:hover {
|
|||
stroke: var(--error-color);
|
||||
}
|
||||
.arrow.fired {
|
||||
stroke: rgb(160 0 168);
|
||||
stroke: var(--fired-transition-color);
|
||||
stroke-width: 3px;
|
||||
animation: blinkTransition 1s;
|
||||
}
|
||||
|
||||
@keyframes blinkTransition {
|
||||
0% {
|
||||
stroke: rgb(255, 128, 9);
|
||||
stroke: var(--firing-transition-color);
|
||||
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% {
|
||||
stroke: rgb(160 0 168);
|
||||
stroke: var(--fired-transition-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,5 +187,5 @@ g:hover > .errorHover {
|
|||
}
|
||||
|
||||
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 [shiftOrCtrlPressed, setShiftOrCtrlPressed] = useState(false);
|
||||
|
||||
console.log(shiftOrCtrlPressed);
|
||||
|
||||
// not null while the user is making a selection
|
||||
const [selectingState, setSelectingState] = useState<SelectingState>(null);
|
||||
|
||||
|
|
@ -347,17 +345,19 @@ export function useMouse(makeCheckPoint: () => void, insertMode: InsertMode, zoo
|
|||
...state,
|
||||
// @ts-ignore
|
||||
selection: [
|
||||
...state.rountangles.map(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.arrows.map(a => ["start", "end"].map(part => ({uid: a.uid, part}))),
|
||||
...state.texts.map(t => ({uid: t.uid, part: "text"})),
|
||||
...state.history.map(h => ({uid: h.uid, part: "history"})),
|
||||
]
|
||||
...state.rountangles.flatMap(r => ["left", "top", "right", "bottom"].map(part => ({uid: r.uid, part}))),
|
||||
...state.diamonds.flatMap(d => ["left", "top", "right", "bottom"].map(part => ({uid: d.uid, part}))),
|
||||
...state.arrows.flatMap(a => ["start", "end"].map(part => ({uid: a.uid, part}))),
|
||||
...state.texts.map(t => ({uid: t.uid, part: "text"})),
|
||||
...state.history.map(h => ({uid: h.uid, part: "history"})),
|
||||
]
|
||||
}))
|
||||
}
|
||||
}
|
||||
}, [makeCheckPoint, deleteSelection, setState, setDragging]);
|
||||
|
||||
console.log(state.selection);
|
||||
|
||||
useEffect(() => {
|
||||
// mousemove and mouseup are global event handlers so they keep working when pointer is outside of browser window
|
||||
window.addEventListener("mouseup", onMouseUp);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue