Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions ai/usage-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,30 @@ Request to create a simple client-side auth guard that prevents browser back nav
- UX improvements: immediate redirect prevents brief flash of protected content
- Maintainability: simple, reusable component for future auth requirements


## Entry 13

# Date/Time:
2025-09-19 19:00

# Tool:
Gemini (Tried to google the answer online and Google's AI overview mentioned the recommendations)

# Prompt/Command:
Ask on how to disable scrollbar and to not create additional empty spaces when there is still sufficient space to enter code.

# Output Summary:
- Explain that Monaco Editor has a field called "scrollBeyondLastLine" that when disabled will cause the scrollbar to scroll only till the last line.

# Action Taken:
- [X] Accepted as-is
- [ ] Modified
- [ ] Rejected

# Author Notes:
- Add the field "scrollBeyondLastLine" and set it to false in the Monaco Editor configuration
- 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.

---


47 changes: 47 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@hookform/resolvers": "^5.2.1",
"@monaco-editor/react": "^4.7.0",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7",
Expand Down
19 changes: 17 additions & 2 deletions frontend/src/app/collab/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import ContentPage from "../components/collab/ContentPage";
import ChatComponent from "../components/collab/ChatComponent";
import CodingComponent from "../components/collab/CodingComponent";
import QuestionComponent from "../components/collab/QuestionComponent";
import SessionHeader from "../components/collab/SessionHeader";

export default function CollabPage() {
return (
<main className="bg-stone-900 h-screen flex flex-col items-center">
<SessionHeader />
<ContentPage />

<div className="flex flex-1 w-full bg-stone-800 ">
<div className="flex-1 p-5">
<QuestionComponent />
</div>

<div className="flex-[2]">
<CodingComponent />
</div>

<div className="flex-1 p-5">
<ChatComponent />
</div>
</div>
</main>
);
}
20 changes: 20 additions & 0 deletions frontend/src/app/components/collab/ChatComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ChevronRightIcon } from "lucide-react";

export default function ChatComponent() {
const chatMessages = ["HELLO", "HOW ARE YOU?"];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed that there is some boiler plate chat messages here. Do you intend to render them for this PR, as its currently not rendered?


return (
<div className="flex flex-col h-full bg-stone-900 p-1">
<div className="flex bg-stone-500 h-full mb-5 rounded-lg"></div>

<div className="flex w-full mt-auto gap-2">
<Input className="bg-white" />
<Button variant="secondary" size="icon" className="size-9">
<ChevronRightIcon />
</Button>
</div>
</div>
);
}
70 changes: 70 additions & 0 deletions frontend/src/app/components/collab/CodingComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use client";

import Editor from "@monaco-editor/react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { ChevronDown, CircleUser } from "lucide-react";

export default function CodingComponent() {
const [codeContent, setCodeContent] = useState<string>("");
const [selectedLanguage, setSeletedLanguage] = useState<string>("JavaScript");

function setInitialContent(value: string | undefined) {
if (value != undefined) {
setCodeContent(value);
}
}

return (
<div className="mt-5">
<div className="flex justify-between mb-4">
<DropdownMenu>
<DropdownMenuTrigger asChild className="flex justify-between">
<Button className="w-40 bg-white text-black hover:bg-gray-500">
{selectedLanguage} <ChevronDown />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-10" align="start">
<DropdownMenuGroup>
<DropdownMenuItem
onClick={() => setSeletedLanguage("JavaScript")}
>
Javascript
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setSeletedLanguage("Python")}>
Python
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setSeletedLanguage("C")}>
C
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setSeletedLanguage("C++")}>
C++
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setSeletedLanguage("Java")}>
Java
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
<div className="flex justify-center items-center">
<div className="text-white mr-3">[email protected]</div>
<CircleUser className="text-white mr-2" size="25" />
</div>
</div>
<Editor
height="85vh"
theme="vs-dark"
language={selectedLanguage.toLowerCase()}
onChange={(value) => setInitialContent(value)}
options={{ scrollBeyondLastLine: false }}
></Editor>
</div>
);
}
15 changes: 0 additions & 15 deletions frontend/src/app/components/collab/ContentPage.tsx

This file was deleted.

43 changes: 43 additions & 0 deletions frontend/src/app/components/collab/QuestionComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export default function QuestionComponent() {
const difficultyMapping = {
Hard: "bg-red-900 text-black",
Medium: "bg-yellow-900 text-black",
Easy: "bg-green-900 text-black",
};

return (
<Card className="h-full flex flex-col bg-stone-900 border-black">
{/* Criteria */}
<CardHeader>
<CardTitle className="text-white text-4xl">Two Sum</CardTitle>
<div className="flex pt-5 items-start gap-2">
<Badge className="bg-red-900 text-black">Difficult</Badge>
</div>
</CardHeader>

<CardContent className="flex flex-col flex-1">
{/* Question Description */}
<div className="flex-1 text-white">
Description : We, the citizens of Singapore, pledge ourselves as one
united people, regardless of race, language or religion, to build a
democratic society based on justice and equality so as to achieve
happiness, prosperity and progress for our nation.
</div>

{/* Examples Section */}
<div className="flex-1 mt-5 p-2 bg-black text-white rounded-lg text-sm">
Input : Test case 1 Output : Correct answer Explanation : Because it
is correct
</div>

{/* Constraints Section */}
<div className="mt-5 p-2 flex-1 text-white">
1 is less than n There will be a total of 1 trillion test cases
</div>
</CardContent>
</Card>
);
}
34 changes: 32 additions & 2 deletions frontend/src/app/components/collab/SessionHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
"use client";
import { Button } from "@/components/ui/button";
import { Mic } from "lucide-react";
import { useRouter } from "next/navigation";

export default function SessionHeader() {
const router = useRouter();

function directToMatch() {
router.replace("/match");
}

return (
<header className="bg-stone-800 w-full h-[5%] text-white border-b-2 border-stone-700">
Session Header
<header
className="flex
justify-end
items-center
gap-3
bg-stone-800
w-full
h-15
text-white
border-b-2
border-stone-700"
>
<Button>
<Mic />
</Button>
<Button
onClick={() => directToMatch()}
className="bg-red-500 text-black mr-3 hover:bg-red-300"
>
Leave Session
</Button>
</header>
);
}
3 changes: 2 additions & 1 deletion frontend/src/app/components/layout/NavbarWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ export default function NavbarWrapper() {

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

if (isAuthPage) {
if (isAuthPage || isCollabPage) {
return null;
}

Expand Down
46 changes: 46 additions & 0 deletions frontend/src/components/ui/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
secondary:
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive:
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);

function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span";

return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
);
}

export { Badge, badgeVariants };