diff --git a/frontend/src/App.js b/frontend/src/App.js
index 7b5634d..5b3a52b 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -1,14 +1,8 @@
import React from 'react';
-import {
- MantineProvider,
- ColorSchemeScript,
- AppShell,
- Container,
-} from '@mantine/core';
+import { MantineProvider, ColorSchemeScript } from '@mantine/core';
import { Notifications } from '@mantine/notifications';
import { ModalsProvider } from '@mantine/modals';
-import Header from './components/Header';
-import MainContent from './components/MainContent';
+import Layout from './components/Layout';
import { SettingsProvider, useSettings } from './contexts/SettingsContext';
import { ModalProvider } from './contexts/ModalContext';
import '@mantine/core/styles.css';
@@ -22,18 +16,7 @@ function AppContent() {
return
Loading...
;
}
- return (
-
-
-
-
-
-
-
-
-
-
- );
+ return ;
}
function App() {
diff --git a/frontend/src/components/Layout.js b/frontend/src/components/Layout.js
new file mode 100644
index 0000000..e766de5
--- /dev/null
+++ b/frontend/src/components/Layout.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import { AppShell, Container } from '@mantine/core';
+import Header from './Header';
+import Sidebar from './Sidebar';
+import MainContent from './MainContent';
+import { useFileNavigation } from '../hooks/useFileNavigation';
+
+const Layout = () => {
+ const { selectedFile, handleFileSelect, handleLinkClick } =
+ useFileNavigation();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Layout;
diff --git a/frontend/src/components/MainContent.js b/frontend/src/components/MainContent.js
index a461e3e..d4835dd 100644
--- a/frontend/src/components/MainContent.js
+++ b/frontend/src/components/MainContent.js
@@ -1,27 +1,20 @@
-import React, { useState, useCallback, useEffect } from 'react';
+import React, { useState, useCallback, useMemo } from 'react';
import { Tabs, Breadcrumbs, Group, Box, Text, Flex } from '@mantine/core';
import { IconCode, IconEye, IconPointFilled } from '@tabler/icons-react';
-import FileActions from './FileActions';
-import FileTree from './FileTree';
import ContentView from './ContentView';
import CreateFileModal from './modals/CreateFileModal';
import DeleteFileModal from './modals/DeleteFileModal';
import CommitMessageModal from './modals/CommitMessageModal';
import { useFileContent } from '../hooks/useFileContent';
-import { useFileList } from '../hooks/useFileList';
import { useFileOperations } from '../hooks/useFileOperations';
import { useGitOperations } from '../hooks/useGitOperations';
-import { useFileNavigation } from '../hooks/useFileNavigation';
import { useSettings } from '../contexts/SettingsContext';
-const MainContent = () => {
+const MainContent = ({ selectedFile, handleFileSelect, handleLinkClick }) => {
const [activeTab, setActiveTab] = useState('source');
const { settings } = useSettings();
- const { files, loadFileList } = useFileList();
- const { handleLinkClick, selectedFile, handleFileSelect } =
- useFileNavigation();
const {
content,
hasUnsavedChanges,
@@ -29,15 +22,11 @@ const MainContent = () => {
handleContentChange,
} = useFileContent(selectedFile);
const { handleSave, handleCreate, handleDelete } = useFileOperations();
- const { handleCommitAndPush, handlePull } = useGitOperations();
+ const { handleCommitAndPush } = useGitOperations(settings.gitEnabled);
- useEffect(() => {
- loadFileList();
- }, [settings.gitEnabled]);
-
- const handleTabChange = (value) => {
+ const handleTabChange = useCallback((value) => {
setActiveTab(value);
- };
+ }, []);
const handleSaveFile = useCallback(
async (filePath, content) => {
@@ -54,25 +43,23 @@ const MainContent = () => {
async (fileName) => {
const success = await handleCreate(fileName);
if (success) {
- await loadFileList();
handleFileSelect(fileName);
}
},
- [handleCreate, loadFileList, handleFileSelect]
+ [handleCreate, handleFileSelect]
);
const handleDeleteFile = useCallback(
async (filePath) => {
const success = await handleDelete(filePath);
if (success) {
- await loadFileList();
handleFileSelect(null);
}
},
- [handleDelete, loadFileList, handleFileSelect]
+ [handleDelete, handleFileSelect]
);
- const renderBreadcrumbs = () => {
+ const renderBreadcrumbs = useMemo(() => {
if (!selectedFile) return null;
const pathParts = selectedFile.split('/');
const items = pathParts.map((part, index) => (
@@ -92,56 +79,35 @@ const MainContent = () => {
)}
);
- };
+ }, [selectedFile, hasUnsavedChanges]);
return (
-
-
-
+
+ {renderBreadcrumbs}
+
+
+ } />
+ } />
+
+
+
+
+
-
-
-
-
- {renderBreadcrumbs()}
-
-
- }
- />
- }
- />
-
-
-
-
-
-
{
+ const { settings } = useSettings();
+ const { files, loadFileList } = useFileList();
+ const { handlePull } = useGitOperations(settings.gitEnabled);
+
+ useEffect(() => {
+ loadFileList();
+ }, [settings.gitEnabled, loadFileList]);
+
+ return (
+
+
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/frontend/src/contexts/SettingsContext.js b/frontend/src/contexts/SettingsContext.js
index 5dd3455..0a8df8d 100644
--- a/frontend/src/contexts/SettingsContext.js
+++ b/frontend/src/contexts/SettingsContext.js
@@ -1,4 +1,11 @@
-import React, { createContext, useContext, useEffect, useMemo } from 'react';
+import React, {
+ createContext,
+ useContext,
+ useEffect,
+ useMemo,
+ useCallback,
+ useState,
+} from 'react';
import { useMantineColorScheme } from '@mantine/core';
import { fetchUserSettings, saveUserSettings } from '../services/api';
import { DEFAULT_SETTINGS } from '../utils/constants';
@@ -9,8 +16,8 @@ export const useSettings = () => useContext(SettingsContext);
export const SettingsProvider = ({ children }) => {
const { colorScheme, setColorScheme } = useMantineColorScheme();
- const [settings, setSettings] = React.useState(DEFAULT_SETTINGS);
- const [loading, setLoading] = React.useState(true);
+ const [settings, setSettings] = useState(DEFAULT_SETTINGS);
+ const [loading, setLoading] = useState(true);
useEffect(() => {
const loadSettings = async () => {
@@ -26,30 +33,32 @@ export const SettingsProvider = ({ children }) => {
};
loadSettings();
- }, [setColorScheme]);
+ }, []);
- const updateSettings = async (newSettings) => {
- try {
- await saveUserSettings({
- userId: 1,
- settings: newSettings,
- });
- setSettings(newSettings);
- // Ensure the color scheme is updated when settings are saved
- if (newSettings.theme) {
- setColorScheme(newSettings.theme);
+ const updateSettings = useCallback(
+ async (newSettings) => {
+ try {
+ await saveUserSettings({
+ userId: 1,
+ settings: newSettings,
+ });
+ setSettings(newSettings);
+ if (newSettings.theme) {
+ setColorScheme(newSettings.theme);
+ }
+ } catch (error) {
+ console.error('Failed to save settings:', error);
+ throw error;
}
- } catch (error) {
- console.error('Failed to save settings:', error);
- throw error;
- }
- };
+ },
+ [setColorScheme]
+ );
- const toggleColorScheme = () => {
+ const toggleColorScheme = useCallback(() => {
const newTheme = colorScheme === 'dark' ? 'light' : 'dark';
setColorScheme(newTheme);
updateSettings({ ...settings, theme: newTheme });
- };
+ }, [colorScheme, settings, setColorScheme, updateSettings]);
const contextValue = useMemo(
() => ({
@@ -59,7 +68,7 @@ export const SettingsProvider = ({ children }) => {
loading,
colorScheme,
}),
- [settings, loading, colorScheme]
+ [settings, updateSettings, toggleColorScheme, loading, colorScheme]
);
return (