|
|
|
@ -7,7 +7,8 @@ import '@fontsource/roboto/700.css';
|
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
|
import { MathJax } from "better-react-mathjax";
|
|
|
|
import { MathJax } from "better-react-mathjax";
|
|
|
|
import { Link as RouterLink } from 'react-router-dom';
|
|
|
|
import { Link as RouterLink } from 'react-router-dom';
|
|
|
|
import { Box, Button, CircularProgress, FormControlLabel, FormGroup, Switch } from '@mui/material';
|
|
|
|
import { Box, Button, CircularProgress, FormControlLabel, FormGroup, Switch, IconButton } from '@mui/material';
|
|
|
|
|
|
|
|
import MuiDrawer from '@mui/material/Drawer';
|
|
|
|
import Grid from '@mui/material/Unstable_Grid2';
|
|
|
|
import Grid from '@mui/material/Unstable_Grid2';
|
|
|
|
import LeftPanel from './LeftPanel';
|
|
|
|
import LeftPanel from './LeftPanel';
|
|
|
|
import { LeanTaskGutter } from 'lean4web/client/src/editor/taskgutter';
|
|
|
|
import { LeanTaskGutter } from 'lean4web/client/src/editor/taskgutter';
|
|
|
|
@ -22,6 +23,82 @@ import { ConnectionContext } from '../connection';
|
|
|
|
import Infoview from './Infoview';
|
|
|
|
import Infoview from './Infoview';
|
|
|
|
import { useParams } from 'react-router-dom';
|
|
|
|
import { useParams } from 'react-router-dom';
|
|
|
|
import { useLoadLevelQuery } from '../game/api';
|
|
|
|
import { useLoadLevelQuery } from '../game/api';
|
|
|
|
|
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
|
|
|
|
|
|
import { faUpload, faArrowRotateRight, faChevronLeft, faChevronRight, faBook, faDownload } from '@fortawesome/free-solid-svg-icons'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { styled, useTheme, Theme, CSSObject } from '@mui/material/styles';
|
|
|
|
|
|
|
|
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar';
|
|
|
|
|
|
|
|
import Toolbar from '@mui/material/Toolbar';
|
|
|
|
|
|
|
|
import List from '@mui/material/List';
|
|
|
|
|
|
|
|
import CssBaseline from '@mui/material/CssBaseline';
|
|
|
|
|
|
|
|
import Typography from '@mui/material/Typography';
|
|
|
|
|
|
|
|
import Divider from '@mui/material/Divider';
|
|
|
|
|
|
|
|
import MenuIcon from '@mui/icons-material/Menu';
|
|
|
|
|
|
|
|
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
|
|
|
|
|
|
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
|
|
|
|
|
|
import ListItem from '@mui/material/ListItem';
|
|
|
|
|
|
|
|
import ListItemButton from '@mui/material/ListItemButton';
|
|
|
|
|
|
|
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
|
|
|
|
|
|
|
import ListItemText from '@mui/material/ListItemText';
|
|
|
|
|
|
|
|
import InboxIcon from '@mui/icons-material/MoveToInbox';
|
|
|
|
|
|
|
|
import MailIcon from '@mui/icons-material/Mail';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Drawer Test */
|
|
|
|
|
|
|
|
const drawerWidth = 400;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const openedMixin = (theme: Theme): CSSObject => ({
|
|
|
|
|
|
|
|
width: drawerWidth,
|
|
|
|
|
|
|
|
transition: theme.transitions.create('width', {
|
|
|
|
|
|
|
|
easing: theme.transitions.easing.sharp,
|
|
|
|
|
|
|
|
duration: theme.transitions.duration.enteringScreen,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
overflowX: 'hidden',
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const closedMixin = (theme: Theme): CSSObject => ({
|
|
|
|
|
|
|
|
transition: theme.transitions.create('width', {
|
|
|
|
|
|
|
|
easing: theme.transitions.easing.sharp,
|
|
|
|
|
|
|
|
duration: theme.transitions.duration.leavingScreen,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
overflowX: 'hidden',
|
|
|
|
|
|
|
|
width: `calc(${theme.spacing(7)} + 1px)`,
|
|
|
|
|
|
|
|
[theme.breakpoints.up('sm')]: {
|
|
|
|
|
|
|
|
width: `calc(${theme.spacing(8)} + 1px)`,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DrawerHeader = styled('div')(({ theme }) => ({
|
|
|
|
|
|
|
|
display: 'flex',
|
|
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
|
|
justifyContent: 'flex-end',
|
|
|
|
|
|
|
|
padding: theme.spacing(0, 1),
|
|
|
|
|
|
|
|
// necessary for content to be below app bar
|
|
|
|
|
|
|
|
...theme.mixins.toolbar,
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface AppBarProps extends MuiAppBarProps {
|
|
|
|
|
|
|
|
open?: boolean;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
|
|
|
|
|
|
|
|
({ theme, open }) => ({
|
|
|
|
|
|
|
|
width: drawerWidth,
|
|
|
|
|
|
|
|
flexShrink: 0,
|
|
|
|
|
|
|
|
whiteSpace: 'nowrap',
|
|
|
|
|
|
|
|
boxSizing: 'border-box',
|
|
|
|
|
|
|
|
...(open && {
|
|
|
|
|
|
|
|
...openedMixin(theme),
|
|
|
|
|
|
|
|
'& .MuiDrawer-paper': openedMixin(theme),
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
...(!open && {
|
|
|
|
|
|
|
|
...closedMixin(theme),
|
|
|
|
|
|
|
|
'& .MuiDrawer-paper': closedMixin(theme),
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** End Drawer Test */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -37,6 +114,14 @@ function Level() {
|
|
|
|
const infoviewRef = useRef<HTMLDivElement>(null)
|
|
|
|
const infoviewRef = useRef<HTMLDivElement>(null)
|
|
|
|
const messagePanelRef = useRef<HTMLDivElement>(null)
|
|
|
|
const messagePanelRef = useRef<HTMLDivElement>(null)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [showSidePanel, setShowSidePanel] = useState(true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const toggleSidePanel = () => {
|
|
|
|
|
|
|
|
setShowSidePanel(!showSidePanel)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const theme = useTheme();
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
// Scroll to top when loading a new level
|
|
|
|
// Scroll to top when loading a new level
|
|
|
|
messagePanelRef.current!.scrollTo(0,0)
|
|
|
|
messagePanelRef.current!.scrollTo(0,0)
|
|
|
|
@ -49,35 +134,43 @@ function Level() {
|
|
|
|
|
|
|
|
|
|
|
|
return <>
|
|
|
|
return <>
|
|
|
|
<Box style={level.isLoading ? null : {display: "none"}} display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
|
|
|
|
<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: 0, ml: 0, mr: 0 }} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
|
|
|
<Box style={level.isLoading ? {display: "none"} : null} display="flex" className="level" sx={{ mt: 0, ml: 0, mr: 0 }} >
|
|
|
|
<Grid xs={4} className="doc-panel">
|
|
|
|
<Drawer variant="permanent" open={showSidePanel} className="doc-panel">
|
|
|
|
<LeftPanel spells={level?.data?.tactics} inventory={level?.data?.tactics} />
|
|
|
|
<DrawerHeader>
|
|
|
|
</Grid>
|
|
|
|
</DrawerHeader>
|
|
|
|
<Grid xs={9} sm={6} className="main-panel">
|
|
|
|
<Divider />
|
|
|
|
<div ref={messagePanelRef} className="message-panel">
|
|
|
|
<IconButton onClick={toggleSidePanel}>
|
|
|
|
<MathJax><ReactMarkdown>{level?.data?.introduction}</ReactMarkdown></MathJax>
|
|
|
|
<FontAwesomeIcon icon={showSidePanel ? faChevronLeft : faChevronRight}></FontAwesomeIcon>
|
|
|
|
</div>
|
|
|
|
</IconButton>
|
|
|
|
<div className="exercise">
|
|
|
|
<LeftPanel spells={level?.data?.tactics} inventory={level?.data?.lemmas} showSidePanel={showSidePanel} setShowSidePanel={setShowSidePanel} />
|
|
|
|
<h4>Aufgabe:</h4>
|
|
|
|
</Drawer>
|
|
|
|
<MathJax><ReactMarkdown>{level?.data?.descrText}</ReactMarkdown></MathJax>
|
|
|
|
<Grid container columnSpacing={{ xs: 1, sm: 2, md: 3 }} sx={{ flexGrow: 1, p: 3 }} className="main-grid">
|
|
|
|
<div className="statement"><code>{level?.data?.descrFormat}</code></div>
|
|
|
|
<Grid xs={8} className="main-panel">
|
|
|
|
<div ref={codeviewRef} className="codeview"></div>
|
|
|
|
<div ref={messagePanelRef} className="message-panel">
|
|
|
|
</div>
|
|
|
|
<MathJax><ReactMarkdown>{level?.data?.introduction}</ReactMarkdown></MathJax>
|
|
|
|
</Grid>
|
|
|
|
</div>
|
|
|
|
<Grid xs={3} className="info-panel">
|
|
|
|
<div className="exercise">
|
|
|
|
|
|
|
|
<h4>Aufgabe:</h4>
|
|
|
|
<Button disabled={levelId <= 1} component={RouterLink} to={`/world/${worldId}/level/${levelId - 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Previous Level</Button>
|
|
|
|
<MathJax><ReactMarkdown>{level?.data?.descrText}</ReactMarkdown></MathJax>
|
|
|
|
<Button disabled={false} component={RouterLink} to={`/world/${worldId}/level/${levelId + 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Next Level</Button>
|
|
|
|
<div className="statement"><code>{level?.data?.descrFormat}</code></div>
|
|
|
|
|
|
|
|
<div ref={codeviewRef} className="codeview"></div>
|
|
|
|
<div style={{display: expertInfoview ? 'block' : 'none' }} ref={infoviewRef} className="infoview vscode-light"></div>
|
|
|
|
</div>
|
|
|
|
<div style={{display: expertInfoview ? 'none' : 'block' }}>
|
|
|
|
</Grid>
|
|
|
|
<Infoview leanClient={connection.getLeanClient()} editor={editor} editorApi={infoProvider?.getApi()} />
|
|
|
|
<Grid xs={4} className="info-panel">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<FormGroup>
|
|
|
|
<Button disabled={levelId <= 1} component={RouterLink} to={`/world/${worldId}/level/${levelId - 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Previous Level</Button>
|
|
|
|
<FormControlLabel onChange={() => { setExpertInfoview(!expertInfoview) }} control={<Switch />} label="Expert mode" />
|
|
|
|
<Button disabled={false} component={RouterLink} to={`/world/${worldId}/level/${levelId + 1}`} sx={{ ml: 3, mt: 2, mb: 2 }} disableFocusRipple>Next Level</Button>
|
|
|
|
</FormGroup>
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
</Grid>
|
|
|
|
</Grid>
|
|
|
|
</Box>
|
|
|
|
</>
|
|
|
|
</>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|