Skip to content

Commit 3771446

Browse files
committed
Add 3rd party lib for code editor
1 parent 4596f44 commit 3771446

File tree

5 files changed

+191
-3
lines changed

5 files changed

+191
-3
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, {useState} from "react";
2+
import AceEditor from "react-ace";
3+
4+
import "ace-builds/src-noconflict/mode-python";
5+
import "ace-builds/src-noconflict/theme-terminal";
6+
import "ace-builds/src-noconflict/ext-language_tools";
7+
import "ace-builds/src-noconflict/ext-searchbox";
8+
import "ace-builds/src-noconflict/ext-inline_autocomplete";
9+
import "ace-builds/src-noconflict/keybinding-vim";
10+
11+
const languages = [
12+
"javascript",
13+
"java",
14+
"python",
15+
"mysql",
16+
"golang",
17+
"typescript",
18+
];
19+
20+
const themes = [
21+
"monokai",
22+
"github",
23+
"tomorrow",
24+
"kuroir",
25+
"twilight",
26+
"xcode",
27+
"textmate",
28+
"solarized_dark",
29+
"solarized_light",
30+
"terminal"
31+
];
32+
33+
languages.forEach(lang => {
34+
require(`ace-builds/src-noconflict/mode-${lang}`);
35+
require(`ace-builds/src-noconflict/snippets/${lang}`);
36+
});
37+
38+
themes.forEach(theme => require(`ace-builds/src-noconflict/theme-${theme}`));
39+
40+
import "ace-builds/src-min-noconflict/ext-searchbox";
41+
import "ace-builds/src-min-noconflict/ext-language_tools";
42+
43+
44+
import {Question} from "@/api/structs";
45+
46+
interface Props {
47+
question: Question;
48+
}
49+
50+
51+
export default function CollabEditor({question}: Props) {
52+
const [theme, setTheme] = useState("twilight")
53+
const [fontSize, setFontSize] = useState(16)
54+
const [language, setLanguage] = useState("python")
55+
56+
57+
const handleOnChange = (newValue: string) => {
58+
console.log("Content changed:", newValue);
59+
};
60+
61+
const handleOnLoad = (editor: any) => {
62+
editor.container.style.resize = "both"
63+
}
64+
65+
// TODO: to be taken from question props instead
66+
// const value = question[language] ?? "// Comment"
67+
const value = `def foo:
68+
pass`
69+
70+
71+
return <>
72+
<div className="flex space-x-4 items-center p-4">
73+
<div className="flex flex-col">
74+
<label className="font-semibold mb-1">Font Size</label>
75+
<input
76+
type="number"
77+
className="border border-gray-600 bg-gray-800 text-white p-2 rounded w-20"
78+
value={fontSize}
79+
onChange={(e) => setFontSize(Number(e.target.value))}
80+
/>
81+
</div>
82+
83+
<div className="flex flex-col">
84+
<label className="font-semibold mb-1">Theme</label>
85+
<select
86+
className="border border-gray-600 bg-gray-800 text-white p-2 rounded"
87+
value={theme}
88+
onChange={(e) => setTheme(e.target.value)}
89+
>
90+
{themes.map((theme) => (
91+
<option key={theme} value={theme}>
92+
{theme}
93+
</option>
94+
))}
95+
</select>
96+
</div>
97+
98+
<div className="flex flex-col">
99+
<label className="font-semibold mb-1">Language</label>
100+
<select
101+
className="border border-gray-600 bg-gray-800 text-white p-2 rounded"
102+
value={language}
103+
onChange={(e) => setLanguage(e.target.value)}
104+
>
105+
{languages.map((lang) => (
106+
<option key={lang} value={lang}>
107+
{lang}
108+
</option>
109+
))}
110+
</select>
111+
</div>
112+
</div>
113+
114+
115+
<AceEditor
116+
mode={language}
117+
className={"editor"}
118+
width={"90%"}
119+
height={"90%"}
120+
theme={theme}
121+
name="Editor"
122+
fontSize={fontSize}
123+
onLoad={handleOnLoad}
124+
onChange={handleOnChange}
125+
lineHeight={19}
126+
showPrintMargin={true}
127+
showGutter={true}
128+
highlightActiveLine={true}
129+
value={value}
130+
setOptions={{
131+
enableBasicAutocompletion: true,
132+
enableLiveAutocompletion: true,
133+
enableSnippets: false,
134+
showLineNumbers: true,
135+
tabSize: 4,
136+
}}/>
137+
</>
138+
139+
}

peerprep/app/questions/[question]/question.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Chip from "@/components/shared/Chip";
55
import PeerprepButton from "@/components/shared/PeerprepButton";
66
import styles from "@/style/question.module.css";
77
import { useRouter } from "next/navigation";
8+
import CollabEditor from "@/app/questions/[question]/CollabEditor";
89

910
interface Props {
1011
question: Question;
@@ -104,9 +105,11 @@ function QuestionBlock({ question }: Props) {
104105
</table>
105106
)}
106107
</div>
107-
<form className={styles.editor_container}>
108-
<textarea className={styles.code_editor} />
109-
</form>
108+
<div className={styles.editor_container}>
109+
<CollabEditor
110+
question={question}
111+
/>
112+
</div>
110113
</>
111114
);
112115
}

peerprep/package-lock.json

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

peerprep/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
"@types/node": "22.5.5",
1313
"@types/react": "18.3.8",
1414
"@types/react-dom": "18.3.0",
15+
"ace-builds": "^1.36.2",
1516
"eslint": "8.57.1",
1617
"eslint-config-next": "14.2.13",
1718
"next": "14.2.13",
1819
"react": "18.3.1",
20+
"react-ace": "^12.0.0",
1921
"react-dom": "18.3.1",
2022
"typescript": "5.6.2"
2123
},

peerprep/style/question.module.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@
8888
width: 30%;
8989
}
9090

91+
.editor {
92+
flex-grow: 1; /* Allow editor to take available space */
93+
min-height: 300px;
94+
position: relative;
95+
}
96+
9197
.editor_container {
9298
width: 48%;
9399
height: 100%;

0 commit comments

Comments
 (0)