mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-02-28 11:37:39 +00:00
feature: swap default code editor to sidebar and make the modal optional
This commit is contained in:
@@ -143,7 +143,7 @@ function MarkdownPreview({ content }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded = false, onToggleExpand = null }) {
|
function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded = false, onToggleExpand = null, onPopOut = null }) {
|
||||||
const { t } = useTranslation('codeEditor');
|
const { t } = useTranslation('codeEditor');
|
||||||
const [content, setContent] = useState('');
|
const [content, setContent] = useState('');
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -165,7 +165,7 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
return localStorage.getItem('codeEditorLineNumbers') !== 'false';
|
return localStorage.getItem('codeEditorLineNumbers') !== 'false';
|
||||||
});
|
});
|
||||||
const [fontSize, setFontSize] = useState(() => {
|
const [fontSize, setFontSize] = useState(() => {
|
||||||
return localStorage.getItem('codeEditorFontSize') || '14';
|
return localStorage.getItem('codeEditorFontSize') || '12';
|
||||||
});
|
});
|
||||||
const [markdownPreview, setMarkdownPreview] = useState(false);
|
const [markdownPreview, setMarkdownPreview] = useState(false);
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
@@ -304,6 +304,16 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
if (isSidebar && onPopOut) {
|
||||||
|
toolbarHTML += `
|
||||||
|
<button class="cm-toolbar-btn cm-popout-btn" title="Open in modal">
|
||||||
|
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// Expand button (only in sidebar mode)
|
// Expand button (only in sidebar mode)
|
||||||
if (isSidebar && onToggleExpand) {
|
if (isSidebar && onToggleExpand) {
|
||||||
toolbarHTML += `
|
toolbarHTML += `
|
||||||
@@ -323,7 +333,6 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
|
|
||||||
dom.innerHTML = toolbarHTML;
|
dom.innerHTML = toolbarHTML;
|
||||||
|
|
||||||
// Attach event listeners for diff navigation
|
|
||||||
if (hasDiff) {
|
if (hasDiff) {
|
||||||
const prevBtn = dom.querySelector('.cm-diff-nav-prev');
|
const prevBtn = dom.querySelector('.cm-diff-nav-prev');
|
||||||
const nextBtn = dom.querySelector('.cm-diff-nav-next');
|
const nextBtn = dom.querySelector('.cm-diff-nav-next');
|
||||||
@@ -355,7 +364,6 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach event listener for toggle diff button
|
|
||||||
if (file.diffInfo) {
|
if (file.diffInfo) {
|
||||||
const toggleDiffBtn = dom.querySelector('.cm-toggle-diff-btn');
|
const toggleDiffBtn = dom.querySelector('.cm-toggle-diff-btn');
|
||||||
toggleDiffBtn?.addEventListener('click', () => {
|
toggleDiffBtn?.addEventListener('click', () => {
|
||||||
@@ -363,7 +371,6 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach event listener for settings button
|
|
||||||
const settingsBtn = dom.querySelector('.cm-settings-btn');
|
const settingsBtn = dom.querySelector('.cm-settings-btn');
|
||||||
settingsBtn?.addEventListener('click', () => {
|
settingsBtn?.addEventListener('click', () => {
|
||||||
if (window.openSettings) {
|
if (window.openSettings) {
|
||||||
@@ -371,7 +378,13 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Attach event listener for expand button
|
if (isSidebar && onPopOut) {
|
||||||
|
const popoutBtn = dom.querySelector('.cm-popout-btn');
|
||||||
|
popoutBtn?.addEventListener('click', () => {
|
||||||
|
onPopOut();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isSidebar && onToggleExpand) {
|
if (isSidebar && onToggleExpand) {
|
||||||
const expandBtn = dom.querySelector('.cm-expand-btn');
|
const expandBtn = dom.querySelector('.cm-expand-btn');
|
||||||
expandBtn?.addEventListener('click', () => {
|
expandBtn?.addEventListener('click', () => {
|
||||||
@@ -390,7 +403,7 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
};
|
};
|
||||||
|
|
||||||
return [showPanel.of(createPanel)];
|
return [showPanel.of(createPanel)];
|
||||||
}, [file.diffInfo, showDiff, isSidebar, isExpanded, onToggleExpand]);
|
}, [file.diffInfo, showDiff, isSidebar, isExpanded, onToggleExpand, onPopOut]);
|
||||||
|
|
||||||
// Get language extension based on file extension
|
// Get language extension based on file extension
|
||||||
const getLanguageExtension = (filename) => {
|
const getLanguageExtension = (filename) => {
|
||||||
@@ -666,16 +679,16 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
|
|
||||||
/* Editor toolbar panel styling */
|
/* Editor toolbar panel styling */
|
||||||
.cm-editor-toolbar-panel {
|
.cm-editor-toolbar-panel {
|
||||||
padding: 8px 12px;
|
padding: 4px 10px;
|
||||||
background-color: ${isDarkMode ? '#1f2937' : '#ffffff'};
|
background-color: ${isDarkMode ? '#1f2937' : '#ffffff'};
|
||||||
border-bottom: 1px solid ${isDarkMode ? '#374151' : '#e5e7eb'};
|
border-bottom: 1px solid ${isDarkMode ? '#374151' : '#e5e7eb'};
|
||||||
color: ${isDarkMode ? '#d1d5db' : '#374151'};
|
color: ${isDarkMode ? '#d1d5db' : '#374151'};
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-diff-nav-btn,
|
.cm-diff-nav-btn,
|
||||||
.cm-toolbar-btn {
|
.cm-toolbar-btn {
|
||||||
padding: 4px;
|
padding: 3px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -712,72 +725,67 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
(isFullscreen ? ' md:w-full md:h-full md:rounded-none' : ' md:w-full md:max-w-6xl md:h-[80vh] md:max-h-[80vh]')
|
(isFullscreen ? ' md:w-full md:h-full md:rounded-none' : ' md:w-full md:max-w-6xl md:h-[80vh] md:max-h-[80vh]')
|
||||||
}`}>
|
}`}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-border flex-shrink-0 min-w-0">
|
<div className="flex items-center justify-between px-3 py-1.5 border-b border-border flex-shrink-0 min-w-0">
|
||||||
<div className="flex items-center gap-3 min-w-0 flex-1">
|
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="flex items-center gap-2 min-w-0">
|
<div className="flex items-center gap-2 min-w-0">
|
||||||
<h3 className="font-medium text-gray-900 dark:text-white truncate">{file.name}</h3>
|
<h3 className="text-sm font-medium text-gray-900 dark:text-white truncate">{file.name}</h3>
|
||||||
{file.diffInfo && (
|
{file.diffInfo && (
|
||||||
<span className="text-xs bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 px-2 py-1 rounded whitespace-nowrap">
|
<span className="text-[10px] bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 px-1.5 py-0.5 rounded whitespace-nowrap">
|
||||||
{t('header.showingChanges')}
|
{t('header.showingChanges')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 truncate">{file.path}</p>
|
<p className="text-xs text-gray-500 dark:text-gray-400 truncate">{file.path}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-1 md:gap-2 flex-shrink-0">
|
<div className="flex items-center gap-0.5 md:gap-1 flex-shrink-0">
|
||||||
{isMarkdownFile && (
|
{isMarkdownFile && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setMarkdownPreview(!markdownPreview)}
|
onClick={() => setMarkdownPreview(!markdownPreview)}
|
||||||
className={`p-2 md:p-2 rounded-md min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-center transition-colors ${
|
className={`p-1.5 rounded-md min-w-[36px] min-h-[36px] md:min-w-0 md:min-h-0 flex items-center justify-center transition-colors ${
|
||||||
markdownPreview
|
markdownPreview
|
||||||
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30'
|
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30'
|
||||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800'
|
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||||
}`}
|
}`}
|
||||||
title={markdownPreview ? t('actions.editMarkdown') : t('actions.previewMarkdown')}
|
title={markdownPreview ? t('actions.editMarkdown') : t('actions.previewMarkdown')}
|
||||||
>
|
>
|
||||||
{markdownPreview ? <Code2 className="w-5 h-5 md:w-4 md:h-4" /> : <Eye className="w-5 h-5 md:w-4 md:h-4" />}
|
{markdownPreview ? <Code2 className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
className="p-2 md:p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
className="p-1.5 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 min-w-[36px] min-h-[36px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
||||||
title={t('actions.download')}
|
title={t('actions.download')}
|
||||||
>
|
>
|
||||||
<Download className="w-5 h-5 md:w-4 md:h-4" />
|
<Download className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
className={`px-3 py-2 text-white rounded-md disabled:opacity-50 flex items-center gap-2 transition-colors min-h-[44px] md:min-h-0 ${
|
className={`p-1.5 rounded-md disabled:opacity-50 flex items-center justify-center transition-colors min-w-[36px] min-h-[36px] md:min-w-0 md:min-h-0 ${
|
||||||
saveSuccess
|
saveSuccess
|
||||||
? 'bg-green-600 hover:bg-green-700'
|
? 'text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/30'
|
||||||
: 'bg-blue-600 hover:bg-blue-700'
|
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||||
}`}
|
}`}
|
||||||
|
title={saveSuccess ? t('actions.saved') : saving ? t('actions.saving') : t('actions.save')}
|
||||||
>
|
>
|
||||||
{saveSuccess ? (
|
{saveSuccess ? (
|
||||||
<>
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<svg className="w-5 h-5 md:w-4 md:h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
</svg>
|
||||||
</svg>
|
|
||||||
<span className="hidden sm:inline">{t('actions.saved')}</span>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<Save className="w-4 h-4" />
|
||||||
<Save className="w-5 h-5 md:w-4 md:h-4" />
|
|
||||||
<span className="hidden sm:inline">{saving ? t('actions.saving') : t('actions.save')}</span>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{!isSidebar && (
|
{!isSidebar && (
|
||||||
<button
|
<button
|
||||||
onClick={toggleFullscreen}
|
onClick={toggleFullscreen}
|
||||||
className="hidden md:flex p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 items-center justify-center"
|
className="hidden md:flex p-1.5 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 items-center justify-center"
|
||||||
title={isFullscreen ? t('actions.exitFullscreen') : t('actions.fullscreen')}
|
title={isFullscreen ? t('actions.exitFullscreen') : t('actions.fullscreen')}
|
||||||
>
|
>
|
||||||
{isFullscreen ? <Minimize2 className="w-4 h-4" /> : <Maximize2 className="w-4 h-4" />}
|
{isFullscreen ? <Minimize2 className="w-4 h-4" /> : <Maximize2 className="w-4 h-4" />}
|
||||||
@@ -786,10 +794,10 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="p-2 md:p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
className="p-1.5 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 min-w-[36px] min-h-[36px] md:min-w-0 md:min-h-0 flex items-center justify-center"
|
||||||
title={t('actions.close')}
|
title={t('actions.close')}
|
||||||
>
|
>
|
||||||
<X className="w-6 h-6 md:w-4 md:h-4" />
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -851,13 +859,13 @@ function CodeEditor({ file, onClose, projectPath, isSidebar = false, isExpanded
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="flex items-center justify-between p-3 border-t border-border bg-muted flex-shrink-0">
|
<div className="flex items-center justify-between px-3 py-1.5 border-t border-border bg-muted flex-shrink-0">
|
||||||
<div className="flex items-center gap-4 text-sm text-gray-600 dark:text-gray-400">
|
<div className="flex items-center gap-3 text-xs text-gray-600 dark:text-gray-400">
|
||||||
<span>{t('footer.lines')} {content.split('\n').length}</span>
|
<span>{t('footer.lines')} {content.split('\n').length}</span>
|
||||||
<span>{t('footer.characters')} {content.length}</span>
|
<span>{t('footer.characters')} {content.length}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
{t('footer.shortcuts')}
|
{t('footer.shortcuts')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
Scroll, FlaskConical, NotebookPen, FileCheck, Workflow, Blocks
|
Scroll, FlaskConical, NotebookPen, FileCheck, Workflow, Blocks
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
import CodeEditor from './CodeEditor';
|
|
||||||
import ImageViewer from './ImageViewer';
|
import ImageViewer from './ImageViewer';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
|
|
||||||
@@ -260,12 +259,11 @@ function getFileIconData(filename) {
|
|||||||
|
|
||||||
// ─── Component ───────────────────────────────────────────────────────
|
// ─── Component ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
function FileTree({ selectedProject }) {
|
function FileTree({ selectedProject, onFileOpen }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [expandedDirs, setExpandedDirs] = useState(new Set());
|
const [expandedDirs, setExpandedDirs] = useState(new Set());
|
||||||
const [selectedFile, setSelectedFile] = useState(null);
|
|
||||||
const [selectedImage, setSelectedImage] = useState(null);
|
const [selectedImage, setSelectedImage] = useState(null);
|
||||||
const [viewMode, setViewMode] = useState('detailed');
|
const [viewMode, setViewMode] = useState('detailed');
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
@@ -403,13 +401,8 @@ function FileTree({ selectedProject }) {
|
|||||||
projectPath: selectedProject.path,
|
projectPath: selectedProject.path,
|
||||||
projectName: selectedProject.name
|
projectName: selectedProject.name
|
||||||
});
|
});
|
||||||
} else {
|
} else if (onFileOpen) {
|
||||||
setSelectedFile({
|
onFileOpen(item.path);
|
||||||
name: item.name,
|
|
||||||
path: item.path,
|
|
||||||
projectPath: selectedProject.path,
|
|
||||||
projectName: selectedProject.name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -722,15 +715,6 @@ function FileTree({ selectedProject }) {
|
|||||||
)}
|
)}
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
{/* Code Editor Modal */}
|
|
||||||
{selectedFile && (
|
|
||||||
<CodeEditor
|
|
||||||
file={selectedFile}
|
|
||||||
onClose={() => setSelectedFile(null)}
|
|
||||||
projectPath={selectedFile.projectPath}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Image Viewer Modal */}
|
{/* Image Viewer Modal */}
|
||||||
{selectedImage && (
|
{selectedImage && (
|
||||||
<ImageViewer
|
<ImageViewer
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export interface EditorSidebarProps {
|
|||||||
onCloseEditor: () => void;
|
onCloseEditor: () => void;
|
||||||
onToggleEditorExpand: () => void;
|
onToggleEditorExpand: () => void;
|
||||||
projectPath?: string;
|
projectPath?: string;
|
||||||
|
fillSpace?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskMasterPanelProps {
|
export interface TaskMasterPanelProps {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ function MainContent({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex-1 flex min-h-0 overflow-hidden">
|
<div className="flex-1 flex min-h-0 overflow-hidden">
|
||||||
<div className={`flex-1 flex flex-col min-h-0 overflow-hidden ${editorExpanded ? 'hidden' : ''}`}>
|
<div className={`flex flex-col min-h-0 overflow-hidden ${editorExpanded ? 'hidden' : ''} ${activeTab === 'files' && editingFile ? 'w-[280px] flex-shrink-0' : 'flex-1'}`}>
|
||||||
<div className={`h-full ${activeTab === 'chat' ? 'block' : 'hidden'}`}>
|
<div className={`h-full ${activeTab === 'chat' ? 'block' : 'hidden'}`}>
|
||||||
<ErrorBoundary showDetails>
|
<ErrorBoundary showDetails>
|
||||||
<ChatInterface
|
<ChatInterface
|
||||||
@@ -141,7 +141,7 @@ function MainContent({
|
|||||||
|
|
||||||
{activeTab === 'files' && (
|
{activeTab === 'files' && (
|
||||||
<div className="h-full overflow-hidden">
|
<div className="h-full overflow-hidden">
|
||||||
<FileTree selectedProject={selectedProject} />
|
<FileTree selectedProject={selectedProject} onFileOpen={handleFileOpen} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -172,6 +172,7 @@ function MainContent({
|
|||||||
onCloseEditor={handleCloseEditor}
|
onCloseEditor={handleCloseEditor}
|
||||||
onToggleEditorExpand={handleToggleEditorExpand}
|
onToggleEditorExpand={handleToggleEditorExpand}
|
||||||
projectPath={selectedProject.path}
|
projectPath={selectedProject.path}
|
||||||
|
fillSpace={activeTab === 'files'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import CodeEditor from '../../../CodeEditor';
|
import CodeEditor from '../../../CodeEditor';
|
||||||
import type { EditorSidebarProps } from '../../types/types';
|
import type { EditorSidebarProps } from '../../types/types';
|
||||||
|
|
||||||
@@ -13,22 +14,30 @@ export default function EditorSidebar({
|
|||||||
onCloseEditor,
|
onCloseEditor,
|
||||||
onToggleEditorExpand,
|
onToggleEditorExpand,
|
||||||
projectPath,
|
projectPath,
|
||||||
|
fillSpace,
|
||||||
}: EditorSidebarProps) {
|
}: EditorSidebarProps) {
|
||||||
|
const [poppedOut, setPoppedOut] = useState(false);
|
||||||
|
|
||||||
if (!editingFile) {
|
if (!editingFile) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile || poppedOut) {
|
||||||
return (
|
return (
|
||||||
<AnyCodeEditor
|
<AnyCodeEditor
|
||||||
file={editingFile}
|
file={editingFile}
|
||||||
onClose={onCloseEditor}
|
onClose={() => {
|
||||||
|
setPoppedOut(false);
|
||||||
|
onCloseEditor();
|
||||||
|
}}
|
||||||
projectPath={projectPath}
|
projectPath={projectPath}
|
||||||
isSidebar={false}
|
isSidebar={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useFlex = editorExpanded || fillSpace;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!editorExpanded && (
|
{!editorExpanded && (
|
||||||
@@ -43,8 +52,8 @@ export default function EditorSidebar({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-l border-gray-200 dark:border-gray-700 h-full overflow-hidden ${editorExpanded ? 'flex-1' : ''}`}
|
className={`flex-shrink-0 border-l border-gray-200 dark:border-gray-700 h-full overflow-hidden ${useFlex ? 'flex-1' : ''}`}
|
||||||
style={editorExpanded ? undefined : { width: `${editorWidth}px` }}
|
style={useFlex ? undefined : { width: `${editorWidth}px` }}
|
||||||
>
|
>
|
||||||
<AnyCodeEditor
|
<AnyCodeEditor
|
||||||
file={editingFile}
|
file={editingFile}
|
||||||
@@ -53,6 +62,7 @@ export default function EditorSidebar({
|
|||||||
isSidebar
|
isSidebar
|
||||||
isExpanded={editorExpanded}
|
isExpanded={editorExpanded}
|
||||||
onToggleExpand={onToggleEditorExpand}
|
onToggleExpand={onToggleEditorExpand}
|
||||||
|
onPopOut={() => setPoppedOut(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user