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 (