diff --git a/client/src/App.tsx b/client/src/App.tsx index d701443..c1eb545 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -10,18 +10,10 @@ import '@fontsource/roboto/700.css'; import './reset.css'; import './app.css'; -type SetTitleType = {setTitle: (string) => void, setSubtitle: (string) => void} -export const SetTitleContext = React.createContext({setTitle: () => {}, setSubtitle: () => {}}) - function App() { - const [title, setTitle] = useState("") - const [subtitle, setSubtitle] = useState("") - return (
- - - +
) } diff --git a/client/src/app.css b/client/src/app.css index c65b42a..5292e3d 100644 --- a/client/src/app.css +++ b/client/src/app.css @@ -35,15 +35,22 @@ code { } .btn { + line-height: inherit; text-decoration: none; - color: var(--clr-primary); - background: white; + background: var(--clr-primary); + color: white; display: inline-block; border-radius: 0.2em; - padding: 0.2em .6em; + padding: 0.2rem .6em; font-size: 1rem; margin: 0 .2em; border: 0; + cursor: pointer; +} + +.btn-inverted { + color: var(--clr-primary); + background: white; } .btn-disabled, .btn[disabled] { @@ -63,7 +70,6 @@ code { } .app-bar { - z-index: 1500; flex: 0; background: var(--clr-primary); display: flex; diff --git a/client/src/components/Button.tsx b/client/src/components/Button.tsx index 2035744..1f63c77 100644 --- a/client/src/components/Button.tsx +++ b/client/src/components/Button.tsx @@ -3,12 +3,13 @@ import { Link, LinkProps } from "react-router-dom"; export interface ButtonProps extends LinkProps { disabled?: boolean + inverted?: boolean } export function Button(props: ButtonProps) { if (props.disabled) { - return {props.children} + return {props.children} } else { - return {props.children} + return {props.children} } } diff --git a/client/src/components/Level.tsx b/client/src/components/Level.tsx index 16313bb..b685944 100644 --- a/client/src/components/Level.tsx +++ b/client/src/components/Level.tsx @@ -33,13 +33,10 @@ import { Main } from './infoview/main' import type { Location } from 'vscode-languageserver-protocol'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faHome, faArrowRight, faArrowLeft } from '@fortawesome/free-solid-svg-icons' +import { faHome, faArrowRight, faArrowLeft, faRotateLeft } from '@fortawesome/free-solid-svg-icons' import { styled, useTheme, Theme, CSSObject } from '@mui/material/styles'; -import { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'; -import Divider from '@mui/material/Divider'; import Markdown from './Markdown'; -import { SetTitleContext } from '../App'; import Split from 'react-split' @@ -73,6 +70,40 @@ function Level() { introductionPanelRef.current!.scrollTo(0,0) }, [levelId]) + React.useEffect(() => { + if (!commandLineMode) { + // Delete last input attempt from command line + editor.executeEdits("command-line", [{ + range: editor.getSelection(), + text: "", + forceMoveMarkers: false + }]); + editor.focus() + } + }, [commandLineMode]) + + const handleUndo = () => { + const endPos = editor.getModel().getFullModelRange().getEndPosition() + let range + console.log(endPos.column) + if (endPos.column === 1) { + range = monaco.Selection.fromPositions( + new monaco.Position(endPos.lineNumber - 1, 1), + endPos + ) + } else { + range = monaco.Selection.fromPositions( + new monaco.Position(endPos.lineNumber, 1), + endPos + ) + } + editor.executeEdits("undo-button", [{ + range, + text: "", + forceMoveMarkers: false + }]); + } + const connection = React.useContext(ConnectionContext) const gameInfo = useGetGameInfoQuery() @@ -103,10 +134,10 @@ function Level() { {levelId && `Level ${levelId}`}{level?.data?.title && `: ${level?.data?.title}`} - - @@ -125,9 +156,13 @@ function Level() {
- - { setCommandLineMode(!commandLineMode) }} />} label="Editor mode" /> - +
+ {commandLineMode && } + + { setCommandLineMode(!commandLineMode) }} />} label="Editor mode" /> + +
+ diff --git a/client/src/components/Welcome.tsx b/client/src/components/Welcome.tsx index 6f36a6f..b9d3f3b 100644 --- a/client/src/components/Welcome.tsx +++ b/client/src/components/Welcome.tsx @@ -14,7 +14,6 @@ import { useGetGameInfoQuery } from '../state/api'; import { Link } from 'react-router-dom'; import Markdown from './Markdown'; import { selectCompleted } from '../state/progress'; -import { SetTitleContext } from '../App'; function LevelIcon({ worldId, levelId, position }) { @@ -34,12 +33,9 @@ function Welcome() { const { nodes, bounds }: any = gameInfo.data ? computeWorldLayout(gameInfo.data?.worlds) : {nodes: []} - const {setTitle, setSubtitle} = React.useContext(SetTitleContext); - useEffect(() => { if (gameInfo.data?.title) { window.document.title = gameInfo.data.title - setTitle(gameInfo.data.title) } }, [gameInfo.data?.title]) diff --git a/client/src/components/infoview/CommandLine.tsx b/client/src/components/infoview/CommandLine.tsx index 66432e5..27e6211 100644 --- a/client/src/components/infoview/CommandLine.tsx +++ b/client/src/components/infoview/CommandLine.tsx @@ -4,43 +4,67 @@ import { LspDiagnosticsContext } from '../../../../node_modules/lean4-infoview/s import { useServerNotificationEffect } from '../../../../node_modules/lean4-infoview/src/infoview/util'; import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js' import { DiagnosticSeverity, PublishDiagnosticsParams } from 'vscode-languageserver-protocol'; -import { MonacoEditorContext } from '../Level' +import { InputModeContext, MonacoEditorContext } from '../Level' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faWandMagicSparkles } from '@fortawesome/free-solid-svg-icons' +function hasErrorsOrWarnings(diags) { + return diags.some( + (d) => + !d.message.startsWith("unsolved goals") && + (d.severity == DiagnosticSeverity.Error || d.severity == DiagnosticSeverity.Warning) + ) +} + export function CommandLine() { const editor = React.useContext(MonacoEditorContext) const commandInput = useRef() const [processing, setProcessing] = useState(false) - // const allDiags = React.useContext(LspDiagnosticsContext) - // const fileDiags = allDiags.get(editor.getModel().uri.toString()) + const { commandLineMode } = React.useContext(InputModeContext) + const allDiags = React.useContext(LspDiagnosticsContext) + const diags = allDiags.get(editor.getModel().uri.toString()) + + React.useEffect(() => { + if (hasErrorsOrWarnings(diags)) { + // alert("err") + } + }, []) + React.useEffect(() => { + if (commandLineMode) { + const endPos = editor.getModel().getFullModelRange().getEndPosition() + if (editor.getModel().getLineContent(endPos.lineNumber).trim() !== "") { + editor.executeEdits("command-line", [{ + range: monaco.Selection.fromPositions(endPos, endPos), + text: "\n", + forceMoveMarkers: false + }]); + } + editor.setPosition(editor.getModel().getFullModelRange().getEndPosition()) + } + }, [commandLineMode]) const handleSubmit : React.FormEventHandler = (ev) => { ev.preventDefault() - var selection = monaco.Selection.fromPositions( - editor.getPosition(), - editor.getModel().getFullModelRange().getEndPosition() - ); - var text = commandInput.current!.value + "\n"; - var op = {range: selection, text: text, forceMoveMarkers: false}; - editor.executeEdits("my-source", [op], editor.getSelections()); + editor.executeEdits("command-line", [{ + range: monaco.Selection.fromPositions( + editor.getPosition(), + editor.getModel().getFullModelRange().getEndPosition() + ), + text: commandInput.current!.value + "\n", + forceMoveMarkers: false + }]); setProcessing(true) } useServerNotificationEffect('textDocument/publishDiagnostics', (params: PublishDiagnosticsParams) => { if (params.uri == editor.getModel().uri.toString()) { setProcessing(false) - const hasErrorsOrWarnings = params.diagnostics.some( - (d) => - !d.message.startsWith("unsolved goals") && - (d.severity == DiagnosticSeverity.Error || d.severity == DiagnosticSeverity.Warning) - ) - if (!hasErrorsOrWarnings) { + if (!hasErrorsOrWarnings(params.diagnostics)) { commandInput.current!.value = ""; editor.setPosition(editor.getModel().getFullModelRange().getEndPosition()) } @@ -50,7 +74,7 @@ export function CommandLine() { return
- +
} diff --git a/client/src/components/infoview/info.tsx b/client/src/components/infoview/info.tsx index f4715d2..dfe66a9 100644 --- a/client/src/components/infoview/info.tsx +++ b/client/src/components/infoview/info.tsx @@ -112,7 +112,6 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => { }), [selectedLocs]) const goalFilter = { reverse: false, showType: true, showInstance: true, showHiddenAssumption: true, showLetValue: true } - /* Adding {' '} to manage string literals properly: https://reactjs.org/docs/jsx-in-depth.html#string-literals-1 */ return <> {hasError && @@ -121,13 +120,13 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => { { e.preventDefault(); void triggerUpdate(); }}>{' '}Try again.
} - {goals && goals.goals.length > 0 &&
-
Main Goal
- -
} +
+ { goals && goals.goals.length > 0 + ? <>
Main Goal
+ + :
No Goals
} +
- {/* */} {userWidgets.map(widget =>
{widget.name} @@ -135,14 +134,6 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => { selectedLocations={selectedLocs} widget={widget}/>
)} - {/*
-
- Messages ({messages.length}) -
- -
-
-
*/} {nothingToShow && ( isPaused ? /* Adding {' '} to manage string literals properly: https://reactjs.org/docs/jsx-in-depth.html#string-literals-1 */ diff --git a/client/src/components/level.css b/client/src/components/level.css index bc98c13..542c587 100644 --- a/client/src/components/level.css +++ b/client/src/components/level.css @@ -24,7 +24,7 @@ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); } -.main-panel, .info-panel { +.main-panel, .info-panel, .doc-panel { height: 100%; overflow: auto; } @@ -66,6 +66,9 @@ .input-mode-switch { margin: .5em 0; float: right; + display: flex; + flex-direction: row; + gap: 1em; } .doc-panel li {