Skip to content

Commit 38073c0

Browse files
authored
Merge pull request #14 from CS3219-AY2526Sem1/collab-frontend
Collab frontend (referencing @CJianzhi) - Verified that scroll bar has been disabled when code does not exceed current screen height - Verified that language selector works as intended with correct syntax highlighting - Verified that collab page is only accessible by authenticated users - Verified that chat box can reflect keys entered, and overflow will spill right
2 parents 109d08d + 7a02869 commit 38073c0

File tree

11 files changed

+302
-20
lines changed

11 files changed

+302
-20
lines changed

ai/usage-log.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,30 @@ Request to create a simple client-side auth guard that prevents browser back nav
392392
- UX improvements: immediate redirect prevents brief flash of protected content
393393
- Maintainability: simple, reusable component for future auth requirements
394394

395+
396+
## Entry 13
397+
398+
# Date/Time:
399+
2025-09-19 19:00
400+
401+
# Tool:
402+
Gemini (Tried to google the answer online and Google's AI overview mentioned the recommendations)
403+
404+
# Prompt/Command:
405+
Ask on how to disable scrollbar and to not create additional empty spaces when there is still sufficient space to enter code.
406+
407+
# Output Summary:
408+
- Explain that Monaco Editor has a field called "scrollBeyondLastLine" that when disabled will cause the scrollbar to scroll only till the last line.
409+
410+
# Action Taken:
411+
- [X] Accepted as-is
412+
- [ ] Modified
413+
- [ ] Rejected
414+
415+
# Author Notes:
416+
- Add the field "scrollBeyondLastLine" and set it to false in the Monaco Editor configuration
417+
- Tested the UI and found that the scrollbar will not appear if there is sufficient space for code to be entered. If code entered has exceeded the maximum container height, the scrollbar will only allow the user to scroll till the last line.
418+
395419
---
396420

397421

frontend/package-lock.json

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

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"dependencies": {
1414
"@hookform/resolvers": "^5.2.1",
15+
"@monaco-editor/react": "^4.7.0",
1516
"@radix-ui/react-dialog": "^1.1.15",
1617
"@radix-ui/react-dropdown-menu": "^2.1.16",
1718
"@radix-ui/react-label": "^2.1.7",

frontend/src/app/collab/page.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
1-
import ContentPage from "../components/collab/ContentPage";
1+
import ChatComponent from "../components/collab/ChatComponent";
2+
import CodingComponent from "../components/collab/CodingComponent";
3+
import QuestionComponent from "../components/collab/QuestionComponent";
24
import SessionHeader from "../components/collab/SessionHeader";
35

46
export default function CollabPage() {
57
return (
68
<main className="bg-stone-900 h-screen flex flex-col items-center">
79
<SessionHeader />
8-
<ContentPage />
10+
11+
<div className="flex flex-1 w-full bg-stone-800 ">
12+
<div className="flex-1 p-5">
13+
<QuestionComponent />
14+
</div>
15+
16+
<div className="flex-[2]">
17+
<CodingComponent />
18+
</div>
19+
20+
<div className="flex-1 p-5">
21+
<ChatComponent />
22+
</div>
23+
</div>
924
</main>
1025
);
1126
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Button } from "@/components/ui/button";
2+
import { Input } from "@/components/ui/input";
3+
import { ChevronRightIcon } from "lucide-react";
4+
5+
export default function ChatComponent() {
6+
const chatMessages = ["HELLO", "HOW ARE YOU?"];
7+
8+
return (
9+
<div className="flex flex-col h-full bg-stone-900 p-1">
10+
<div className="flex bg-stone-500 h-full mb-5 rounded-lg"></div>
11+
12+
<div className="flex w-full mt-auto gap-2">
13+
<Input className="bg-white" />
14+
<Button variant="secondary" size="icon" className="size-9">
15+
<ChevronRightIcon />
16+
</Button>
17+
</div>
18+
</div>
19+
);
20+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"use client";
2+
3+
import Editor from "@monaco-editor/react";
4+
import {
5+
DropdownMenu,
6+
DropdownMenuContent,
7+
DropdownMenuGroup,
8+
DropdownMenuItem,
9+
DropdownMenuTrigger,
10+
} from "@/components/ui/dropdown-menu";
11+
import { useState } from "react";
12+
import { Button } from "@/components/ui/button";
13+
import { ChevronDown, CircleUser } from "lucide-react";
14+
15+
export default function CodingComponent() {
16+
const [codeContent, setCodeContent] = useState<string>("");
17+
const [selectedLanguage, setSeletedLanguage] = useState<string>("JavaScript");
18+
19+
function setInitialContent(value: string | undefined) {
20+
if (value != undefined) {
21+
setCodeContent(value);
22+
}
23+
}
24+
25+
return (
26+
<div className="mt-5">
27+
<div className="flex justify-between mb-4">
28+
<DropdownMenu>
29+
<DropdownMenuTrigger asChild className="flex justify-between">
30+
<Button className="w-40 bg-white text-black hover:bg-gray-500">
31+
{selectedLanguage} <ChevronDown />
32+
</Button>
33+
</DropdownMenuTrigger>
34+
<DropdownMenuContent className="w-10" align="start">
35+
<DropdownMenuGroup>
36+
<DropdownMenuItem
37+
onClick={() => setSeletedLanguage("JavaScript")}
38+
>
39+
Javascript
40+
</DropdownMenuItem>
41+
<DropdownMenuItem onClick={() => setSeletedLanguage("Python")}>
42+
Python
43+
</DropdownMenuItem>
44+
<DropdownMenuItem onClick={() => setSeletedLanguage("C")}>
45+
C
46+
</DropdownMenuItem>
47+
<DropdownMenuItem onClick={() => setSeletedLanguage("C++")}>
48+
C++
49+
</DropdownMenuItem>
50+
<DropdownMenuItem onClick={() => setSeletedLanguage("Java")}>
51+
Java
52+
</DropdownMenuItem>
53+
</DropdownMenuGroup>
54+
</DropdownMenuContent>
55+
</DropdownMenu>
56+
<div className="flex justify-center items-center">
57+
<div className="text-white mr-3">[email protected]</div>
58+
<CircleUser className="text-white mr-2" size="25" />
59+
</div>
60+
</div>
61+
<Editor
62+
height="85vh"
63+
theme="vs-dark"
64+
language={selectedLanguage.toLowerCase()}
65+
onChange={(value) => setInitialContent(value)}
66+
options={{ scrollBeyondLastLine: false }}
67+
></Editor>
68+
</div>
69+
);
70+
}

frontend/src/app/components/collab/ContentPage.tsx

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Badge } from "@/components/ui/badge";
2+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
3+
4+
export default function QuestionComponent() {
5+
const difficultyMapping = {
6+
Hard: "bg-red-900 text-black",
7+
Medium: "bg-yellow-900 text-black",
8+
Easy: "bg-green-900 text-black",
9+
};
10+
11+
return (
12+
<Card className="h-full flex flex-col bg-stone-900 border-black">
13+
{/* Criteria */}
14+
<CardHeader>
15+
<CardTitle className="text-white text-4xl">Two Sum</CardTitle>
16+
<div className="flex pt-5 items-start gap-2">
17+
<Badge className="bg-red-900 text-black">Difficult</Badge>
18+
</div>
19+
</CardHeader>
20+
21+
<CardContent className="flex flex-col flex-1">
22+
{/* Question Description */}
23+
<div className="flex-1 text-white">
24+
Description : We, the citizens of Singapore, pledge ourselves as one
25+
united people, regardless of race, language or religion, to build a
26+
democratic society based on justice and equality so as to achieve
27+
happiness, prosperity and progress for our nation.
28+
</div>
29+
30+
{/* Examples Section */}
31+
<div className="flex-1 mt-5 p-2 bg-black text-white rounded-lg text-sm">
32+
Input : Test case 1 Output : Correct answer Explanation : Because it
33+
is correct
34+
</div>
35+
36+
{/* Constraints Section */}
37+
<div className="mt-5 p-2 flex-1 text-white">
38+
1 is less than n There will be a total of 1 trillion test cases
39+
</div>
40+
</CardContent>
41+
</Card>
42+
);
43+
}
Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
1+
"use client";
2+
import { Button } from "@/components/ui/button";
3+
import { Mic } from "lucide-react";
4+
import { useRouter } from "next/navigation";
5+
16
export default function SessionHeader() {
7+
const router = useRouter();
8+
9+
function directToMatch() {
10+
router.replace("/match");
11+
}
12+
213
return (
3-
<header className="bg-stone-800 w-full h-[5%] text-white border-b-2 border-stone-700">
4-
Session Header
14+
<header
15+
className="flex
16+
justify-end
17+
items-center
18+
gap-3
19+
bg-stone-800
20+
w-full
21+
h-15
22+
text-white
23+
border-b-2
24+
border-stone-700"
25+
>
26+
<Button>
27+
<Mic />
28+
</Button>
29+
<Button
30+
onClick={() => directToMatch()}
31+
className="bg-red-500 text-black mr-3 hover:bg-red-300"
32+
>
33+
Leave Session
34+
</Button>
535
</header>
636
);
737
}

frontend/src/app/components/layout/NavbarWrapper.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ export default function NavbarWrapper() {
1515

1616
// Don't show navbar on auth pages
1717
const isAuthPage = pathname.startsWith("/auth");
18+
const isCollabPage = pathname.startsWith("/collab");
1819

19-
if (isAuthPage) {
20+
if (isAuthPage || isCollabPage) {
2021
return null;
2122
}
2223

0 commit comments

Comments
 (0)