mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-16 01:12:46 +00:00
fix: make the codeeditor part of the system ui providers
This commit is contained in:
@@ -18,6 +18,8 @@ import { SystemUIProvider } from '@/components/refactored/shared/contexts/system
|
||||
import { RootLayout } from '@/components/refactored/shared/layout/RootLayout';
|
||||
import StandaloneShellRouterAdapter from '@/components/standalone-shell/view/StandaloneShellRouterAdapter';
|
||||
import FileTreeRouterAdapter from '@/components/file-tree/view/FileTreeRouterAdapter.js';
|
||||
import GitPanelRouterAdapter from '@/components/git-panel/view/GitPanelRouterAdapter.js';
|
||||
import { TaskMasterPanel } from '@/components/task-master/index.js';
|
||||
|
||||
const isValidRouteTab = (value: string | undefined): boolean => {
|
||||
if (!value) {
|
||||
@@ -120,6 +122,8 @@ const router = createBrowserRouter(
|
||||
{ index: true, element: <Navigate to="chat" replace /> },
|
||||
{ path: 'shell', element: <StandaloneShellRouterAdapter /> },
|
||||
{ path: 'files', element: <FileTreeRouterAdapter /> },
|
||||
{ path: 'git', element: <GitPanelRouterAdapter /> },
|
||||
{ path: 'tasks', element: <TaskMasterPanel isVisible={true} /> },
|
||||
{ path: ':tab', element: <WorkspaceTabRoute /> },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export type { CodeEditorFile } from '@/hooks/code-editor-sidebar/types.js';
|
||||
|
||||
export type CodeEditorSettingsState = {
|
||||
isDarkMode: boolean;
|
||||
wordWrap: boolean;
|
||||
|
||||
@@ -2,10 +2,10 @@ import { useState, useEffect, useRef } from 'react';
|
||||
import type { MouseEvent, MutableRefObject } from 'react';
|
||||
import CodeEditor from './CodeEditor';
|
||||
import { CodeEditorFile } from '@/hooks/code-editor-sidebar/types.js';
|
||||
import { useDeviceSettings } from '@/hooks/useDeviceSettings.js';
|
||||
|
||||
type EditorSidebarProps = {
|
||||
editingFile: CodeEditorFile | null;
|
||||
isMobile: boolean;
|
||||
editorExpanded: boolean;
|
||||
editorWidth: number;
|
||||
hasManualWidth: boolean;
|
||||
@@ -24,7 +24,6 @@ const MIN_EDITOR_WIDTH = 280;
|
||||
|
||||
export default function EditorSidebar({
|
||||
editingFile,
|
||||
isMobile,
|
||||
editorExpanded,
|
||||
editorWidth,
|
||||
hasManualWidth,
|
||||
@@ -39,6 +38,8 @@ export default function EditorSidebar({
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [effectiveWidth, setEffectiveWidth] = useState(editorWidth);
|
||||
|
||||
const { isMobile } = useDeviceSettings({ trackPWA: false });
|
||||
|
||||
// Adjust editor width when container size changes to ensure buttons are always visible
|
||||
useEffect(() => {
|
||||
if (!editingFile || isMobile || poppedOut) return;
|
||||
|
||||
114
src/components/code-editor/view/EditorSidebarRouterAdapter.tsx
Normal file
114
src/components/code-editor/view/EditorSidebarRouterAdapter.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* This is for backward compatibility with the old setup that point to the file tree route.
|
||||
* It fetches the project and session data based on the URL parameters and passes them to the FileTree component.
|
||||
* If no valid parameters are found, it defaults to an empty project.
|
||||
*
|
||||
* TODO: This adapter can be removed once all tabs use the updated projects and sessions format.
|
||||
*/
|
||||
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
getProjectsInLegacyFormat,
|
||||
getSessionInLegacyFormat,
|
||||
} from "@/components/refactored/sidebar/data/legacy-response-format-api.js";
|
||||
import { Project } from "@/types/app.js";
|
||||
import { useSystemUI } from "@/components/refactored/shared/contexts/system-ui-context/useSystemUI";
|
||||
import EditorSidebar from "@/components/code-editor/view/EditorSidebar.js";
|
||||
|
||||
export default function EditorSidebarRouterAdapter() {
|
||||
const { sessionId, workspaceId } = useParams<{
|
||||
sessionId?: string;
|
||||
workspaceId?: string;
|
||||
}>();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const {
|
||||
codeEditorSidebar: {
|
||||
editingFile,
|
||||
editorWidth,
|
||||
editorExpanded,
|
||||
hasManualWidth,
|
||||
resizeHandleRef,
|
||||
handleCloseEditor,
|
||||
handleToggleEditorExpand,
|
||||
handleResizeStart,
|
||||
},
|
||||
} = useSystemUI();
|
||||
|
||||
const [project, setProject] = useState<Project | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const fetchProjectAndSession = async () => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
if (workspaceId) {
|
||||
const fetchedProject = await getProjectsInLegacyFormat(workspaceId);
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(fetchedProject);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionId) {
|
||||
const result = await getSessionInLegacyFormat(sessionId);
|
||||
|
||||
if (!cancelled) {
|
||||
if (result) {
|
||||
setProject(result.project);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch project/session:", error);
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(null);
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchProjectAndSession();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [sessionId, workspaceId]);
|
||||
|
||||
const fillSpace = pathname.replace(/\/+$/, "").endsWith("/files");
|
||||
|
||||
if (loading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorSidebar
|
||||
editingFile={editingFile}
|
||||
editorExpanded={editorExpanded}
|
||||
editorWidth={editorWidth}
|
||||
hasManualWidth={hasManualWidth}
|
||||
resizeHandleRef={resizeHandleRef}
|
||||
onResizeStart={handleResizeStart}
|
||||
onCloseEditor={handleCloseEditor}
|
||||
onToggleEditorExpand={handleToggleEditorExpand}
|
||||
projectPath={project?.fullPath}
|
||||
fillSpace={fillSpace}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -47,7 +47,6 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps)
|
||||
|
||||
const { files, loading, refreshFiles } = useFileTreeData(selectedProject);
|
||||
|
||||
console.log("Files are: ", files)
|
||||
const { viewMode, changeViewMode } = useFileTreeViewMode();
|
||||
const { expandedDirs, toggleDirectory, expandDirectories, collapseAll } = useExpandedDirectories();
|
||||
const { searchQuery, setSearchQuery, filteredFiles } = useFileTreeSearch({
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
*/
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
getProjectsInLegacyFormat,
|
||||
getSessionInLegacyFormat,
|
||||
} from "@/components/refactored/sidebar/data/legacy-response-format-api.js";
|
||||
import { Project } from "@/types/app.js";
|
||||
import FileTree from "@/components/file-tree/view/FileTree.js";
|
||||
import { useEditorSidebar } from "@/hooks/code-editor-sidebar/useEditorSidebar.js";
|
||||
import { useSystemUI } from "@/components/refactored/shared/contexts/system-ui-context/useSystemUI";
|
||||
|
||||
export default function FileTreeRouterAdapter() {
|
||||
const { sessionId, workspaceId } = useParams<{
|
||||
@@ -22,7 +22,9 @@ export default function FileTreeRouterAdapter() {
|
||||
workspaceId?: string;
|
||||
}>();
|
||||
|
||||
const { handleFileOpen } = useEditorSidebar({});
|
||||
const {
|
||||
codeEditorSidebar: { handleFileOpen },
|
||||
} = useSystemUI();
|
||||
|
||||
const [project, setProject] = useState<Project | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -79,15 +81,18 @@ export default function FileTreeRouterAdapter() {
|
||||
};
|
||||
}, [sessionId, workspaceId]);
|
||||
|
||||
console.log("FileTreeRouterAdapter project:", project);
|
||||
const handleProjectFileOpen = useCallback(
|
||||
(filePath: string) => {
|
||||
handleFileOpen(filePath, null, project?.name);
|
||||
},
|
||||
[handleFileOpen, project?.name],
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
console.log("FileTreeRouterAdapter project:", project);
|
||||
|
||||
return (
|
||||
<FileTree onFileOpen={handleFileOpen} selectedProject={project} />
|
||||
<FileTree onFileOpen={handleProjectFileOpen} selectedProject={project} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,6 @@ export type FileDiffInfo = {
|
||||
|
||||
export type FileOpenHandler = (filePath: string, diffInfo?: FileDiffInfo) => void;
|
||||
|
||||
export type GitPanelProps = {
|
||||
selectedProject: Project | null;
|
||||
isMobile?: boolean;
|
||||
onFileOpen?: FileOpenHandler;
|
||||
};
|
||||
|
||||
export type GitStatusResponse = {
|
||||
branch?: string;
|
||||
hasCommits?: boolean;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useGitPanelController } from '../hooks/useGitPanelController';
|
||||
import { useRevertLocalCommit } from '../hooks/useRevertLocalCommit';
|
||||
import type { ConfirmationRequest, GitPanelProps, GitPanelView } from '../types/types';
|
||||
import type { ConfirmationRequest, FileOpenHandler, GitPanelView } from '../types/types';
|
||||
import { getChangedFileCount } from '../utils/gitPanelUtils';
|
||||
import ChangesView from '../view/changes/ChangesView';
|
||||
import HistoryView from '../view/history/HistoryView';
|
||||
@@ -10,13 +10,22 @@ import GitPanelHeader from '../view/GitPanelHeader';
|
||||
import GitRepositoryErrorState from '../view/GitRepositoryErrorState';
|
||||
import GitViewTabs from '../view/GitViewTabs';
|
||||
import ConfirmActionModal from '../view/modals/ConfirmActionModal';
|
||||
import { useDeviceSettings } from '@/hooks/useDeviceSettings.js';
|
||||
import { Project } from '@/types/app.js';
|
||||
|
||||
export default function GitPanel({ selectedProject, isMobile = false, onFileOpen }: GitPanelProps) {
|
||||
type GitPanelProps = {
|
||||
selectedProject: Project | null;
|
||||
onFileOpen?: FileOpenHandler;
|
||||
};
|
||||
|
||||
export default function GitPanel({ selectedProject, onFileOpen }: GitPanelProps) {
|
||||
const [activeView, setActiveView] = useState<GitPanelView>('changes');
|
||||
const [wrapText, setWrapText] = useState(true);
|
||||
const [hasExpandedFiles, setHasExpandedFiles] = useState(false);
|
||||
const [confirmAction, setConfirmAction] = useState<ConfirmationRequest | null>(null);
|
||||
|
||||
const { isMobile } = useDeviceSettings();
|
||||
|
||||
const {
|
||||
gitStatus,
|
||||
gitDiff,
|
||||
|
||||
99
src/components/git-panel/view/GitPanelRouterAdapter.tsx
Normal file
99
src/components/git-panel/view/GitPanelRouterAdapter.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* This is for backward compatibility with the old setup that point to the file tree route.
|
||||
* It fetches the project and session data based on the URL parameters and passes them to the FileTree component.
|
||||
* If no valid parameters are found, it defaults to an empty project.
|
||||
*
|
||||
* TODO: This adapter can be removed once all tabs use the updated projects and sessions format.
|
||||
*/
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
getProjectsInLegacyFormat,
|
||||
getSessionInLegacyFormat,
|
||||
} from "@/components/refactored/sidebar/data/legacy-response-format-api.js";
|
||||
import { Project } from "@/types/app.js";
|
||||
import GitPanel from "@/components/git-panel/view/GitPanel.js";
|
||||
import { useSystemUI } from "@/components/refactored/shared/contexts/system-ui-context/useSystemUI";
|
||||
import type { FileDiffInfo } from "@/components/git-panel/types/types";
|
||||
|
||||
export default function GitPanelRouterAdapter() {
|
||||
const { sessionId, workspaceId } = useParams<{
|
||||
sessionId?: string;
|
||||
workspaceId?: string;
|
||||
}>();
|
||||
|
||||
const {
|
||||
codeEditorSidebar: { handleFileOpen },
|
||||
} = useSystemUI();
|
||||
|
||||
const [project, setProject] = useState<Project | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const fetchProjectAndSession = async () => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
if (workspaceId) {
|
||||
const fetchedProject = await getProjectsInLegacyFormat(workspaceId);
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(fetchedProject);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionId) {
|
||||
const result = await getSessionInLegacyFormat(sessionId);
|
||||
|
||||
if (!cancelled) {
|
||||
if (result) {
|
||||
setProject(result.project);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch project/session:", error);
|
||||
|
||||
if (!cancelled) {
|
||||
setProject(null);
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchProjectAndSession();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [sessionId, workspaceId]);
|
||||
|
||||
const handleProjectFileOpen = useCallback(
|
||||
(filePath: string, diffInfo?: FileDiffInfo) => {
|
||||
handleFileOpen(filePath, diffInfo, project?.name);
|
||||
},
|
||||
[handleFileOpen, project?.name],
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<GitPanel selectedProject={project} onFileOpen={handleProjectFileOpen} />
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import ChatInterface from '../../chat/view/ChatInterface';
|
||||
import FileTree from '../../file-tree/view/FileTree';
|
||||
import StandaloneShell from '../../standalone-shell/view/StandaloneShell';
|
||||
@@ -8,13 +8,14 @@ import type { MainContentProps } from '../types/types';
|
||||
import { useTaskMaster } from '../../../contexts/TaskMasterContext';
|
||||
import { useTasksSettings } from '../../../contexts/TasksSettingsContext';
|
||||
import { useUiPreferences } from '../../../hooks/useUiPreferences';
|
||||
import { useEditorSidebar } from '../../../hooks/code-editor-sidebar/useEditorSidebar';
|
||||
import EditorSidebar from '../../code-editor/view/EditorSidebar';
|
||||
import type { Project } from '../../../types/app';
|
||||
import { TaskMasterPanel } from '../../task-master';
|
||||
import MainContentHeader from './subcomponents/MainContentHeader';
|
||||
import MainContentStateView from './subcomponents/MainContentStateView';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import { useSystemUI } from '@/components/refactored/shared/contexts/system-ui-context/useSystemUI';
|
||||
import type { OpenEditorFileHandler } from '@/hooks/code-editor-sidebar/useEditorSidebar';
|
||||
|
||||
type TaskMasterContextValue = {
|
||||
currentProject?: Project | null;
|
||||
@@ -54,20 +55,28 @@ function MainContent({
|
||||
|
||||
const { currentProject, setCurrentProject } = useTaskMaster() as TaskMasterContextValue;
|
||||
const { tasksEnabled, isTaskMasterInstalled } = useTasksSettings() as TasksSettingsContextValue;
|
||||
const {
|
||||
codeEditorSidebar: {
|
||||
editingFile,
|
||||
editorWidth,
|
||||
editorExpanded,
|
||||
hasManualWidth,
|
||||
resizeHandleRef,
|
||||
handleFileOpen,
|
||||
handleCloseEditor,
|
||||
handleToggleEditorExpand,
|
||||
handleResizeStart,
|
||||
},
|
||||
} = useSystemUI();
|
||||
|
||||
const shouldShowTasksTab = Boolean(tasksEnabled && isTaskMasterInstalled);
|
||||
|
||||
const {
|
||||
editingFile,
|
||||
editorWidth,
|
||||
editorExpanded,
|
||||
hasManualWidth,
|
||||
resizeHandleRef,
|
||||
handleFileOpen,
|
||||
handleCloseEditor,
|
||||
handleToggleEditorExpand,
|
||||
handleResizeStart,
|
||||
} = useEditorSidebar({});
|
||||
const handleProjectFileOpen = useCallback<OpenEditorFileHandler>(
|
||||
(filePath, diffInfo = null) => {
|
||||
handleFileOpen(filePath, diffInfo, selectedProject?.name);
|
||||
},
|
||||
[handleFileOpen, selectedProject?.name],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const selectedProjectName = selectedProject?.name;
|
||||
@@ -114,7 +123,7 @@ function MainContent({
|
||||
ws={ws}
|
||||
sendMessage={sendMessage}
|
||||
latestMessage={latestMessage}
|
||||
onFileOpen={handleFileOpen}
|
||||
onFileOpen={handleProjectFileOpen}
|
||||
onInputFocusChange={onInputFocusChange}
|
||||
onSessionActive={onSessionActive}
|
||||
onSessionInactive={onSessionInactive}
|
||||
@@ -137,7 +146,7 @@ function MainContent({
|
||||
|
||||
{activeTab === 'files' && (
|
||||
<div className="h-full overflow-hidden">
|
||||
<FileTree selectedProject={selectedProject} onFileOpen={handleFileOpen} />
|
||||
<FileTree selectedProject={selectedProject} onFileOpen={(filePath) => handleFileOpen(filePath, null, selectedProject.name)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -154,7 +163,7 @@ function MainContent({
|
||||
|
||||
{activeTab === 'git' && (
|
||||
<div className="h-full overflow-hidden">
|
||||
<GitPanel selectedProject={selectedProject} isMobile={isMobile} onFileOpen={handleFileOpen} />
|
||||
<GitPanel selectedProject={selectedProject} onFileOpen={(filePath, diffInfo) => handleFileOpen(filePath, diffInfo, selectedProject.name)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -175,7 +184,6 @@ function MainContent({
|
||||
|
||||
<EditorSidebar
|
||||
editingFile={editingFile}
|
||||
isMobile={isMobile}
|
||||
editorExpanded={editorExpanded}
|
||||
editorWidth={editorWidth}
|
||||
hasManualWidth={hasManualWidth}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { createContext } from 'react';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import type { UseEditorSidebarReturn } from '@/hooks/code-editor-sidebar/useEditorSidebar';
|
||||
|
||||
export type SystemUIContextValue = {
|
||||
sidebarIsCollapsed: boolean;
|
||||
setSidebarIsCollapsed: Dispatch<SetStateAction<boolean>>;
|
||||
isChatInputFocused: boolean;
|
||||
setIsChatInputFocused: Dispatch<SetStateAction<boolean>>;
|
||||
codeEditorSidebar: UseEditorSidebarReturn;
|
||||
};
|
||||
|
||||
export const SystemUIContext = createContext<SystemUIContextValue | null>(null);
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { useMemo, useState, type ReactNode } from 'react';
|
||||
import { SystemUIContext, type SystemUIContextValue } from '@/components/refactored/shared/contexts/system-ui-context/SystemUIContext';
|
||||
import { useEditorSidebar } from '@/hooks/code-editor-sidebar/useEditorSidebar';
|
||||
|
||||
export function SystemUIProvider({ children }: { children: ReactNode }) {
|
||||
const [sidebarIsCollapsed, setSidebarIsCollapsed] = useState(false);
|
||||
const [isChatInputFocused, setIsChatInputFocused] = useState(false);
|
||||
const {
|
||||
editingFile,
|
||||
editorWidth,
|
||||
editorExpanded,
|
||||
hasManualWidth,
|
||||
resizeHandleRef,
|
||||
handleFileOpen,
|
||||
handleCloseEditor,
|
||||
handleToggleEditorExpand,
|
||||
handleResizeStart,
|
||||
} = useEditorSidebar({});
|
||||
|
||||
const value = useMemo<SystemUIContextValue>(
|
||||
() => ({
|
||||
@@ -11,8 +23,31 @@ export function SystemUIProvider({ children }: { children: ReactNode }) {
|
||||
setSidebarIsCollapsed,
|
||||
isChatInputFocused,
|
||||
setIsChatInputFocused,
|
||||
codeEditorSidebar: {
|
||||
editingFile,
|
||||
editorWidth,
|
||||
editorExpanded,
|
||||
hasManualWidth,
|
||||
resizeHandleRef,
|
||||
handleFileOpen,
|
||||
handleCloseEditor,
|
||||
handleToggleEditorExpand,
|
||||
handleResizeStart,
|
||||
},
|
||||
}),
|
||||
[isChatInputFocused, sidebarIsCollapsed],
|
||||
[
|
||||
editingFile,
|
||||
editorExpanded,
|
||||
editorWidth,
|
||||
handleCloseEditor,
|
||||
handleFileOpen,
|
||||
handleResizeStart,
|
||||
handleToggleEditorExpand,
|
||||
hasManualWidth,
|
||||
isChatInputFocused,
|
||||
resizeHandleRef,
|
||||
sidebarIsCollapsed,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,10 +2,13 @@ import { Outlet } from 'react-router-dom';
|
||||
import { Sidebar } from '@/components/refactored/sidebar/view/Sidebar';
|
||||
import { MainHeading } from '@/components/refactored/shared/layout/MainHeading';
|
||||
import { MobileNav } from '@/components/refactored/shared/layout/MobileNav';
|
||||
import EditorSidebarRouterAdapter from '@/components/code-editor/view/EditorSidebarRouterAdapter';
|
||||
import { useDeviceSettings } from '@/hooks/useDeviceSettings';
|
||||
import { useSystemUI } from '@/components/refactored/shared/contexts/system-ui-context/useSystemUI.js';
|
||||
|
||||
export function RootLayout() {
|
||||
const { isMobile } = useDeviceSettings({ trackPWA: false });
|
||||
const { codeEditorSidebar: { editorExpanded } } = useSystemUI();
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-full overflow-hidden bg-background">
|
||||
@@ -13,7 +16,12 @@ export function RootLayout() {
|
||||
<div className={`flex min-w-0 flex-1 flex-col ${isMobile ? 'pb-mobile-nav' : ''}`}>
|
||||
<MainHeading />
|
||||
<main className="relative min-h-0 flex-1 overflow-hidden">
|
||||
<Outlet />
|
||||
<div className="flex h-full min-h-0 overflow-hidden">
|
||||
<div className={`flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden ${editorExpanded ? 'hidden' : ''}`}>
|
||||
<Outlet />
|
||||
</div>
|
||||
<EditorSidebarRouterAdapter />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<MobileNav />
|
||||
|
||||
@@ -7,6 +7,7 @@ export type CodeEditorDiffInfo = {
|
||||
export type CodeEditorFile = {
|
||||
name: string;
|
||||
path: string;
|
||||
projectName?: string;
|
||||
diffInfo?: CodeEditorDiffInfo | null;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import type { MouseEvent as ReactMouseEvent } from 'react';
|
||||
import type { MouseEvent as ReactMouseEvent, MutableRefObject } from 'react';
|
||||
import { CodeEditorFile, CodeEditorDiffInfo } from '@/hooks/code-editor-sidebar/types.js';
|
||||
import { useDeviceSettings } from '@/hooks/useDeviceSettings.js';
|
||||
|
||||
@@ -8,6 +8,24 @@ type UseEditorSidebarOptions = {
|
||||
initialWidth?: number;
|
||||
};
|
||||
|
||||
export type OpenEditorFileHandler = (
|
||||
filePath: string,
|
||||
diffInfo?: CodeEditorDiffInfo | null,
|
||||
projectName?: string,
|
||||
) => void;
|
||||
|
||||
export type UseEditorSidebarReturn = {
|
||||
editingFile: CodeEditorFile | null;
|
||||
editorWidth: number;
|
||||
editorExpanded: boolean;
|
||||
hasManualWidth: boolean;
|
||||
resizeHandleRef: MutableRefObject<HTMLDivElement | null>;
|
||||
handleFileOpen: OpenEditorFileHandler;
|
||||
handleCloseEditor: () => void;
|
||||
handleToggleEditorExpand: () => void;
|
||||
handleResizeStart: (event: ReactMouseEvent<HTMLDivElement>) => void;
|
||||
};
|
||||
|
||||
// TODO: Remove every parameter here (except initial width)
|
||||
// selectedProject is only used to set projectName on the file being edited. It turns out that projectName
|
||||
// isn't actually used anywhere in the code editor, so it can be removed without affecting functionality. If we do want to keep track of projectName for some reason, we can set it in the MainContent component where the file is opened instead of here.
|
||||
@@ -15,7 +33,7 @@ type UseEditorSidebarOptions = {
|
||||
//
|
||||
export const useEditorSidebar = ({
|
||||
initialWidth = 600,
|
||||
}: UseEditorSidebarOptions) => {
|
||||
}: UseEditorSidebarOptions): UseEditorSidebarReturn => {
|
||||
const [editingFile, setEditingFile] = useState<CodeEditorFile | null>(null);
|
||||
const [editorWidth, setEditorWidth] = useState(initialWidth);
|
||||
const [editorExpanded, setEditorExpanded] = useState(false);
|
||||
@@ -25,14 +43,15 @@ export const useEditorSidebar = ({
|
||||
|
||||
const { isMobile } = useDeviceSettings({ trackPWA: false });
|
||||
|
||||
const handleFileOpen = useCallback(
|
||||
(filePath: string, diffInfo: CodeEditorDiffInfo | null = null) => {
|
||||
const handleFileOpen = useCallback<OpenEditorFileHandler>(
|
||||
(filePath, diffInfo = null, projectName) => {
|
||||
const normalizedPath = filePath.replace(/\\/g, '/');
|
||||
const fileName = normalizedPath.split('/').pop() || filePath;
|
||||
|
||||
setEditingFile({
|
||||
name: fileName,
|
||||
path: filePath,
|
||||
projectName,
|
||||
diffInfo,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -110,9 +110,9 @@ export const api = {
|
||||
body: JSON.stringify(workspaceData),
|
||||
}),
|
||||
readFile: (projectName, filePath) =>
|
||||
authenticatedFetch(`/api/projects/${projectName}/file?filePath=${encodeURIComponent(filePath)}`),
|
||||
authenticatedFetch(`/api/projects/${encodeURIComponent(projectName)}/file?filePath=${encodeURIComponent(filePath)}`),
|
||||
saveFile: (projectName, filePath, content) =>
|
||||
authenticatedFetch(`/api/projects/${projectName}/file`, {
|
||||
authenticatedFetch(`/api/projects/${encodeURIComponent(projectName)}/file`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ filePath, content }),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user