allow hot reloading in level

pull/43/head
Alexander Bentkamp 2 years ago
parent 4c135aa6ae
commit b5e1d38341

@ -7,11 +7,8 @@ import '@fontsource/roboto/700.css';
import ReactMarkdown from 'react-markdown';
import { MathJax } from "better-react-mathjax";
import { Link as RouterLink } from 'react-router-dom';
import { Box, Button, CircularProgress, FormControlLabel, FormGroup, Switch } from '@mui/material';
import Grid from '@mui/material/Unstable_Grid2';
import LeftPanel from './LeftPanel';
import { AbbreviationProvider } from 'lean4web/client/src/editor/abbreviation/AbbreviationProvider';
import { AbbreviationRewriter } from 'lean4web/client/src/editor/abbreviation/rewriter/AbbreviationRewriter';
@ -23,7 +20,6 @@ import './level.css'
import { ConnectionContext } from '../connection';
import Infoview from './Infoview';
import { useParams } from 'react-router-dom';
import { MonacoServices } from 'monaco-languageclient';
import { useLoadLevelQuery } from '../game/api';
@ -34,9 +30,6 @@ function Level() {
const levelId = parseInt(params.levelId)
const worldId = params.worldId
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
const [infoviewApi, setInfoviewApi] = useState(null)
const [expertInfoview, setExpertInfoview] = useState(false)
const codeviewRef = useRef<HTMLDivElement>(null)
@ -50,6 +43,52 @@ function Level() {
const connection = React.useContext(ConnectionContext)
const level = useLoadLevelQuery({world: worldId, level: levelId})
const {editor, infoProvider} = useLevelEditor(worldId, levelId, codeviewRef, infoviewRef)
return <>
<Box style={level.isLoading ? null : {display: "none"}} display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
<Grid style={level.isLoading ? {display: "none"} : null} className="level" container sx={{ mt: 3, ml: 1, mr: 1 }} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid xs={4} className="doc-panel">
<LeftPanel spells={level?.data?.tactics} inventory={level?.data?.tactics} />
</Grid>
<Grid xs={4} className="main-panel">
<div ref={messagePanelRef} className="message-panel">
<MathJax><ReactMarkdown>{level?.data?.introduction}</ReactMarkdown></MathJax>
</div>
<div ref={codeviewRef} className="codeview">
</div>
</Grid>
<Grid xs={4} className="info-panel">
<Button disabled={levelId <= 1} component={RouterLink} to={`/world/${worldId}/level/${levelId - 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Previous Level</Button>
<Button disabled={false} component={RouterLink} to={`/world/${worldId}/level/${levelId + 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Next Level</Button>
<div style={{display: expertInfoview ? 'block' : 'none' }} ref={infoviewRef} className="infoview vscode-light"></div>
<div style={{display: expertInfoview ? 'none' : 'block' }}>
<Infoview leanClient={connection.getLeanClient()} editor={editor} editorApi={infoProvider?.getApi()} />
</div>
<FormGroup>
<FormControlLabel onChange={() => { setExpertInfoview(!expertInfoview) }} control={<Switch />} label="Expert mode" />
</FormGroup>
</Grid>
</Grid>
</>
}
export default Level
function useLevelEditor(worldId: string, levelId: number, codeviewRef, infoviewRef) {
const connection = React.useContext(ConnectionContext)
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
const [infoviewApi, setInfoviewApi] = useState(null)
// Create Editor
useEffect(() => {
const editor = monaco.editor.create(codeviewRef.current!, {
glyphMargin: true,
@ -76,11 +115,9 @@ function Level() {
setInfoProvider(infoProvider)
setInfoviewApi(infoviewApi)
return () => { editor.dispose() }
}, [])
// The next function will be called when the level changes
// Create model when level changes
useEffect(() => {
connection.startLeanClient().then((leanClient) => {
if (editor) {
@ -94,45 +131,10 @@ function Level() {
infoProvider.openPreview(editor, infoviewApi)
new AbbreviationRewriter(new AbbreviationProvider(), model, editor)
return () => { model.dispose(); }
}
})
}, [editor, levelId, connection])
const level = useLoadLevelQuery({world: worldId, level: levelId})
return <>
<Box style={level.isLoading ? null : {display: "none"}} display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
<Grid style={level.isLoading ? {display: "none"} : null} className="level" container sx={{ mt: 3, ml: 1, mr: 1 }} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid xs={4} className="doc-panel">
<LeftPanel spells={level?.data?.tactics} inventory={level?.data?.tactics} />
</Grid>
<Grid xs={4} className="main-panel">
<div ref={messagePanelRef} className="message-panel">
<MathJax><ReactMarkdown>{level?.data?.introduction}</ReactMarkdown></MathJax>
</div>
<div ref={codeviewRef} className="codeview">
</div>
</Grid>
<Grid xs={4} className="info-panel">
<Button disabled={levelId <= 1} component={RouterLink} to={`/world/${worldId}/level/${levelId - 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Previous Level</Button>
<Button disabled={false} component={RouterLink} to={`/world/${worldId}/level/${levelId + 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Next Level</Button>
<div style={{display: expertInfoview ? 'block' : 'none' }} ref={infoviewRef} className="infoview vscode-light"></div>
<div style={{display: expertInfoview ? 'none' : 'block' }}>
<Infoview leanClient={connection.getLeanClient()} editor={editor} editorApi={infoProvider?.getApi()} />
</div>
<FormGroup>
<FormControlLabel onChange={() => { setExpertInfoview(!expertInfoview) }} control={<Switch />} label="Expert mode" />
</FormGroup>
</Grid>
</Grid>
</>
return {editor, infoProvider}
}
export default Level

Loading…
Cancel
Save