Added Layout to the editor page

This commit is contained in:
inaseem 2021-10-03 19:49:58 +05:30
parent c82b287c8a
commit c5e00165dd
7 changed files with 209 additions and 172 deletions

View File

@ -0,0 +1,32 @@
import React from "react";
import { EventEmitter } from "../utils/EventEmitter";
import Split from "react-split";
const Layouts = (props) => {
const { splitType, children } = props;
return (
<>
<Split
className="split"
minSize={0}
snapOffset={0}
expandToMin={false}
gutterSize={10}
gutterAlign="center"
dragInterval={1}
direction={splitType}
style={{
flexGrow: 1,
...(splitType === "horizontal"
? { display: "flex", flexDirection: "row", alignItems: "stretch" }
: {}),
}}
onDragEnd={() => EventEmitter.dispatch("resize")}
>
{children}
</Split>
</>
);
};
export default Layouts;

View File

@ -19,6 +19,9 @@ function RijuTerminal() {
term.loadAddon(fitAddon);
window.addEventListener("resize", () => fitAddon.fit());
EventEmitter.subscribe("resize", () => {
fitAddon.fit();
});
EventEmitter.subscribe("terminal", (payload) => {
if (!payload) return;
const { type, data } = payload;
@ -40,7 +43,14 @@ function RijuTerminal() {
}, []);
return (
<Box id="riju-term" sx={{ height: `calc(100% - 8px)`, mt: 1, ml: 2 }} />
<Box
id="riju-term"
sx={{
height: "100%",
width: "100%",
backgroundColor: "#292D3E",
}}
/>
);
}

View File

@ -1,13 +1,30 @@
import MonacoEditor, { useMonaco } from "@monaco-editor/react";
import { Circle, Code as Format, Home, PlayArrow } from "@mui/icons-material";
import {
Circle,
Code as Format,
Home,
HorizontalSplit,
PlayArrow,
VerticalSplit,
} from "@mui/icons-material";
import { LoadingButton } from "@mui/lab";
import { Box, Button, Chip, Divider, Typography } from "@mui/material";
import {
Box,
Button,
Chip,
Divider,
Stack,
ToggleButton,
ToggleButtonGroup,
Typography,
} from "@mui/material";
import ansi from "ansicolor";
import dynamic from "next/dynamic";
import Head from "next/head";
import { useRouter } from "next/router";
import React, { useEffect, useRef, useState } from "react";
import { createMessageConnection } from "vscode-jsonrpc";
import Layouts from "../../components/Layouts";
import langs from "../../static/langs.json";
import { EventEmitter } from "../../utils/EventEmitter";
ansi.rgb = {
@ -27,12 +44,14 @@ const CodeRunner = (props) => {
const router = useRouter();
const { langConfig } = props;
const editorRef = useRef(null);
const paneRef = useRef(null);
const [config, setConfig] = useState(langConfig);
const [mounted, setMounted] = useState(false);
const [isRunning, setRunning] = useState(false);
const [isFormatting, setFormatting] = useState(false);
const [isLspStarted, setLspStarted] = useState(false);
const [isLspRequested, setIsLspRequested] = useState(false);
const [splitType, setSplitType] = useState("horizontal");
const monaco = useMonaco();
const [status, setStatus] = useState("connecting");
@ -233,8 +252,6 @@ const CodeRunner = (props) => {
case "lsp":
setLspStarted(false);
setIsLspRequested(false);
// lspButton.classList.add("is-light");
// lspButtonState.innerText = "CRASHED";
break;
case "terminal":
sendToTerminal(
@ -307,13 +324,42 @@ const CodeRunner = (props) => {
showValue();
},
});
// editor.getModel().onDidChangeContent(() => recordActivity());
// window.addEventListener("resize", () => editor.layout());
editor.getModel().setValue(config.template + "\n");
monaco.editor.setModelLanguage(
editor.getModel(),
config.monacoLang || "plaintext"
);
// Below code is just for adding an empty line in editor
monaco.languages.registerCodeLensProvider(
config.monacoLang || "plaintext",
{
provideCodeLenses: function (model, token) {
return {
lenses: [
{
range: {
startLineNumber: 1,
startColumn: 1,
endLineNumber: 2,
endColumn: 1,
},
id: "Format",
command: {
// id: commandId,
// title: "Format",
title: "",
},
},
],
dispose: () => {},
};
},
resolveCodeLens: function (model, codeLens, token) {
return codeLens;
},
}
);
setMounted(true);
}
@ -338,6 +384,17 @@ const CodeRunner = (props) => {
}
};
const handleLayout = (event, value) => {
const e = document.querySelector(".split .gutter");
e.classList.replace(`gutter-${splitType}`, `gutter-${value}`);
const es = document.querySelectorAll(".split .panel");
for (const e of es) {
e.removeAttribute("style");
e.removeAttribute("style");
}
setSplitType(value);
};
return (
<>
<Head>
@ -352,25 +409,20 @@ const CodeRunner = (props) => {
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<Box
sx={{
display: "flex",
flexDirection: "column",
height: "100vh",
bgcolor: "#fff",
}}
component="main"
<Stack
direction="column"
sx={{ height: "100vh", bgcolor: "white" }}
alignItems="stretch"
>
<Box
<Stack
direction="row"
alignItems="stretch"
sx={{
display: "flex",
flexDirection: "row",
alignItems: "stretch",
boxShadow: `0 2px 4px rgb(0 0 0 / 2%)`,
width: "60%",
boxShadow: `0 2px 4px rgb(0 0 0 / 10%)`,
zIndex: (t) => t.zIndex.appBar,
}}
>
<Box sx={{ flexGrow: 1, display: "flex", alignItems: "center" }}>
<Stack direction="row" sx={{ flexGrow: 1 }} alignItems="stretch">
<Button
variant="contained"
sx={{ borderRadius: 0, minWidth: 0 }}
@ -383,7 +435,10 @@ const CodeRunner = (props) => {
>
<Home fontSize={"small"} />
</Button>
<Typography sx={{ fontSize: 14, px: 2, fontWeight: 600 }}>
<Typography
sx={{ fontSize: 14, px: 2, fontWeight: 600, alignSelf: "center" }}
textAlign="center"
>
{config.name}
</Typography>
<Chip
@ -397,7 +452,7 @@ const CodeRunner = (props) => {
}}
label={status}
/>
</Box>
</Stack>
<LoadingButton
onClick={handleLspClick}
size="small"
@ -423,6 +478,31 @@ const CodeRunner = (props) => {
>
<Typography sx={{ fontSize: 12 }}>Autocomplete</Typography>
</LoadingButton>
<ToggleButtonGroup
size="small"
value={splitType}
color="primary"
exclusive
onChange={handleLayout}
aria-label="split type"
sx={{ mr: 1 }}
>
<ToggleButton
value="vertical"
aria-label="vertical split"
sx={{ borderRadius: 0 }}
>
<VerticalSplit fontSize="small" />
</ToggleButton>
<ToggleButton
value="horizontal"
aria-label="horizontal split"
sx={{ borderRadius: 0 }}
>
<HorizontalSplit fontSize="small" />
</ToggleButton>
</ToggleButtonGroup>
<LoadingButton
onClick={sendFormat}
loading={isFormatting}
@ -451,26 +531,17 @@ const CodeRunner = (props) => {
>
<Typography sx={{ fontSize: 12, color: "#fff" }}>Run</Typography>
</LoadingButton>
</Box>
<Divider />
<Box
sx={{
display: "flex",
flexDirection: "row",
flexGrow: 1,
alignItems: "stretch",
}}
>
<Box sx={{ backgroundColor: "white", width: "60%" }}>
<Box
component={MonacoEditor}
</Stack>
<Layouts splitType={splitType}>
<Box className="panel editor">
<MonacoEditor
wrapperClassName={"rijuEditor"}
onChange={handleChange}
height="90vh"
// height="100vh"
defaultLanguage="javascript"
defaultValue="// some comment"
options={{
minimap: { enabled: false },
minimap: { enabled: splitType == "horizontal" ? false : true },
scrollbar: { verticalScrollbarSize: 0 },
fontLigatures: true,
fontFamily: "Fira Code",
@ -478,17 +549,11 @@ const CodeRunner = (props) => {
onMount={editorDidMount}
/>
</Box>
<Box
sx={{
overflow: "hidden",
backgroundColor: "#292D3E",
width: "40%",
}}
>
<Box className="panel" sx={{ bgcolor: "#292D3E", p: 2 }}>
<RijuTerminal />
</Box>
</Box>
</Box>
</Layouts>
</Stack>
</>
);
};

View File

@ -1,121 +0,0 @@
.container {
min-height: 100vh;
padding: 0 0.5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.footer {
width: 100%;
height: 100px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
}
.footer a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.title a {
color: #0070f3;
text-decoration: none;
}
.title a:hover,
.title a:focus,
.title a:active {
text-decoration: underline;
}
.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
}
.title,
.description {
text-align: center;
}
.description {
line-height: 1.5;
font-size: 1.5rem;
}
.code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
margin-top: 3rem;
}
.card {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
width: 45%;
}
.card:hover,
.card:focus,
.card:active {
color: #0070f3;
border-color: #0070f3;
}
.card h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
.logo {
height: 1em;
margin-left: 0.5rem;
}
@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}

View File

@ -20,6 +20,43 @@ a {
}
.rijuEdutor {
overflow: hidden;
height: calc(100% - 8px);
height: 100%;
width: 100%;
}
/* Split pane */
.split {
overflow: auto;
}
.split .panel {
overflow: auto;
}
.split .editor {
overflow: hidden;
}
.split .gutter {
background-color: #eee;
opacity: 1;
z-index: 1;
background-repeat: no-repeat;
background-position: 50%;
}
/* .split .gutter:hover {
opacity: 1;
-webkit-transition: all 2s ease;
transition: all 2s ease;
} */
.split .gutter.gutter-vertical {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=");
cursor: row-resize;
width: 100% !important;
}
.split .gutter.gutter-horizontal {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
cursor: col-resize;
height: 100% !important;
}

View File

@ -51,6 +51,7 @@
"prettier": "^2.3.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-split": "^2.0.13",
"regenerator-runtime": "^0.13.7",
"setimmediate": "^1.0.5",
"strip-ansi": "^6.0.0",

View File

@ -4787,7 +4787,7 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
prop-types@15.7.2, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.7.2, prop-types@^15.5.7, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -4952,6 +4952,14 @@ react-refresh@0.8.3:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==
react-split@^2.0.13:
version "2.0.13"
resolved "https://registry.yarnpkg.com/react-split/-/react-split-2.0.13.tgz#8d55fcb17edfd6cd2fb0203ab8324c02ec39a81a"
integrity sha512-suq/UH4epMu2aF4NBh+imlpUvntsIvU3li9EBBLdxqNtYEg+nY7TGl8Ij65mD1qYyhs3dQhA1Pv3rLXd1s5/lQ==
dependencies:
prop-types "^15.5.7"
split.js "^1.6.0"
react-transition-group@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
@ -5432,6 +5440,11 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies:
extend-shallow "^3.0.0"
split.js@^1.6.0:
version "1.6.4"
resolved "https://registry.yarnpkg.com/split.js/-/split.js-1.6.4.tgz#13d47cba53382adef230a53294ce5dacb2a2f2e1"
integrity sha512-kYmQZprRJrF1IOjg/E+gdBEsKFv5kbgUE6RJVJZvrIzTOK/IHzKSqIeiJnWs7IP5D9TnpTQ2CbanuDuIWcyDUQ==
ssri@^6.0.1:
version "6.0.2"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"