From 752bf862fd151576a29e057efce74173b49d5458 Mon Sep 17 00:00:00 2001 From: rah7202 Date: Sat, 4 Apr 2026 13:13:27 +0530 Subject: [PATCH 1/9] fix: Added drag option for gemini output panel --- frontend/src/components/RightPanel.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/RightPanel.tsx b/frontend/src/components/RightPanel.tsx index 3ad6643..5275a3d 100644 --- a/frontend/src/components/RightPanel.tsx +++ b/frontend/src/components/RightPanel.tsx @@ -45,8 +45,10 @@ export default function RightPanel({ aiOutputRef, bottomRef, handleRestoreSnapshot }: RightPanelProps) { + + return ( -
+
Date: Sat, 4 Apr 2026 13:13:42 +0530 Subject: [PATCH 2/9] fix: Added drag option for gemini output panel --- frontend/src/components/AIPanel.tsx | 674 +++++++++++++++++++++++++++- 1 file changed, 671 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/AIPanel.tsx b/frontend/src/components/AIPanel.tsx index ec935ef..50404b9 100644 --- a/frontend/src/components/AIPanel.tsx +++ b/frontend/src/components/AIPanel.tsx @@ -1,3 +1,607 @@ +// import ReactMarkdown from "react-markdown"; +// import remarkGfm from "remark-gfm"; +// import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +// import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"; +// import { FiCopy } from "react-icons/fi"; +// import { IoSend } from "react-icons/io5"; +// import { AiOutlineClear } from "react-icons/ai"; +// import { useState, useRef, useCallback } from "react"; +// import toast from "react-hot-toast"; +// import api from "../lib/authAxios"; + +// import geminiLogo from "../assets/geminiLogo.png"; +// import type { Components } from "react-markdown"; + +// interface AIMessage { +// role: "user" | "ai"; +// content: string; +// } + +// interface CodeProps { +// inline?: boolean; +// className?: string; +// children?: React.ReactNode; +// } + +// interface AIPanelProps { +// roomId: string; +// mode: "code" | "selection" | "question"; +// history: AIMessage[]; +// setHistory: (v: AIMessage[]) => void; +// isAiThinking: boolean; +// rateCooldown: number; +// aiQuestion: string; +// setAiQuestion: (v: string) => void; +// onAskQuestion: (q: string) => void; +// isRunning: boolean; +// userOutput: string; +// aiOutputRef: React.RefObject; +// bottomRef: React.RefObject; +// } + +// export default function AIPanel({ +// roomId, +// mode, history, setHistory, +// isAiThinking, rateCooldown, +// aiQuestion, setAiQuestion, onAskQuestion, +// isRunning, userOutput, +// aiOutputRef, bottomRef, +// }: AIPanelProps) { + +// // ── Resizable AI output panel ───────────────────────────────────────────── +// // Min 120px, no max (user decides). Default 340px feels like a real editor. +// const AI_MIN_HEIGHT = 120; +// const AI_DEFAULT_HEIGHT = 340; +// const [aiPanelHeight, setAiPanelHeight] = useState(AI_DEFAULT_HEIGHT); +// const dragStartY = useRef(0); +// const dragStartHeight = useRef(AI_DEFAULT_HEIGHT); +// const isDragging = useRef(false); + +// const onDragStart = useCallback((e: React.MouseEvent) => { +// e.preventDefault(); +// isDragging.current = true; +// dragStartY.current = e.clientY; +// dragStartHeight.current = aiPanelHeight; + +// const onMouseMove = (ev: MouseEvent) => { +// if (!isDragging.current) return; +// // Dragging UP (negative delta) = growing the panel +// const delta = dragStartY.current - ev.clientY; +// const newHeight = Math.max(AI_MIN_HEIGHT, dragStartHeight.current + delta); +// setAiPanelHeight(newHeight); +// }; + +// const onMouseUp = () => { +// isDragging.current = false; +// document.removeEventListener("mousemove", onMouseMove); +// document.removeEventListener("mouseup", onMouseUp); +// document.body.style.cursor = ""; +// document.body.style.userSelect = ""; +// }; + +// document.addEventListener("mousemove", onMouseMove); +// document.addEventListener("mouseup", onMouseUp); +// document.body.style.cursor = "ns-resize"; +// document.body.style.userSelect = "none"; +// }, [aiPanelHeight]); + +// const copyToClipboard = (text: string) => { +// navigator.clipboard.writeText(text); +// toast.success("Copied!"); +// }; + +// const handleClearChat = async () => { +// if (history.length === 0) { +// toast("Chat is already empty", { icon: "ℹ️" }); +// return; +// } +// try { +// await api.delete(`/ai/history/${roomId}`); +// setHistory([]); +// toast.success("Chat cleared"); +// } catch { +// toast.error("Failed to clear chat"); +// } +// }; + +// const markdownComponents: Components = { +// h2: ({ children }) => ( +//

+// {children} +//

+// ), +// h3: ({ children }) => ( +//

+// {children} +//

+// ), +// p: ({ children }) => ( +//

+// {children} +//

+// ), +// ul: ({ children }) => ( +//
    +// {children} +//
+// ), +// li: ({ children }) => ( +//
  • +// +// {children} +//
  • +// ), +// code({ inline, className, children }: CodeProps) { +// const match = /language-(\w+)/.exec(className || ""); +// const codeText = String(children).replace(/\n$/, ""); +// return !inline && match ? ( +//
    +//
    +// +// {match[1]} +// +// +//
    +// +// {codeText} +// +//
    +// ) : ( +// +// {children} +// +// ); +// }, +// }; + +// return ( +// <> +// {/* QUESTION INPUT */} +//
    +//