Update layout

This commit is contained in:
2024-10-11 23:57:45 +02:00
parent d29732f5e9
commit 563de5aa2d
5 changed files with 148 additions and 109 deletions

View File

@@ -1,14 +1,8 @@
import React from 'react'; import React from 'react';
import { import { MantineProvider, ColorSchemeScript } from '@mantine/core';
MantineProvider,
ColorSchemeScript,
AppShell,
Container,
} from '@mantine/core';
import { Notifications } from '@mantine/notifications'; import { Notifications } from '@mantine/notifications';
import { ModalsProvider } from '@mantine/modals'; import { ModalsProvider } from '@mantine/modals';
import Header from './components/Header'; import Layout from './components/Layout';
import MainContent from './components/MainContent';
import { SettingsProvider, useSettings } from './contexts/SettingsContext'; import { SettingsProvider, useSettings } from './contexts/SettingsContext';
import { ModalProvider } from './contexts/ModalContext'; import { ModalProvider } from './contexts/ModalContext';
import '@mantine/core/styles.css'; import '@mantine/core/styles.css';
@@ -22,18 +16,7 @@ function AppContent() {
return <div>Loading...</div>; return <div>Loading...</div>;
} }
return ( return <Layout />;
<AppShell header={{ height: 60 }} padding="md">
<AppShell.Header>
<Header />
</AppShell.Header>
<AppShell.Main>
<Container size="xl">
<MainContent />
</Container>
</AppShell.Main>
</AppShell>
);
} }
function App() { function App() {

View File

@@ -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 (
<AppShell header={{ height: 60 }} padding="md">
<AppShell.Header>
<Header />
</AppShell.Header>
<AppShell.Main>
<Container
size="xl"
p={0}
style={{
display: 'flex',
height: 'calc(100vh - 60px - 2rem)', // Subtracting header height and vertical padding
overflow: 'hidden', // Prevent scrolling in the container
}}
>
<Sidebar
selectedFile={selectedFile}
handleFileSelect={handleFileSelect}
/>
<MainContent
selectedFile={selectedFile}
handleFileSelect={handleFileSelect}
handleLinkClick={handleLinkClick}
/>
</Container>
</AppShell.Main>
</AppShell>
);
};
export default Layout;

View File

@@ -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 { Tabs, Breadcrumbs, Group, Box, Text, Flex } from '@mantine/core';
import { IconCode, IconEye, IconPointFilled } from '@tabler/icons-react'; import { IconCode, IconEye, IconPointFilled } from '@tabler/icons-react';
import FileActions from './FileActions';
import FileTree from './FileTree';
import ContentView from './ContentView'; import ContentView from './ContentView';
import CreateFileModal from './modals/CreateFileModal'; import CreateFileModal from './modals/CreateFileModal';
import DeleteFileModal from './modals/DeleteFileModal'; import DeleteFileModal from './modals/DeleteFileModal';
import CommitMessageModal from './modals/CommitMessageModal'; import CommitMessageModal from './modals/CommitMessageModal';
import { useFileContent } from '../hooks/useFileContent'; import { useFileContent } from '../hooks/useFileContent';
import { useFileList } from '../hooks/useFileList';
import { useFileOperations } from '../hooks/useFileOperations'; import { useFileOperations } from '../hooks/useFileOperations';
import { useGitOperations } from '../hooks/useGitOperations'; import { useGitOperations } from '../hooks/useGitOperations';
import { useFileNavigation } from '../hooks/useFileNavigation';
import { useSettings } from '../contexts/SettingsContext'; import { useSettings } from '../contexts/SettingsContext';
const MainContent = () => { const MainContent = ({ selectedFile, handleFileSelect, handleLinkClick }) => {
const [activeTab, setActiveTab] = useState('source'); const [activeTab, setActiveTab] = useState('source');
const { settings } = useSettings(); const { settings } = useSettings();
const { files, loadFileList } = useFileList();
const { handleLinkClick, selectedFile, handleFileSelect } =
useFileNavigation();
const { const {
content, content,
hasUnsavedChanges, hasUnsavedChanges,
@@ -29,15 +22,11 @@ const MainContent = () => {
handleContentChange, handleContentChange,
} = useFileContent(selectedFile); } = useFileContent(selectedFile);
const { handleSave, handleCreate, handleDelete } = useFileOperations(); const { handleSave, handleCreate, handleDelete } = useFileOperations();
const { handleCommitAndPush, handlePull } = useGitOperations(); const { handleCommitAndPush } = useGitOperations(settings.gitEnabled);
useEffect(() => { const handleTabChange = useCallback((value) => {
loadFileList();
}, [settings.gitEnabled]);
const handleTabChange = (value) => {
setActiveTab(value); setActiveTab(value);
}; }, []);
const handleSaveFile = useCallback( const handleSaveFile = useCallback(
async (filePath, content) => { async (filePath, content) => {
@@ -54,25 +43,23 @@ const MainContent = () => {
async (fileName) => { async (fileName) => {
const success = await handleCreate(fileName); const success = await handleCreate(fileName);
if (success) { if (success) {
await loadFileList();
handleFileSelect(fileName); handleFileSelect(fileName);
} }
}, },
[handleCreate, loadFileList, handleFileSelect] [handleCreate, handleFileSelect]
); );
const handleDeleteFile = useCallback( const handleDeleteFile = useCallback(
async (filePath) => { async (filePath) => {
const success = await handleDelete(filePath); const success = await handleDelete(filePath);
if (success) { if (success) {
await loadFileList();
handleFileSelect(null); handleFileSelect(null);
} }
}, },
[handleDelete, loadFileList, handleFileSelect] [handleDelete, handleFileSelect]
); );
const renderBreadcrumbs = () => { const renderBreadcrumbs = useMemo(() => {
if (!selectedFile) return null; if (!selectedFile) return null;
const pathParts = selectedFile.split('/'); const pathParts = selectedFile.split('/');
const items = pathParts.map((part, index) => ( const items = pathParts.map((part, index) => (
@@ -92,56 +79,35 @@ const MainContent = () => {
)} )}
</Group> </Group>
); );
}; }, [selectedFile, hasUnsavedChanges]);
return ( return (
<Box style={{ height: 'calc(100vh - 60px)', display: 'flex' }}> <Box
<Box style={{
style={{ flex: 1,
width: '300px', overflow: 'hidden',
borderRight: '1px solid var(--mantine-color-gray-3)', display: 'flex',
overflow: 'hidden', flexDirection: 'column',
}} }}
> >
<FileActions <Flex justify="space-between" align="center" p="md">
handlePullChanges={handlePull} {renderBreadcrumbs}
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.List>
<Tabs.Tab value="source" leftSection={<IconCode size="0.8rem" />} />
<Tabs.Tab value="preview" leftSection={<IconEye size="0.8rem" />} />
</Tabs.List>
</Tabs>
</Flex>
<Box style={{ flex: 1, overflow: 'auto' }}>
<ContentView
activeTab={activeTab}
selectedFile={selectedFile} selectedFile={selectedFile}
content={content}
handleContentChange={handleContentChange}
handleSave={handleSaveFile}
handleLinkClick={handleLinkClick}
/> />
<FileTree files={files} handleFileSelect={handleFileSelect} />
</Box>
<Box
style={{
flex: 1,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
>
<Flex justify="space-between" align="center" p="md">
{renderBreadcrumbs()}
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.List>
<Tabs.Tab
value="source"
leftSection={<IconCode size="0.8rem" />}
/>
<Tabs.Tab
value="preview"
leftSection={<IconEye size="0.8rem" />}
/>
</Tabs.List>
</Tabs>
</Flex>
<Box style={{ flex: 1, overflow: 'auto' }}>
<ContentView
activeTab={activeTab}
selectedFile={selectedFile}
content={content}
handleContentChange={handleContentChange}
handleSave={handleSaveFile}
handleLinkClick={handleLinkClick}
/>
</Box>
</Box> </Box>
<CreateFileModal onCreateFile={handleCreateFile} /> <CreateFileModal onCreateFile={handleCreateFile} />
<DeleteFileModal <DeleteFileModal

View File

@@ -0,0 +1,39 @@
import React, { useEffect } from 'react';
import { Box } from '@mantine/core';
import FileActions from './FileActions';
import FileTree from './FileTree';
import { useFileList } from '../hooks/useFileList';
import { useGitOperations } from '../hooks/useGitOperations';
import { useSettings } from '../contexts/SettingsContext';
const Sidebar = ({ selectedFile, handleFileSelect }) => {
const { settings } = useSettings();
const { files, loadFileList } = useFileList();
const { handlePull } = useGitOperations(settings.gitEnabled);
useEffect(() => {
loadFileList();
}, [settings.gitEnabled, loadFileList]);
return (
<Box
style={{
width: '25%',
minWidth: '200px',
maxWidth: '300px',
borderRight: '1px solid var(--app-shell-border-color)',
height: '100%',
overflow: 'hidden',
}}
>
<FileActions handlePullChanges={handlePull} selectedFile={selectedFile} />
<FileTree
files={files}
handleFileSelect={handleFileSelect}
selectedFile={selectedFile}
/>
</Box>
);
};
export default Sidebar;

View File

@@ -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 { useMantineColorScheme } from '@mantine/core';
import { fetchUserSettings, saveUserSettings } from '../services/api'; import { fetchUserSettings, saveUserSettings } from '../services/api';
import { DEFAULT_SETTINGS } from '../utils/constants'; import { DEFAULT_SETTINGS } from '../utils/constants';
@@ -9,8 +16,8 @@ export const useSettings = () => useContext(SettingsContext);
export const SettingsProvider = ({ children }) => { export const SettingsProvider = ({ children }) => {
const { colorScheme, setColorScheme } = useMantineColorScheme(); const { colorScheme, setColorScheme } = useMantineColorScheme();
const [settings, setSettings] = React.useState(DEFAULT_SETTINGS); const [settings, setSettings] = useState(DEFAULT_SETTINGS);
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
const loadSettings = async () => { const loadSettings = async () => {
@@ -26,30 +33,32 @@ export const SettingsProvider = ({ children }) => {
}; };
loadSettings(); loadSettings();
}, [setColorScheme]); }, []);
const updateSettings = async (newSettings) => { const updateSettings = useCallback(
try { async (newSettings) => {
await saveUserSettings({ try {
userId: 1, await saveUserSettings({
settings: newSettings, userId: 1,
}); settings: newSettings,
setSettings(newSettings); });
// Ensure the color scheme is updated when settings are saved setSettings(newSettings);
if (newSettings.theme) { if (newSettings.theme) {
setColorScheme(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); [setColorScheme]
throw error; );
}
};
const toggleColorScheme = () => { const toggleColorScheme = useCallback(() => {
const newTheme = colorScheme === 'dark' ? 'light' : 'dark'; const newTheme = colorScheme === 'dark' ? 'light' : 'dark';
setColorScheme(newTheme); setColorScheme(newTheme);
updateSettings({ ...settings, theme: newTheme }); updateSettings({ ...settings, theme: newTheme });
}; }, [colorScheme, settings, setColorScheme, updateSettings]);
const contextValue = useMemo( const contextValue = useMemo(
() => ({ () => ({
@@ -59,7 +68,7 @@ export const SettingsProvider = ({ children }) => {
loading, loading,
colorScheme, colorScheme,
}), }),
[settings, loading, colorScheme] [settings, updateSettings, toggleColorScheme, loading, colorScheme]
); );
return ( return (