diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 75040d1..5e6baad 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -2,8 +2,8 @@ import React from 'react';
import { MantineProvider, ColorSchemeScript } from '@mantine/core';
import { Notifications } from '@mantine/notifications';
import { ModalsProvider } from '@mantine/modals';
-import Layout from './components/Layout';
-import LoginPage from './components/LoginPage';
+import Layout from './components/layout/Layout';
+import LoginPage from './components/auth/LoginPage';
import { WorkspaceProvider } from './contexts/WorkspaceContext';
import { ModalProvider } from './contexts/ModalContext';
import { AuthProvider, useAuth } from './contexts/AuthContext';
diff --git a/frontend/src/components/LoginPage.jsx b/frontend/src/components/auth/LoginPage.jsx
similarity index 96%
rename from frontend/src/components/LoginPage.jsx
rename to frontend/src/components/auth/LoginPage.jsx
index c5c55f1..590ba33 100644
--- a/frontend/src/components/LoginPage.jsx
+++ b/frontend/src/components/auth/LoginPage.jsx
@@ -9,7 +9,7 @@ import {
Text,
Stack,
} from '@mantine/core';
-import { useAuth } from '../contexts/AuthContext';
+import { useAuth } from '../../contexts/AuthContext';
const LoginPage = () => {
const [email, setEmail] = useState('');
diff --git a/frontend/src/components/ContentView.jsx b/frontend/src/components/editor/ContentView.jsx
similarity index 91%
rename from frontend/src/components/ContentView.jsx
rename to frontend/src/components/editor/ContentView.jsx
index 24e686f..11eda30 100644
--- a/frontend/src/components/ContentView.jsx
+++ b/frontend/src/components/editor/ContentView.jsx
@@ -2,8 +2,8 @@ import React from 'react';
import { Text, Center } from '@mantine/core';
import Editor from './Editor';
import MarkdownPreview from './MarkdownPreview';
-import { getFileUrl } from '../services/api';
-import { isImageFile } from '../utils/fileHelpers';
+import { getFileUrl } from '../../services/api';
+import { isImageFile } from '../../utils/fileHelpers';
const ContentView = ({
activeTab,
diff --git a/frontend/src/components/Editor.jsx b/frontend/src/components/editor/Editor.jsx
similarity index 97%
rename from frontend/src/components/Editor.jsx
rename to frontend/src/components/editor/Editor.jsx
index 902bb9b..47ec20d 100644
--- a/frontend/src/components/Editor.jsx
+++ b/frontend/src/components/editor/Editor.jsx
@@ -5,7 +5,7 @@ import { EditorView, keymap } from '@codemirror/view';
import { markdown } from '@codemirror/lang-markdown';
import { defaultKeymap } from '@codemirror/commands';
import { oneDark } from '@codemirror/theme-one-dark';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const Editor = ({ content, handleContentChange, handleSave, selectedFile }) => {
const { colorScheme } = useWorkspace();
diff --git a/frontend/src/components/MarkdownPreview.jsx b/frontend/src/components/editor/MarkdownPreview.jsx
similarity index 96%
rename from frontend/src/components/MarkdownPreview.jsx
rename to frontend/src/components/editor/MarkdownPreview.jsx
index 90a8402..51b80ee 100644
--- a/frontend/src/components/MarkdownPreview.jsx
+++ b/frontend/src/components/editor/MarkdownPreview.jsx
@@ -8,8 +8,8 @@ import rehypeReact from 'rehype-react';
import rehypePrism from 'rehype-prism';
import * as prod from 'react/jsx-runtime';
import { notifications } from '@mantine/notifications';
-import { remarkWikiLinks } from '../utils/remarkWikiLinks';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import { remarkWikiLinks } from '../../utils/remarkWikiLinks';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const MarkdownPreview = ({ content, handleFileSelect }) => {
const [processedContent, setProcessedContent] = useState(null);
diff --git a/frontend/src/components/FileActions.jsx b/frontend/src/components/files/FileActions.jsx
similarity index 94%
rename from frontend/src/components/FileActions.jsx
rename to frontend/src/components/files/FileActions.jsx
index b387022..d8b4f18 100644
--- a/frontend/src/components/FileActions.jsx
+++ b/frontend/src/components/files/FileActions.jsx
@@ -6,8 +6,8 @@ import {
IconGitPullRequest,
IconGitCommit,
} from '@tabler/icons-react';
-import { useModalContext } from '../contexts/ModalContext';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import { useModalContext } from '../../contexts/ModalContext';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const FileActions = ({ handlePullChanges, selectedFile }) => {
const { settings } = useWorkspace();
diff --git a/frontend/src/components/FileTree.jsx b/frontend/src/components/files/FileTree.jsx
similarity index 100%
rename from frontend/src/components/FileTree.jsx
rename to frontend/src/components/files/FileTree.jsx
diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/layout/Header.jsx
similarity index 61%
rename from frontend/src/components/Header.jsx
rename to frontend/src/components/layout/Header.jsx
index be18fd8..7b06bae 100644
--- a/frontend/src/components/Header.jsx
+++ b/frontend/src/components/layout/Header.jsx
@@ -1,8 +1,8 @@
import React from 'react';
import { Group, Text } from '@mantine/core';
-import UserMenu from './UserMenu';
-import WorkspaceSwitcher from './WorkspaceSwitcher';
-import Settings from './Settings';
+import UserMenu from '../navigation/UserMenu';
+import WorkspaceSwitcher from '../navigation/WorkspaceSwitcher';
+import WorkspaceSettings from '../settings/workspace/WorkspaceSettings';
const Header = () => {
return (
@@ -14,7 +14,7 @@ const Header = () => {
-
+
);
};
diff --git a/frontend/src/components/Layout.jsx b/frontend/src/components/layout/Layout.jsx
similarity index 89%
rename from frontend/src/components/Layout.jsx
rename to frontend/src/components/layout/Layout.jsx
index 74b64aa..1b5094f 100644
--- a/frontend/src/components/Layout.jsx
+++ b/frontend/src/components/layout/Layout.jsx
@@ -3,9 +3,9 @@ import { AppShell, Container, Loader, Center } from '@mantine/core';
import Header from './Header';
import Sidebar from './Sidebar';
import MainContent from './MainContent';
-import { useFileNavigation } from '../hooks/useFileNavigation';
-import { useFileList } from '../hooks/useFileList';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import { useFileNavigation } from '../../hooks/useFileNavigation';
+import { useFileList } from '../../hooks/useFileList';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const Layout = () => {
const { currentWorkspace, loading: workspaceLoading } = useWorkspace();
diff --git a/frontend/src/components/MainContent.jsx b/frontend/src/components/layout/MainContent.jsx
similarity index 86%
rename from frontend/src/components/MainContent.jsx
rename to frontend/src/components/layout/MainContent.jsx
index 731b250..fe6d760 100644
--- a/frontend/src/components/MainContent.jsx
+++ b/frontend/src/components/layout/MainContent.jsx
@@ -2,15 +2,15 @@ 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 ContentView from './ContentView';
-import CreateFileModal from './modals/CreateFileModal';
-import DeleteFileModal from './modals/DeleteFileModal';
-import CommitMessageModal from './modals/CommitMessageModal';
+import ContentView from '../editor/ContentView';
+import CreateFileModal from '../modals/file/CreateFileModal';
+import DeleteFileModal from '../modals/file/DeleteFileModal';
+import CommitMessageModal from '../modals/git/CommitMessageModal';
-import { useFileContent } from '../hooks/useFileContent';
-import { useFileOperations } from '../hooks/useFileOperations';
-import { useGitOperations } from '../hooks/useGitOperations';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import { useFileContent } from '../../hooks/useFileContent';
+import { useFileOperations } from '../../hooks/useFileOperations';
+import { useGitOperations } from '../../hooks/useGitOperations';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const MainContent = ({ selectedFile, handleFileSelect, loadFileList }) => {
const [activeTab, setActiveTab] = useState('source');
diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/layout/Sidebar.jsx
similarity index 78%
rename from frontend/src/components/Sidebar.jsx
rename to frontend/src/components/layout/Sidebar.jsx
index 04619c7..c6e96fc 100644
--- a/frontend/src/components/Sidebar.jsx
+++ b/frontend/src/components/layout/Sidebar.jsx
@@ -1,9 +1,9 @@
import React, { useEffect } from 'react';
import { Box } from '@mantine/core';
-import FileActions from './FileActions';
-import FileTree from './FileTree';
-import { useGitOperations } from '../hooks/useGitOperations';
-import { useWorkspace } from '../contexts/WorkspaceContext';
+import FileActions from '../files/FileActions';
+import FileTree from '../files/FileTree';
+import { useGitOperations } from '../../hooks/useGitOperations';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
const Sidebar = ({ selectedFile, handleFileSelect, files, loadFileList }) => {
const { settings } = useWorkspace();
diff --git a/frontend/src/components/modals/account/DeleteAccountModal.jsx b/frontend/src/components/modals/account/DeleteAccountModal.jsx
new file mode 100644
index 0000000..cc77459
--- /dev/null
+++ b/frontend/src/components/modals/account/DeleteAccountModal.jsx
@@ -0,0 +1,55 @@
+import React, { useState } from 'react';
+import {
+ Modal,
+ Stack,
+ Text,
+ PasswordInput,
+ Group,
+ Button,
+} from '@mantine/core';
+
+const DeleteAccountModal = ({ opened, onClose, onConfirm }) => {
+ const [password, setPassword] = useState('');
+
+ return (
+
+
+
+ Warning: This action cannot be undone
+
+
+ Please enter your password to confirm account deletion.
+
+ setPassword(e.currentTarget.value)}
+ required
+ />
+
+
+
+
+
+
+ );
+};
+
+export default DeleteAccountModal;
diff --git a/frontend/src/components/modals/account/EmailPasswordModal.jsx b/frontend/src/components/modals/account/EmailPasswordModal.jsx
new file mode 100644
index 0000000..cb585d2
--- /dev/null
+++ b/frontend/src/components/modals/account/EmailPasswordModal.jsx
@@ -0,0 +1,51 @@
+import React, { useState } from 'react';
+import {
+ Modal,
+ Text,
+ Button,
+ Group,
+ Stack,
+ PasswordInput,
+} from '@mantine/core';
+
+const EmailPasswordModal = ({ opened, onClose, onConfirm, email }) => {
+ const [password, setPassword] = useState('');
+
+ return (
+
+
+
+ Please enter your password to confirm changing your email to: {email}
+
+ setPassword(e.currentTarget.value)}
+ required
+ />
+
+
+
+
+
+
+ );
+};
+
+export default EmailPasswordModal;
diff --git a/frontend/src/components/modals/CreateFileModal.jsx b/frontend/src/components/modals/file/CreateFileModal.jsx
similarity index 94%
rename from frontend/src/components/modals/CreateFileModal.jsx
rename to frontend/src/components/modals/file/CreateFileModal.jsx
index c06952b..b44a843 100644
--- a/frontend/src/components/modals/CreateFileModal.jsx
+++ b/frontend/src/components/modals/file/CreateFileModal.jsx
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Modal, TextInput, Button, Group, Box } from '@mantine/core';
-import { useModalContext } from '../../contexts/ModalContext';
+import { useModalContext } from '../../../contexts/ModalContext';
const CreateFileModal = ({ onCreateFile }) => {
const [fileName, setFileName] = useState('');
diff --git a/frontend/src/components/modals/DeleteFileModal.jsx b/frontend/src/components/modals/file/DeleteFileModal.jsx
similarity index 93%
rename from frontend/src/components/modals/DeleteFileModal.jsx
rename to frontend/src/components/modals/file/DeleteFileModal.jsx
index edd4fbf..056bb21 100644
--- a/frontend/src/components/modals/DeleteFileModal.jsx
+++ b/frontend/src/components/modals/file/DeleteFileModal.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import { Modal, Text, Button, Group } from '@mantine/core';
-import { useModalContext } from '../../contexts/ModalContext';
+import { useModalContext } from '../../../contexts/ModalContext';
const DeleteFileModal = ({ onDeleteFile, selectedFile }) => {
const { deleteFileModalVisible, setDeleteFileModalVisible } =
diff --git a/frontend/src/components/modals/CommitMessageModal.jsx b/frontend/src/components/modals/git/CommitMessageModal.jsx
similarity index 95%
rename from frontend/src/components/modals/CommitMessageModal.jsx
rename to frontend/src/components/modals/git/CommitMessageModal.jsx
index 8976498..d0707b9 100644
--- a/frontend/src/components/modals/CommitMessageModal.jsx
+++ b/frontend/src/components/modals/git/CommitMessageModal.jsx
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Modal, TextInput, Button, Group, Box } from '@mantine/core';
-import { useModalContext } from '../../contexts/ModalContext';
+import { useModalContext } from '../../../contexts/ModalContext';
const CommitMessageModal = ({ onCommitAndPush }) => {
const [message, setMessage] = useState('');
diff --git a/frontend/src/components/modals/CreateWorkspaceModal.jsx b/frontend/src/components/modals/workspace/CreateWorkspaceModal.jsx
similarity index 94%
rename from frontend/src/components/modals/CreateWorkspaceModal.jsx
rename to frontend/src/components/modals/workspace/CreateWorkspaceModal.jsx
index 265eccf..d847af1 100644
--- a/frontend/src/components/modals/CreateWorkspaceModal.jsx
+++ b/frontend/src/components/modals/workspace/CreateWorkspaceModal.jsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { Modal, TextInput, Button, Group, Box } from '@mantine/core';
-import { useModalContext } from '../../contexts/ModalContext';
-import { createWorkspace } from '../../services/api';
+import { useModalContext } from '../../../contexts/ModalContext';
+import { createWorkspace } from '../../../services/api';
import { notifications } from '@mantine/notifications';
const CreateWorkspaceModal = ({ onWorkspaceCreated }) => {
diff --git a/frontend/src/components/modals/DeleteWorkspaceModal.jsx b/frontend/src/components/modals/workspace/DeleteWorkspaceModal.jsx
similarity index 100%
rename from frontend/src/components/modals/DeleteWorkspaceModal.jsx
rename to frontend/src/components/modals/workspace/DeleteWorkspaceModal.jsx
diff --git a/frontend/src/components/UserMenu.jsx b/frontend/src/components/navigation/UserMenu.jsx
similarity index 96%
rename from frontend/src/components/UserMenu.jsx
rename to frontend/src/components/navigation/UserMenu.jsx
index 6d50b44..c5d0e68 100644
--- a/frontend/src/components/UserMenu.jsx
+++ b/frontend/src/components/navigation/UserMenu.jsx
@@ -9,8 +9,8 @@ import {
Divider,
} from '@mantine/core';
import { IconUser, IconLogout, IconSettings } from '@tabler/icons-react';
-import { useAuth } from '../contexts/AuthContext';
-import AccountSettings from './AccountSettings';
+import { useAuth } from '../../contexts/AuthContext';
+import AccountSettings from '../settings/account/AccountSettings';
const UserMenu = () => {
const [accountSettingsOpened, setAccountSettingsOpened] = useState(false);
diff --git a/frontend/src/components/WorkspaceSwitcher.jsx b/frontend/src/components/navigation/WorkspaceSwitcher.jsx
similarity index 96%
rename from frontend/src/components/WorkspaceSwitcher.jsx
rename to frontend/src/components/navigation/WorkspaceSwitcher.jsx
index e29f24d..6ddc0af 100644
--- a/frontend/src/components/WorkspaceSwitcher.jsx
+++ b/frontend/src/components/navigation/WorkspaceSwitcher.jsx
@@ -15,10 +15,10 @@ import {
useMantineTheme,
} from '@mantine/core';
import { IconFolders, IconSettings, IconFolderPlus } from '@tabler/icons-react';
-import { useWorkspace } from '../contexts/WorkspaceContext';
-import { useModalContext } from '../contexts/ModalContext';
-import { listWorkspaces } from '../services/api';
-import CreateWorkspaceModal from './modals/CreateWorkspaceModal';
+import { useWorkspace } from '../../contexts/WorkspaceContext';
+import { useModalContext } from '../../contexts/ModalContext';
+import { listWorkspaces } from '../../services/api';
+import CreateWorkspaceModal from '../modals/workspace/CreateWorkspaceModal';
const WorkspaceSwitcher = () => {
const { currentWorkspace, switchWorkspace } = useWorkspace();
diff --git a/frontend/src/components/AccountSettings.jsx b/frontend/src/components/settings/account/AccountSettings.jsx
similarity index 61%
rename from frontend/src/components/AccountSettings.jsx
rename to frontend/src/components/settings/account/AccountSettings.jsx
index c4ad495..7210f6f 100644
--- a/frontend/src/components/AccountSettings.jsx
+++ b/frontend/src/components/settings/account/AccountSettings.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useReducer, useRef } from 'react';
+import React, { useState, useReducer, useRef, useEffect } from 'react';
import {
Modal,
Badge,
@@ -8,13 +8,15 @@ import {
Stack,
Accordion,
TextInput,
- PasswordInput,
Box,
- Text,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
-import { useAuth } from '../contexts/AuthContext';
-import { useProfileSettings } from '../hooks/useProfileSettings';
+import { useAuth } from '../../../contexts/AuthContext';
+import { useProfileSettings } from '../../../hooks/useProfileSettings';
+import EmailPasswordModal from '../../modals/account/EmailPasswordModal';
+import DeleteAccountModal from '../../modals/account/DeleteAccountModal';
+import SecuritySettings from './SecuritySettings';
+import ProfileSettings from './ProfileSettings';
// Reducer for managing settings state
const initialState = {
@@ -53,178 +55,12 @@ function settingsReducer(state, action) {
}
}
-// Password confirmation modal for email changes
-const EmailPasswordModal = ({ opened, onClose, onConfirm, email }) => {
- const [password, setPassword] = useState('');
-
- return (
-
-
-
- Please enter your password to confirm changing your email to: {email}
-
- setPassword(e.currentTarget.value)}
- required
- />
-
-
-
-
-
-
- );
-};
-
-// Delete account confirmation modal
-const DeleteAccountModal = ({ opened, onClose, onConfirm }) => {
- const [password, setPassword] = useState('');
-
- return (
-
-
-
- Warning: This action cannot be undone
-
-
- Please enter your password to confirm account deletion.
-
- setPassword(e.currentTarget.value)}
- required
- />
-
-
-
-
-
-
- );
-};
-
const AccordionControl = ({ children }) => (
{children}
);
-const ProfileSettings = ({ settings, onInputChange }) => (
-
-
- onInputChange('displayName', e.currentTarget.value)}
- placeholder="Enter display name"
- />
- onInputChange('email', e.currentTarget.value)}
- placeholder="Enter email"
- />
-
-
-);
-
-const SecuritySettings = ({ settings, onInputChange }) => {
- const [confirmPassword, setConfirmPassword] = useState('');
- const [error, setError] = useState('');
-
- const handlePasswordChange = (field, value) => {
- if (field === 'confirmNewPassword') {
- setConfirmPassword(value);
- // Check if passwords match when either password field changes
- if (value !== settings.newPassword) {
- setError('Passwords do not match');
- } else {
- setError('');
- }
- } else {
- onInputChange(field, value);
- // Check if passwords match when either password field changes
- if (field === 'newPassword' && value !== confirmPassword) {
- setError('Passwords do not match');
- } else if (value === confirmPassword) {
- setError('');
- }
- }
- };
-
- return (
-
-
-
- handlePasswordChange('currentPassword', e.currentTarget.value)
- }
- placeholder="Enter current password"
- />
-
- handlePasswordChange('newPassword', e.currentTarget.value)
- }
- placeholder="Enter new password"
- />
-
- handlePasswordChange('confirmNewPassword', e.currentTarget.value)
- }
- placeholder="Confirm new password"
- error={error}
- />
-
- Password must be at least 8 characters long. Leave password fields
- empty if you don't want to change it.
-
-
-
- );
-};
-
const DangerZone = ({ onDeleteClick }) => (