From 36f8f50d6317a9f708a423823eab06e108d615cc Mon Sep 17 00:00:00 2001 From: simos Date: Fri, 31 Oct 2025 09:47:30 +0000 Subject: [PATCH] feat(editor): add sidebar mode to CodeEditor component Add an optional prop to the CodeEditor component to support rendering in both modal and sidebar layouts. When enabled, the editor adapts its container styling and removes the fixed overlay positioning, allowing it to be embedded inline. This includes conditional rendering of the loading state and main container to properly display within a sidebar context while maintaining the existing modal behavior as the default. --- src/components/CodeEditor.jsx | 63 ++++++++++-------- src/components/MainContent.jsx | 116 ++++++++++++++++++++++++++++----- 2 files changed, 135 insertions(+), 44 deletions(-) diff --git a/src/components/CodeEditor.jsx b/src/components/CodeEditor.jsx index abdce7d..770a1c8 100644 --- a/src/components/CodeEditor.jsx +++ b/src/components/CodeEditor.jsx @@ -13,7 +13,7 @@ import { showMinimap } from '@replit/codemirror-minimap'; import { X, Save, Download, Maximize2, Minimize2, Eye, EyeOff } from 'lucide-react'; import { api } from '../utils/api'; -function CodeEditor({ file, onClose, projectPath }) { +function CodeEditor({ file, onClose, projectPath, isSidebar = false }) { const [content, setContent] = useState(''); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); @@ -321,14 +321,23 @@ function CodeEditor({ file, onClose, projectPath }) { } `} -
-
+ {isSidebar ? ( +
Loading {file.name}...
-
+ ) : ( +
+
+
+
+ Loading {file.name}... +
+
+
+ )} ); } @@ -403,33 +412,32 @@ function CodeEditor({ file, onClose, projectPath }) { } `} -
-
+
{/* Header */} -
+
-
- - {file.name.split('.').pop()?.toUpperCase() || 'FILE'} - -
-

{file.name}

+

{file.name}

{file.diffInfo && ( - + 📝 Has changes )}
-

{file.path}

+

{file.path}

@@ -496,13 +504,15 @@ function CodeEditor({ file, onClose, projectPath }) { )} - + {!isSidebar && ( + + )}
diff --git a/src/components/MainContent.jsx b/src/components/MainContent.jsx index a9b1b81..dc84661 100644 --- a/src/components/MainContent.jsx +++ b/src/components/MainContent.jsx @@ -11,7 +11,7 @@ * No session protection logic is implemented here - it's purely a props bridge. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import ChatInterface from './ChatInterface'; import FileTree from './FileTree'; import CodeEditor from './CodeEditor'; @@ -28,13 +28,13 @@ import { useTaskMaster } from '../contexts/TaskMasterContext'; import { useTasksSettings } from '../contexts/TasksSettingsContext'; import { api } from '../utils/api'; -function MainContent({ - selectedProject, - selectedSession, - activeTab, - setActiveTab, - ws, - sendMessage, +function MainContent({ + selectedProject, + selectedSession, + activeTab, + setActiveTab, + ws, + sendMessage, messages, isMobile, isPWA, @@ -61,6 +61,9 @@ function MainContent({ const [editingFile, setEditingFile] = useState(null); const [selectedTask, setSelectedTask] = useState(null); const [showTaskDetail, setShowTaskDetail] = useState(false); + const [editorWidth, setEditorWidth] = useState(600); + const [isResizing, setIsResizing] = useState(false); + const resizeRef = useRef(null); // PRD Editor state const [showPRDEditor, setShowPRDEditor] = useState(false); @@ -153,6 +156,52 @@ function MainContent({ console.log('Update task status:', taskId, newStatus); refreshTasks?.(); }; + + // Handle resize functionality + const handleMouseDown = (e) => { + if (isMobile) return; // Disable resize on mobile + setIsResizing(true); + e.preventDefault(); + }; + + useEffect(() => { + const handleMouseMove = (e) => { + if (!isResizing) return; + + const container = resizeRef.current?.parentElement; + if (!container) return; + + const containerRect = container.getBoundingClientRect(); + const newWidth = containerRect.right - e.clientX; + + // Min width: 300px, Max width: 80% of container + const minWidth = 300; + const maxWidth = containerRect.width * 0.8; + + if (newWidth >= minWidth && newWidth <= maxWidth) { + setEditorWidth(newWidth); + } + }; + + const handleMouseUp = () => { + setIsResizing(false); + }; + + if (isResizing) { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + document.body.style.cursor = 'col-resize'; + document.body.style.userSelect = 'none'; + } + + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + }; + }, [isResizing]); + if (isLoading) { return (
@@ -234,10 +283,10 @@ function MainContent({ return (
{/* Header with tabs */} -
-
+
{isMobile && (
- {/* Content Area */} -
-
- - + {/* Main Content */} +
+
+ + setServerLogs([])} /> */}
+
+ + {/* Code Editor Right Sidebar - Desktop only, Mobile uses modal */} + {editingFile && !isMobile && ( + <> + {/* Resize Handle */} +
+ {/* Visual indicator on hover */} +
+
+ + {/* Editor Sidebar */} +
+ +
+ + )}
- {/* Code Editor Modal */} - {editingFile && ( + {/* Code Editor Modal for Mobile */} + {editingFile && isMobile && ( )}