From 0e04e096d915f8a22c7587282371d71456223cfb Mon Sep 17 00:00:00 2001 From: Ricardo Costa Date: Tue, 30 Apr 2024 12:00:17 +0100 Subject: [PATCH] Implemented Document Creation & Deletion --- code/client/src/App.scss | 1 + code/client/src/App.tsx | 8 +-- .../src/domain/communication/communication.ts | 4 +- .../context}/CommunicationContext.tsx | 10 ++-- .../communication/context/useContext.ts | 7 +++ .../communication/http/httpCommunication.ts | 10 +++- .../src/domain/communication/socket/socket.ts | 2 +- .../socket/socketCommunication.ts | 2 +- .../socket/useSocketListeners.ts | 2 +- code/client/src/domain/editor/crdt/fugue.ts | 12 ++--- code/client/src/domain/editor/crdt/types.ts | 4 +- code/client/src/domain/editor/crdt/utils.ts | 2 +- .../src/domain/editor/hooks/useEvents.ts | 8 +-- .../src/domain/editor/hooks/useFugue.ts | 2 +- .../editor/operations/fugue/operations.ts | 8 +-- .../domain/editor/operations/fugue/types.ts | 4 +- .../editor/operations/history/operations.ts | 10 ++-- .../domain/editor/operations/history/types.ts | 2 +- .../editor/operations/input/operations.ts | 14 ++--- .../domain/editor/operations/input/types.ts | 4 +- .../editor/operations/markdown/types.ts | 4 +- .../editor/operations/markdown/utils.ts | 8 +-- .../slate/handlers/history/historyHandlers.ts | 4 +- .../editor/slate/handlers/history/utils.ts | 4 +- .../slate/handlers/input/inputHandlers.ts | 14 ++--- .../handlers/markdown/markdownHandlers.ts | 6 +-- .../domain/editor/slate/hooks/useCursors.ts | 6 +-- .../domain/editor/slate/hooks/useDecorate.ts | 2 +- .../domain/editor/slate/hooks/useEditor.ts | 2 +- .../editor/slate/hooks/useRenderers.tsx | 2 +- .../markdown/operations/applyOperations.ts | 4 +- .../markdown/operations/editorOperations.ts | 12 ++--- .../rendering/components/components.ts | 24 ++++----- .../plugins/markdown/rendering/elements.tsx | 4 +- .../plugins/markdown/rendering/renderers.tsx | 12 ++--- .../editor/slate/plugins/markdown/rules.ts | 4 +- .../slate/plugins/markdown/shortcuts.ts | 4 +- .../slate/plugins/markdown/withMarkdown.ts | 6 +-- code/client/src/domain/editor/slate/types.ts | 4 +- .../domain/editor/slate/utils/selection.ts | 2 +- .../src/domain/editor/slate/utils/slate.ts | 8 +-- code/client/src/index.css | 9 +--- code/client/src/pwa/pwa-config.ts | 4 +- .../src/ui/components/header/Header.scss | 4 +- .../src/ui/components/header/Header.tsx | 7 +-- .../src/ui/pages/editor/DocumentEditor.tsx | 10 ++-- .../pages/editor/components/cursor/Cursor.tsx | 2 +- .../components/slate-editor/SlateEditor.tsx | 30 +++++------ .../editor/components/title/EditorTitle.tsx | 4 +- .../editor/components/toolbar/Toolbar.tsx | 6 +-- code/client/src/ui/pages/home/Home.scss | 40 ++++++++++++++ code/client/src/ui/pages/home/Home.tsx | 52 +++++++++++++++---- code/client/tests/editor/crdt/fugue.test.ts | 4 +- code/client/tests/editor/crdt/tree.test.ts | 6 +-- .../tests/editor/slate/SlateEditor.test.tsx | 6 +-- .../slate/operations/Deletions.test.tsx | 4 +- .../editor/slate/operations/Inserts.test.tsx | 4 +- .../client/tests/editor/slate/toSlate.test.ts | 4 +- code/client/tests/editor/slate/utils.tsx | 6 +-- code/client/tests/mocks/mock-server.ts | 4 +- code/client/tests/mocks/mockCommunication.ts | 2 +- code/client/tsconfig.json | 2 +- code/server/package.json | 3 +- .../http/document/createDocument.ts | 11 ---- .../http/document/deleteDocument.ts | 11 ---- .../controllers/http/document/getDocument.ts | 11 ---- .../src/controllers/http/documentHandlers.ts | 33 ++++++++++++ .../src/controllers/http/errorHandler.ts | 7 +++ code/server/src/controllers/http/router.ts | 18 ++++--- .../controllers/ws/document/onCursorChange.ts | 5 +- code/server/src/database/memory/operations.ts | 6 +++ code/server/src/server.ts | 2 +- code/server/src/services/documentService.ts | 5 ++ code/server/src/types.d.ts | 2 + code/shared/crdt/types/document.ts | 1 + 75 files changed, 341 insertions(+), 236 deletions(-) rename code/client/src/{contexts => domain/communication/context}/CommunicationContext.tsx (56%) create mode 100644 code/client/src/domain/communication/context/useContext.ts create mode 100644 code/client/src/ui/pages/home/Home.scss delete mode 100644 code/server/src/controllers/http/document/createDocument.ts delete mode 100644 code/server/src/controllers/http/document/deleteDocument.ts delete mode 100644 code/server/src/controllers/http/document/getDocument.ts create mode 100644 code/server/src/controllers/http/documentHandlers.ts create mode 100644 code/server/src/controllers/http/errorHandler.ts diff --git a/code/client/src/App.scss b/code/client/src/App.scss index 60f45e34..01824197 100644 --- a/code/client/src/App.scss +++ b/code/client/src/App.scss @@ -14,6 +14,7 @@ .app { width: 100vw; height: 100vh; + color: black; } ::-webkit-scrollbar { diff --git a/code/client/src/App.tsx b/code/client/src/App.tsx index f3f8fc56..85f57e9c 100644 --- a/code/client/src/App.tsx +++ b/code/client/src/App.tsx @@ -1,17 +1,17 @@ import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; import DocumentEditor from '@/ui/pages/editor/DocumentEditor'; import Header from '@/ui/components/header/Header'; -import Home from '@/ui/pages/home/Home.tsx'; +import Home from '@/ui/pages/home/Home'; import './App.scss'; -import { CommunicationProvider } from '@/contexts/CommunicationContext.tsx'; -import { communication } from '@/domain/communication/communication.ts'; +import { CommunicationProvider } from '@/domain/communication/context/CommunicationContext'; +import { communication } from '@/domain/communication/communication'; function App() { return (
-
+
} /> } /> diff --git a/code/client/src/domain/communication/communication.ts b/code/client/src/domain/communication/communication.ts index 5eac5747..a50178ea 100644 --- a/code/client/src/domain/communication/communication.ts +++ b/code/client/src/domain/communication/communication.ts @@ -1,5 +1,5 @@ -import { socketCommunication, SocketCommunication } from '@/domain/communication/socket/socketCommunication.ts'; -import { httpCommunication, HttpCommunication } from '@/domain/communication/http/httpCommunication.ts'; +import { socketCommunication, SocketCommunication } from '@/domain/communication/socket/socketCommunication'; +import { httpCommunication, HttpCommunication } from '@/domain/communication/http/httpCommunication'; export interface Communication { socket: SocketCommunication; diff --git a/code/client/src/contexts/CommunicationContext.tsx b/code/client/src/domain/communication/context/CommunicationContext.tsx similarity index 56% rename from code/client/src/contexts/CommunicationContext.tsx rename to code/client/src/domain/communication/context/CommunicationContext.tsx index 8f2970e2..7e936094 100644 --- a/code/client/src/contexts/CommunicationContext.tsx +++ b/code/client/src/domain/communication/context/CommunicationContext.tsx @@ -1,15 +1,13 @@ import { createContext, ReactElement } from 'react'; -import { communication, Communication } from '@/domain/communication/communication.ts'; +import { communication, Communication } from '@/domain/communication/communication'; -const CommunicationContext = createContext(communication); +export const CommunicationContext = createContext(communication); type CommunicationProviderProps = { communication: Communication; children: ReactElement; }; -const CommunicationProvider = ({ communication, children }: CommunicationProviderProps) => { +export function CommunicationProvider({ communication, children }: CommunicationProviderProps) { return {children}; -}; - -export { CommunicationContext, CommunicationProvider }; +} diff --git a/code/client/src/domain/communication/context/useContext.ts b/code/client/src/domain/communication/context/useContext.ts new file mode 100644 index 00000000..f24b40a2 --- /dev/null +++ b/code/client/src/domain/communication/context/useContext.ts @@ -0,0 +1,7 @@ +import { Communication } from '@/domain/communication/communication'; +import { useContext } from 'react'; +import { CommunicationContext } from '@/domain/communication/context/CommunicationContext'; + +export function useCommunication(): Communication { + return useContext(CommunicationContext); +} diff --git a/code/client/src/domain/communication/http/httpCommunication.ts b/code/client/src/domain/communication/http/httpCommunication.ts index 985dae4d..c1b148ff 100644 --- a/code/client/src/domain/communication/http/httpCommunication.ts +++ b/code/client/src/domain/communication/http/httpCommunication.ts @@ -1,4 +1,4 @@ -import config from '@/config.ts'; +import config from '@/config'; export const BASE_URL = config.HTTP_SERVER_URL; @@ -34,7 +34,13 @@ const request = async (url: string, method: string, body?: any) => { }; if (body) requestInit.body = JSON.stringify(body); const response = await fetch(BASE_URL + url, requestInit); - return await response.json(); + + try { + return await response.json(); + } catch (err) { + // parsing failed, probably empty body + return undefined; + } }; export const httpCommunication: HttpCommunication = { diff --git a/code/client/src/domain/communication/socket/socket.ts b/code/client/src/domain/communication/socket/socket.ts index fbc10798..f7acaed4 100644 --- a/code/client/src/domain/communication/socket/socket.ts +++ b/code/client/src/domain/communication/socket/socket.ts @@ -1,5 +1,5 @@ import { io, Socket } from 'socket.io-client'; -import config from '@/config.ts'; +import config from '@/config'; import { range } from 'lodash'; declare module 'socket.io-client' { diff --git a/code/client/src/domain/communication/socket/socketCommunication.ts b/code/client/src/domain/communication/socket/socketCommunication.ts index 834fbfb6..680d7e9a 100644 --- a/code/client/src/domain/communication/socket/socketCommunication.ts +++ b/code/client/src/domain/communication/socket/socketCommunication.ts @@ -1,4 +1,4 @@ -import { socket } from '@/domain/communication/socket/socket.ts'; +import { socket } from '@/domain/communication/socket/socket'; import { SocketEventHandlers } from 'socket.io-client'; type EmitType = (event: string, data?: any) => void; diff --git a/code/client/src/domain/communication/socket/useSocketListeners.ts b/code/client/src/domain/communication/socket/useSocketListeners.ts index 547d578d..acb41e99 100644 --- a/code/client/src/domain/communication/socket/useSocketListeners.ts +++ b/code/client/src/domain/communication/socket/useSocketListeners.ts @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -import { SocketCommunication } from '@/domain/communication/socket/socketCommunication.ts'; +import { SocketCommunication } from '@/domain/communication/socket/socketCommunication'; import { SocketEventHandlers } from 'socket.io-client'; function useSocketListeners(socket: SocketCommunication, eventHandlers: SocketEventHandlers) { diff --git a/code/client/src/domain/editor/crdt/fugue.ts b/code/client/src/domain/editor/crdt/fugue.ts index e84b9014..8d17eb6e 100644 --- a/code/client/src/domain/editor/crdt/fugue.ts +++ b/code/client/src/domain/editor/crdt/fugue.ts @@ -1,9 +1,9 @@ import { type Id, Nodes } from '@notespace/shared/crdt/types/nodes'; -import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; -import { FugueTree } from '@notespace/shared/crdt/FugueTree.ts'; -import { generateReplicaId, nodeInsert } from './utils.ts'; -import { type FugueNode, type NodeInsert } from '@/ui/pages/editor/crdt/types.ts'; -import { Cursor, Selection } from '@notespace/shared/types/cursor.ts'; +import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; +import { FugueTree } from '@notespace/shared/crdt/FugueTree'; +import { generateReplicaId, nodeInsert } from './utils'; +import { type FugueNode, type NodeInsert } from '@/domain/editor/crdt/types'; +import { Cursor, Selection } from '@notespace/shared/types/cursor'; import { isEmpty, last, range } from 'lodash'; import { BlockStyleOperation, @@ -11,7 +11,7 @@ import { InlineStyleOperation, InsertOperation, ReviveOperation, -} from '@notespace/shared/crdt/types/operations.ts'; +} from '@notespace/shared/crdt/types/operations'; /** * Class that represents a local replica of a FugueTree diff --git a/code/client/src/domain/editor/crdt/types.ts b/code/client/src/domain/editor/crdt/types.ts index a89d2e4b..15a89720 100644 --- a/code/client/src/domain/editor/crdt/types.ts +++ b/code/client/src/domain/editor/crdt/types.ts @@ -1,5 +1,5 @@ -import { type InlineStyle } from '@notespace/shared/types/styles.ts'; -import { Node } from '@notespace/shared/crdt/types/nodes.ts'; +import { type InlineStyle } from '@notespace/shared/types/styles'; +import { Node } from '@notespace/shared/crdt/types/nodes'; export type NodeInsert = { value: string; diff --git a/code/client/src/domain/editor/crdt/utils.ts b/code/client/src/domain/editor/crdt/utils.ts index ae7566fb..ffe519dc 100644 --- a/code/client/src/domain/editor/crdt/utils.ts +++ b/code/client/src/domain/editor/crdt/utils.ts @@ -1,5 +1,5 @@ import { range } from 'lodash'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; +import { InlineStyle } from '@notespace/shared/types/styles'; const BASE64CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const DEFAULT_REPLICA_ID_LENGTH = 10; diff --git a/code/client/src/domain/editor/hooks/useEvents.ts b/code/client/src/domain/editor/hooks/useEvents.ts index 3e88a12c..28d9a84a 100644 --- a/code/client/src/domain/editor/hooks/useEvents.ts +++ b/code/client/src/domain/editor/hooks/useEvents.ts @@ -1,7 +1,7 @@ -import useSocketListeners from '@/domain/communication/socket/useSocketListeners.ts'; -import { type Operation } from '@notespace/shared/crdt/types/operations.ts'; -import { Communication } from '@/domain/communication/communication.ts'; -import { FugueDomainOperations } from '@/domain/editor/operations/fugue/types.ts'; +import useSocketListeners from '@/domain/communication/socket/useSocketListeners'; +import { type Operation } from '@notespace/shared/crdt/types/operations'; +import { Communication } from '@/domain/communication/communication'; +import { FugueDomainOperations } from '@/domain/editor/operations/fugue/types'; /** * Hook client socket listeners to events diff --git a/code/client/src/domain/editor/hooks/useFugue.ts b/code/client/src/domain/editor/hooks/useFugue.ts index 83f609e0..9cc55b53 100644 --- a/code/client/src/domain/editor/hooks/useFugue.ts +++ b/code/client/src/domain/editor/hooks/useFugue.ts @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; function useFugue() { return useMemo(() => new Fugue(), []); diff --git a/code/client/src/domain/editor/operations/fugue/operations.ts b/code/client/src/domain/editor/operations/fugue/operations.ts index 0a1de24f..3531bedf 100644 --- a/code/client/src/domain/editor/operations/fugue/operations.ts +++ b/code/client/src/domain/editor/operations/fugue/operations.ts @@ -1,7 +1,7 @@ -import { Operation } from '@notespace/shared/crdt/types/operations.ts'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import { Document } from '@notespace/shared/crdt/types/document.ts'; -import { FugueDomainOperations } from '@/domain/editor/operations/fugue/types.ts'; +import { Operation } from '@notespace/shared/crdt/types/operations'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import { Document } from '@notespace/shared/crdt/types/document'; +import { FugueDomainOperations } from '@/domain/editor/operations/fugue/types'; export default (fugue: Fugue): FugueDomainOperations => { function applyOperations(operations: Operation[]) { diff --git a/code/client/src/domain/editor/operations/fugue/types.ts b/code/client/src/domain/editor/operations/fugue/types.ts index 9c4f3b2a..2ec72aff 100644 --- a/code/client/src/domain/editor/operations/fugue/types.ts +++ b/code/client/src/domain/editor/operations/fugue/types.ts @@ -1,5 +1,5 @@ -import { Operation } from '@notespace/shared/crdt/types/operations.ts'; -import { Document } from '@notespace/shared/crdt/types/document.ts'; +import { Operation } from '@notespace/shared/crdt/types/operations'; +import { Document } from '@notespace/shared/crdt/types/document'; export type FugueDomainOperations = { applyOperations: (operations: Operation[]) => void; diff --git a/code/client/src/domain/editor/operations/history/operations.ts b/code/client/src/domain/editor/operations/history/operations.ts index e6d98569..042b28e8 100644 --- a/code/client/src/domain/editor/operations/history/operations.ts +++ b/code/client/src/domain/editor/operations/history/operations.ts @@ -1,4 +1,4 @@ -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; import { ApplyHistory, HistoryDomainOperations, @@ -11,10 +11,10 @@ import { SetNodeOperation, SplitNodeOperation, UnsetNodeOperation, -} from '@/domain/editor/domain/document/history/types.ts'; -import { Communication } from '@/domain/communication/communication.ts'; -import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; -import { getStyleType } from '@notespace/shared/types/styles.ts'; +} from '@/domain/editor/domain/document/history/types'; +import { Communication } from '@/domain/communication/communication'; +import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; +import { getStyleType } from '@notespace/shared/types/styles'; export default (fugue: Fugue, { socket }: Communication): HistoryDomainOperations => { const applyHistoryOperation: ApplyHistory = (operations: HistoryOperation[]) => { diff --git a/code/client/src/domain/editor/operations/history/types.ts b/code/client/src/domain/editor/operations/history/types.ts index de88cd03..fdce509e 100644 --- a/code/client/src/domain/editor/operations/history/types.ts +++ b/code/client/src/domain/editor/operations/history/types.ts @@ -1,4 +1,4 @@ -import { Cursor, Selection } from '@notespace/shared/types/cursor.ts'; +import { Cursor, Selection } from '@notespace/shared/types/cursor'; import { BaseInsertTextOperation, BaseRemoveTextOperation, diff --git a/code/client/src/domain/editor/operations/input/operations.ts b/code/client/src/domain/editor/operations/input/operations.ts index 8df88868..29fc130b 100644 --- a/code/client/src/domain/editor/operations/input/operations.ts +++ b/code/client/src/domain/editor/operations/input/operations.ts @@ -1,11 +1,11 @@ import { BaseSelection } from 'slate'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import { InputDomainOperations } from '@/domain/editor/domain/document/input/types.ts'; -import { Cursor, Selection } from '@notespace/shared/types/cursor.ts'; -import { nodeInsert } from '@/domain/editor/crdt/utils.ts'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; -import { Operation } from '@notespace/shared/crdt/types/operations.ts'; -import { Communication } from '@/domain/communication/communication.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import { InputDomainOperations } from '@/domain/editor/operations/input/types'; +import { Cursor, Selection } from '@notespace/shared/types/cursor'; +import { nodeInsert } from '@/domain/editor/crdt/utils'; +import { InlineStyle } from '@notespace/shared/types/styles'; +import { Operation } from '@notespace/shared/crdt/types/operations'; +import { Communication } from '@/domain/communication/communication'; export default (fugue: Fugue, { socket }: Communication): InputDomainOperations => { function insertCharacter(char: string, cursor: Cursor, styles: InlineStyle[] = []) { diff --git a/code/client/src/domain/editor/operations/input/types.ts b/code/client/src/domain/editor/operations/input/types.ts index 903dae61..dfbe2f2a 100644 --- a/code/client/src/domain/editor/operations/input/types.ts +++ b/code/client/src/domain/editor/operations/input/types.ts @@ -1,5 +1,5 @@ -import { InlineStyle } from '@notespace/shared/types/styles.ts'; -import { Cursor, Selection } from '@notespace/shared/types/cursor.ts'; +import { InlineStyle } from '@notespace/shared/types/styles'; +import { Cursor, Selection } from '@notespace/shared/types/cursor'; import { BaseSelection } from 'slate'; export type InputDomainOperations = { diff --git a/code/client/src/domain/editor/operations/markdown/types.ts b/code/client/src/domain/editor/operations/markdown/types.ts index aec4cf6f..d7eb3ae3 100644 --- a/code/client/src/domain/editor/operations/markdown/types.ts +++ b/code/client/src/domain/editor/operations/markdown/types.ts @@ -1,5 +1,5 @@ -import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; -import { Selection } from '@notespace/shared/types/cursor.ts'; +import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; +import { Selection } from '@notespace/shared/types/cursor'; export type MarkdownDomainOperations = { applyBlockStyle: ApplyBlockStyle; diff --git a/code/client/src/domain/editor/operations/markdown/utils.ts b/code/client/src/domain/editor/operations/markdown/utils.ts index ae7d07a4..cac6f066 100644 --- a/code/client/src/domain/editor/operations/markdown/utils.ts +++ b/code/client/src/domain/editor/operations/markdown/utils.ts @@ -1,7 +1,7 @@ -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import { DeleteOperation } from '@notespace/shared/crdt/types/operations.ts'; -import { Id } from '@notespace/shared/crdt/types/nodes.ts'; -import { Selection } from '@notespace/shared/types/cursor.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import { DeleteOperation } from '@notespace/shared/crdt/types/operations'; +import { Id } from '@notespace/shared/crdt/types/nodes'; +import { Selection } from '@notespace/shared/types/cursor'; /** * Deletes characters around the selection diff --git a/code/client/src/domain/editor/slate/handlers/history/historyHandlers.ts b/code/client/src/domain/editor/slate/handlers/history/historyHandlers.ts index b5b1a98c..0757dbb2 100644 --- a/code/client/src/domain/editor/slate/handlers/history/historyHandlers.ts +++ b/code/client/src/domain/editor/slate/handlers/history/historyHandlers.ts @@ -1,7 +1,7 @@ import { Editor } from 'slate'; import { last } from 'lodash'; -import { HistoryDomainOperations } from '@/domain/editor/domain/document/history/types.ts'; -import { toHistoryOperations } from '@/domain/editor/slate/handlers/history/utils.ts'; +import { HistoryDomainOperations } from '@/domain/editor/domain/document/history/types'; +import { toHistoryOperations } from '@/domain/editor/slate/handlers/history/utils'; export type HistoryHandlers = { undoOperation: () => void; diff --git a/code/client/src/domain/editor/slate/handlers/history/utils.ts b/code/client/src/domain/editor/slate/handlers/history/utils.ts index 0aea708c..175da315 100644 --- a/code/client/src/domain/editor/slate/handlers/history/utils.ts +++ b/code/client/src/domain/editor/slate/handlers/history/utils.ts @@ -21,8 +21,8 @@ import { SetNodeOperation, SplitNodeOperation, UnsetNodeOperation, -} from '@/domain/editor/domain/document/history/types.ts'; -import { pointToCursor } from '@/domain/editor/slate/utils/selection.ts'; +} from '@/domain/editor/domain/document/history/types'; +import { pointToCursor } from '@/domain/editor/slate/utils/selection'; const reverseTypes: { [key: string]: HistoryOperation['type'] } = { insert_text: 'remove_text', diff --git a/code/client/src/domain/editor/slate/handlers/input/inputHandlers.ts b/code/client/src/domain/editor/slate/handlers/input/inputHandlers.ts index 931c39e8..35b8d98d 100644 --- a/code/client/src/domain/editor/slate/handlers/input/inputHandlers.ts +++ b/code/client/src/domain/editor/slate/handlers/input/inputHandlers.ts @@ -1,12 +1,12 @@ -import { getKeyFromInputEvent } from '@/domain/editor/slate/utils/domEvents.ts'; -import { getSelection, isSelected } from '@/domain/editor/slate/utils/selection.ts'; -import { isEqual } from 'lodash'; -import { Cursor, emptyCursor } from '@notespace/shared/types/cursor.ts'; -import CustomEditor from '@/domain/editor/slate/CustomEditor.ts'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; import { Editor } from 'slate'; -import { InputDomainOperations } from '@/domain/editor/domain/document/input/types.ts'; import { ReactEditor } from 'slate-react'; +import CustomEditor from '@/domain/editor/slate/CustomEditor'; +import { isEqual } from 'lodash'; +import { getKeyFromInputEvent } from '@/domain/editor/slate/utils/domEvents'; +import { getSelection, isSelected } from '@/domain/editor/slate/utils/selection'; +import { Cursor, emptyCursor } from '@notespace/shared/types/cursor'; +import { InlineStyle } from '@notespace/shared/types/styles'; +import { InputDomainOperations } from '@/domain/editor/operations/input/types'; const hotkeys: Record = { b: 'bold', diff --git a/code/client/src/domain/editor/slate/handlers/markdown/markdownHandlers.ts b/code/client/src/domain/editor/slate/handlers/markdown/markdownHandlers.ts index f2b83b49..6c58c7c7 100644 --- a/code/client/src/domain/editor/slate/handlers/markdown/markdownHandlers.ts +++ b/code/client/src/domain/editor/slate/handlers/markdown/markdownHandlers.ts @@ -1,8 +1,8 @@ -import { getSelection, isSelected } from '@/domain/editor/slate/utils/selection.ts'; +import { getSelection, isSelected } from '@/domain/editor/slate/utils/selection'; import { Editor } from 'slate'; -import CustomEditor from '@/domain/editor/slate/CustomEditor.ts'; +import CustomEditor from '@/domain/editor/slate/CustomEditor'; import { MarkdownDomainOperations } from '@/domain/editor/operations/markdown/types'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; +import { InlineStyle } from '@notespace/shared/types/styles'; export default (editor: Editor, handlers: MarkdownDomainOperations) => { /** diff --git a/code/client/src/domain/editor/slate/hooks/useCursors.ts b/code/client/src/domain/editor/slate/hooks/useCursors.ts index 0e965542..81fd59b4 100644 --- a/code/client/src/domain/editor/slate/hooks/useCursors.ts +++ b/code/client/src/domain/editor/slate/hooks/useCursors.ts @@ -1,8 +1,8 @@ import { Range } from 'slate'; import { useState } from 'react'; -import useSocketListeners from '@/domain/communication/socket/useSocketListeners.ts'; -import { Communication } from '@/domain/communication/communication.ts'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; +import useSocketListeners from '@/domain/communication/socket/useSocketListeners'; +import { Communication } from '@/domain/communication/communication'; +import { InlineStyle } from '@notespace/shared/types/styles'; export type CursorData = { id: string; diff --git a/code/client/src/domain/editor/slate/hooks/useDecorate.ts b/code/client/src/domain/editor/slate/hooks/useDecorate.ts index a5c2450f..0bab41e8 100644 --- a/code/client/src/domain/editor/slate/hooks/useDecorate.ts +++ b/code/client/src/domain/editor/slate/hooks/useDecorate.ts @@ -1,4 +1,4 @@ -import { CursorData } from '@/domain/editor/slate/hooks/useCursors.ts'; +import { CursorData } from '@/domain/editor/slate/hooks/useCursors'; import { BaseRange, Editor, NodeEntry, Path, Range, Text } from 'slate'; function useDecorate(editor: Editor, cursors: CursorData[]) { diff --git a/code/client/src/domain/editor/slate/hooks/useEditor.ts b/code/client/src/domain/editor/slate/hooks/useEditor.ts index 3b6c21c6..96757b8b 100644 --- a/code/client/src/domain/editor/slate/hooks/useEditor.ts +++ b/code/client/src/domain/editor/slate/hooks/useEditor.ts @@ -1,6 +1,6 @@ import { type Editor } from 'slate'; import { useMemo } from 'react'; -import { buildEditor } from '@/domain/editor/slate/utils/slate.ts'; +import { buildEditor } from '@/domain/editor/slate/utils/slate'; function useEditor(...plugins: Array<(editor: Editor) => Editor>): Editor { return useMemo(() => buildEditor(...plugins), []); // eslint-disable-line react-hooks/exhaustive-deps diff --git a/code/client/src/domain/editor/slate/hooks/useRenderers.tsx b/code/client/src/domain/editor/slate/hooks/useRenderers.tsx index 9359def8..eb68034a 100644 --- a/code/client/src/domain/editor/slate/hooks/useRenderers.tsx +++ b/code/client/src/domain/editor/slate/hooks/useRenderers.tsx @@ -1,6 +1,6 @@ import { useCallback } from 'react'; import { type RenderElementProps, type RenderLeafProps } from 'slate-react'; -import { getElementRenderer, getLeafRenderer } from '@/domain/editor/slate/plugins/markdown/rendering/renderers.tsx'; +import { getElementRenderer, getLeafRenderer } from '@/domain/editor/slate/plugins/markdown/rendering/renderers'; /** * Returns the renderers for the editor. diff --git a/code/client/src/domain/editor/slate/plugins/markdown/operations/applyOperations.ts b/code/client/src/domain/editor/slate/plugins/markdown/operations/applyOperations.ts index 0fabd8ee..e359519c 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/operations/applyOperations.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/operations/applyOperations.ts @@ -1,6 +1,6 @@ import { type Editor, Element, Range, Text, Transforms } from 'slate'; -import { getSelectionByRange } from '@/domain/editor/slate/utils/selection.ts'; -import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; +import { getSelectionByRange } from '@/domain/editor/slate/utils/selection'; +import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; import { ApplyBlockStyle, ApplyInlineStyle } from '@/domain/editor/operations/markdown/types'; /** diff --git a/code/client/src/domain/editor/slate/plugins/markdown/operations/editorOperations.ts b/code/client/src/domain/editor/slate/plugins/markdown/operations/editorOperations.ts index 1407426d..b11589cf 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/operations/editorOperations.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/operations/editorOperations.ts @@ -1,12 +1,12 @@ import { Descendant, Editor, Element, Point, Range, Text, type TextUnit, Transforms } from 'slate'; -import { type CustomElement } from '@/domain/editor/slate/types.ts'; -import { shortcuts } from '../shortcuts.ts'; -import CustomEditor from '@/domain/editor/slate/CustomEditor.ts'; -import { isMultiBlock } from '@/domain/editor/slate/utils/slate.ts'; -import { getSelection } from '@/domain/editor/slate/utils/selection.ts'; +import { type CustomElement } from '@/domain/editor/slate/types'; +import { shortcuts } from '../shortcuts'; +import CustomEditor from '@/domain/editor/slate/CustomEditor'; +import { isMultiBlock } from '@/domain/editor/slate/utils/slate'; +import { getSelection } from '@/domain/editor/slate/utils/selection'; import { TextDeleteOptions } from 'slate/dist/interfaces/transforms/text'; import { MarkdownDomainOperations } from '@/domain/editor/operations/markdown/types'; -import { RuleType } from '@/domain/editor/slate/plugins/markdown/rules.ts'; +import { RuleType } from '@/domain/editor/slate/plugins/markdown/rules'; type InlineFunction = (n: unknown) => boolean; type DeleteBackwardFunction = (unit: TextUnit, options?: { at: Range }) => void; diff --git a/code/client/src/domain/editor/slate/plugins/markdown/rendering/components/components.ts b/code/client/src/domain/editor/slate/plugins/markdown/rendering/components/components.ts index dd6378c0..00216fe0 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/rendering/components/components.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/rendering/components/components.ts @@ -1,15 +1,15 @@ -import Heading1 from './elements/Heading1.tsx'; -import Heading2 from './elements/Heading2.tsx'; -import Heading3 from './elements/Heading3.tsx'; -import Heading4 from './elements/Heading4.tsx'; -import Heading5 from './elements/Heading5.tsx'; -import Heading6 from './elements/Heading6.tsx'; -import Blockquote from './elements/Blockquote.tsx'; -import ListItem from './elements/ListItem.tsx'; -import NumberedListItem from './elements/NumberedListItem.tsx'; -import LineBreak from './elements/LineBreak.tsx'; -import Code from './elements/Code.tsx'; -import Paragraph from './elements/Paragraph.tsx'; +import Heading1 from './elements/Heading1'; +import Heading2 from './elements/Heading2'; +import Heading3 from './elements/Heading3'; +import Heading4 from './elements/Heading4'; +import Heading5 from './elements/Heading5'; +import Heading6 from './elements/Heading6'; +import Blockquote from './elements/Blockquote'; +import ListItem from './elements/ListItem'; +import NumberedListItem from './elements/NumberedListItem'; +import LineBreak from './elements/LineBreak'; +import Code from './elements/Code'; +import Paragraph from './elements/Paragraph'; export { Heading1, diff --git a/code/client/src/domain/editor/slate/plugins/markdown/rendering/elements.tsx b/code/client/src/domain/editor/slate/plugins/markdown/rendering/elements.tsx index 0c5d6ee2..4c57e4a7 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/rendering/elements.tsx +++ b/code/client/src/domain/editor/slate/plugins/markdown/rendering/elements.tsx @@ -1,5 +1,5 @@ import { type ReactNode } from 'react'; -import { BlockStyles } from '@notespace/shared/types/styles.ts'; +import { BlockStyles } from '@notespace/shared/types/styles'; import { RenderElementProps } from 'slate-react'; import { Blockquote, @@ -13,7 +13,7 @@ import { LineBreak, ListItem, NumberedListItem, -} from './components/components.ts'; +} from './components/components'; export const ElementRenderers = { [BlockStyles.h1]: (props: RenderElementProps) => , diff --git a/code/client/src/domain/editor/slate/plugins/markdown/rendering/renderers.tsx b/code/client/src/domain/editor/slate/plugins/markdown/rendering/renderers.tsx index edc9f49c..420b7c4a 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/rendering/renderers.tsx +++ b/code/client/src/domain/editor/slate/plugins/markdown/rendering/renderers.tsx @@ -1,10 +1,10 @@ import { type RenderElementProps } from 'slate-react'; -import { ElementRenderers, LeafRenderers } from './elements.tsx'; -import { Paragraph } from './components/components.ts'; -import { type CustomText } from '@/domain/editor/slate/types.ts'; +import { ElementRenderers, LeafRenderers } from './elements'; +import { Paragraph } from './components/components'; +import { type CustomText } from '@/domain/editor/slate/types'; import { type ReactNode } from 'react'; -import Selection from '@/ui/pages/editor/components/cursor/Selection.tsx'; -import Cursor from '@/ui/pages/editor/components/cursor/Cursor.tsx'; +import Selection from '@/ui/pages/editor/components/cursor/Selection'; +import Cursor from '@/ui/pages/editor/components/cursor/Cursor'; import { Range } from 'slate'; /** @@ -38,7 +38,7 @@ export const getLeafRenderer = (leaf: CustomText, children: ReactNode) => { const { color, id, range, styles } = leaf.cursor; children = Range.isCollapsed(range!) ? ( - + ) : ( ); diff --git a/code/client/src/domain/editor/slate/plugins/markdown/rules.ts b/code/client/src/domain/editor/slate/plugins/markdown/rules.ts index b418668f..a8558362 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/rules.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/rules.ts @@ -1,8 +1,8 @@ import { createSetBlockApply, createSetInlineApply, -} from '@/domain/editor/slate/plugins/markdown/operations/applyOperations.ts'; -import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; +} from '@/domain/editor/slate/plugins/markdown/operations/applyOperations'; +import { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; import { ApplyBlockStyle, ApplyInlineStyle } from '@/domain/editor/operations/markdown/types'; import { Editor, Range } from 'slate'; diff --git a/code/client/src/domain/editor/slate/plugins/markdown/shortcuts.ts b/code/client/src/domain/editor/slate/plugins/markdown/shortcuts.ts index b46f0b84..84ec6860 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/shortcuts.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/shortcuts.ts @@ -1,5 +1,5 @@ -import { BlockStyles, InlineStyles } from '@notespace/shared/types/styles.ts'; -import { blockRules, inlineRules } from '@/domain/editor/slate/plugins/markdown/rules.ts'; +import { BlockStyles, InlineStyles } from '@notespace/shared/types/styles'; +import { blockRules, inlineRules } from '@/domain/editor/slate/plugins/markdown/rules'; export const shortcuts = [ blockRules(BlockStyles.h1, '#'), diff --git a/code/client/src/domain/editor/slate/plugins/markdown/withMarkdown.ts b/code/client/src/domain/editor/slate/plugins/markdown/withMarkdown.ts index 09adf8f8..702414f4 100644 --- a/code/client/src/domain/editor/slate/plugins/markdown/withMarkdown.ts +++ b/code/client/src/domain/editor/slate/plugins/markdown/withMarkdown.ts @@ -1,9 +1,9 @@ import { type Editor } from 'slate'; -import operations from './operations/editorOperations.ts'; +import operations from './operations/editorOperations'; import markdownHandlers from '@/domain/editor/operations/markdown/operations'; import { MarkdownDomainOperations } from '@/domain/editor/operations/markdown/types'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import { Communication } from '@/domain/communication/communication.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import { Communication } from '@/domain/communication/communication'; /** * Adds markdown support to the editor. diff --git a/code/client/src/domain/editor/slate/types.ts b/code/client/src/domain/editor/slate/types.ts index 42569855..f2373ad6 100644 --- a/code/client/src/domain/editor/slate/types.ts +++ b/code/client/src/domain/editor/slate/types.ts @@ -1,8 +1,8 @@ import { type BaseEditor, type Descendant } from 'slate'; import { type ReactEditor } from 'slate-react'; import { type HistoryEditor } from 'slate-history'; -import { type BlockStyle } from '@notespace/shared/types/styles.ts'; -import { CursorData } from '@/domain/editor/slate/hooks/useCursors.ts'; +import { type BlockStyle } from '@notespace/shared/types/styles'; +import { CursorData } from '@/domain/editor/slate/hooks/useCursors'; export interface CustomFormat { bold?: boolean; diff --git a/code/client/src/domain/editor/slate/utils/selection.ts b/code/client/src/domain/editor/slate/utils/selection.ts index d683c3d3..b43bc899 100644 --- a/code/client/src/domain/editor/slate/utils/selection.ts +++ b/code/client/src/domain/editor/slate/utils/selection.ts @@ -1,5 +1,5 @@ import { Editor, Node, Path, Point, Range } from 'slate'; -import { Cursor, emptyCursor, emptySelection, Selection } from '@notespace/shared/types/cursor.ts'; +import { Cursor, emptyCursor, emptySelection, Selection } from '@notespace/shared/types/cursor'; import { first, isEqual } from 'lodash'; /** diff --git a/code/client/src/domain/editor/slate/utils/slate.ts b/code/client/src/domain/editor/slate/utils/slate.ts index 12822952..989b6548 100644 --- a/code/client/src/domain/editor/slate/utils/slate.ts +++ b/code/client/src/domain/editor/slate/utils/slate.ts @@ -1,9 +1,9 @@ import { createEditor, Descendant, Editor } from 'slate'; -import type { BlockStyle, InlineStyle } from '@notespace/shared/types/styles.ts'; -import type { CustomText } from '@/domain/editor/slate/types.ts'; +import type { BlockStyle, InlineStyle } from '@notespace/shared/types/styles'; +import type { CustomText } from '@/domain/editor/slate/types'; import { isEqual, last } from 'lodash'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import { BlockStyles } from '@notespace/shared/types/styles.ts'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import { BlockStyles } from '@notespace/shared/types/styles'; /** * Converts a FugueTree to a Slate document diff --git a/code/client/src/index.css b/code/client/src/index.css index 0d25e30a..a2acc515 100644 --- a/code/client/src/index.css +++ b/code/client/src/index.css @@ -40,16 +40,11 @@ h1 { button { border-radius: 8px; - font-family: inherit; - background-color: white; - color: lightgray; cursor: pointer; - transition: border-color 0.25s; + padding: 2vh; + border: none; } -button:hover { - border-color: gray; -} button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; diff --git a/code/client/src/pwa/pwa-config.ts b/code/client/src/pwa/pwa-config.ts index 2450c7ce..b73af2ef 100644 --- a/code/client/src/pwa/pwa-config.ts +++ b/code/client/src/pwa/pwa-config.ts @@ -1,5 +1,5 @@ -// import { injectConfig } from './inject-config.ts'; -// import { manifestConfig } from './manifest-config.ts'; +// import { injectConfig } from './inject-config'; +// import { manifestConfig } from './manifest-config'; // import { VitePWAOptions } from 'vite-plugin-pwa'; // // export const pwaConfig: Partial = { diff --git a/code/client/src/ui/components/header/Header.scss b/code/client/src/ui/components/header/Header.scss index dc4d000f..1e7b62cf 100644 --- a/code/client/src/ui/components/header/Header.scss +++ b/code/client/src/ui/components/header/Header.scss @@ -7,8 +7,8 @@ header { display: flex; align-items: center; - h1 { - font-size: 2vh; + .title { + font-size: 3vh; padding: 1vh; margin: 0 0 0 1vh; font-weight: 500; diff --git a/code/client/src/ui/components/header/Header.tsx b/code/client/src/ui/components/header/Header.tsx index 8666eac2..7071a2be 100644 --- a/code/client/src/ui/components/header/Header.tsx +++ b/code/client/src/ui/components/header/Header.tsx @@ -1,11 +1,12 @@ +import { Link } from 'react-router-dom'; import './Header.scss'; -import { FaBars } from 'react-icons/fa'; function Header() { return (
- -

NoteSpace

+ + NoteSpace +
); } diff --git a/code/client/src/ui/pages/editor/DocumentEditor.tsx b/code/client/src/ui/pages/editor/DocumentEditor.tsx index 8d071416..d35c6080 100644 --- a/code/client/src/ui/pages/editor/DocumentEditor.tsx +++ b/code/client/src/ui/pages/editor/DocumentEditor.tsx @@ -1,12 +1,12 @@ -import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor.tsx'; +import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor'; import './DocumentEditor.scss'; -import useFugue from '@/domain/editor/hooks/useFugue.ts'; -import { useContext, useEffect, useState } from 'react'; +import useFugue from '@/domain/editor/hooks/useFugue'; +import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { CommunicationContext } from '@/contexts/CommunicationContext.tsx'; +import { useCommunication } from '@/domain/communication/context/useContext'; function DocumentEditor() { - const communication = useContext(CommunicationContext); + const communication = useCommunication(); const { http, socket } = communication; const fugue = useFugue(); diff --git a/code/client/src/ui/pages/editor/components/cursor/Cursor.tsx b/code/client/src/ui/pages/editor/components/cursor/Cursor.tsx index a51a7f43..b50be253 100644 --- a/code/client/src/ui/pages/editor/components/cursor/Cursor.tsx +++ b/code/client/src/ui/pages/editor/components/cursor/Cursor.tsx @@ -1,5 +1,5 @@ import { ReactNode } from 'react'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; +import { InlineStyle } from '@notespace/shared/types/styles'; type CursorProps = { children: ReactNode; diff --git a/code/client/src/ui/pages/editor/components/slate-editor/SlateEditor.tsx b/code/client/src/ui/pages/editor/components/slate-editor/SlateEditor.tsx index d513494c..037178e5 100644 --- a/code/client/src/ui/pages/editor/components/slate-editor/SlateEditor.tsx +++ b/code/client/src/ui/pages/editor/components/slate-editor/SlateEditor.tsx @@ -1,22 +1,22 @@ -import { toSlate } from '@/domain/editor/slate/utils/slate.ts'; -import { descendant } from '@/domain/editor/slate/utils/slate.ts'; +import { toSlate } from '@/domain/editor/slate/utils/slate'; +import { descendant } from '@/domain/editor/slate/utils/slate'; import { Editable, Slate, withReact } from 'slate-react'; import { withHistory } from 'slate-history'; -import { Communication } from '@/domain/communication/communication.ts'; -import { getMarkdownPlugin } from '@/domain/editor/slate/plugins/markdown/withMarkdown.ts'; -import useEvents from '@/domain/editor/hooks/useEvents.ts'; -import useRenderers from '@/domain/editor/slate/hooks/useRenderers.tsx'; -import Toolbar from '@/ui/pages/editor/components/toolbar/Toolbar.tsx'; -import useEditor from '@/domain/editor/slate/hooks/useEditor.ts'; -import useHistory from '@/domain/editor/slate/hooks/useHistory.ts'; -import useDecorate from '@/domain/editor/slate/hooks/useDecorate.ts'; -import useCursors from '@/domain/editor/slate/hooks/useCursors.ts'; -import getEventHandlers from '@/domain/editor/slate/handlers/getEventHandlers.ts'; -import getFugueOperations from '@/domain/editor/operations/fugue/operations.ts'; +import { Communication } from '@/domain/communication/communication'; +import { getMarkdownPlugin } from '@/domain/editor/slate/plugins/markdown/withMarkdown'; +import useEvents from '@/domain/editor/hooks/useEvents'; +import useRenderers from '@/domain/editor/slate/hooks/useRenderers'; +import Toolbar from '@/ui/pages/editor/components/toolbar/Toolbar'; +import useEditor from '@/domain/editor/slate/hooks/useEditor'; +import useHistory from '@/domain/editor/slate/hooks/useHistory'; +import useDecorate from '@/domain/editor/slate/hooks/useDecorate'; +import useCursors from '@/domain/editor/slate/hooks/useCursors'; +import getEventHandlers from '@/domain/editor/slate/handlers/getEventHandlers'; +import getFugueOperations from '@/domain/editor/operations/fugue/operations'; import './SlateEditor.scss'; import { Descendant } from 'slate'; -import { Fugue } from '@/domain/editor/crdt/fugue.ts'; -import EditorTitle from '@/ui/pages/editor/components/title/EditorTitle.tsx'; +import { Fugue } from '@/domain/editor/crdt/fugue'; +import EditorTitle from '@/ui/pages/editor/components/title/EditorTitle'; import { useCallback, useEffect } from 'react'; type SlateEditorProps = { diff --git a/code/client/src/ui/pages/editor/components/title/EditorTitle.tsx b/code/client/src/ui/pages/editor/components/title/EditorTitle.tsx index da698650..e8bae515 100644 --- a/code/client/src/ui/pages/editor/components/title/EditorTitle.tsx +++ b/code/client/src/ui/pages/editor/components/title/EditorTitle.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; -import useSocketListeners from '@/domain/communication/socket/useSocketListeners.ts'; +import useSocketListeners from '@/domain/communication/socket/useSocketListeners'; import { ReactEditor, useSlate } from 'slate-react'; -import { Communication } from '@/domain/communication/communication.ts'; +import { Communication } from '@/domain/communication/communication'; interface InputProps extends React.InputHTMLAttributes { title: string; diff --git a/code/client/src/ui/pages/editor/components/toolbar/Toolbar.tsx b/code/client/src/ui/pages/editor/components/toolbar/Toolbar.tsx index 6b7e4f08..3a0bf6e9 100644 --- a/code/client/src/ui/pages/editor/components/toolbar/Toolbar.tsx +++ b/code/client/src/ui/pages/editor/components/toolbar/Toolbar.tsx @@ -1,9 +1,9 @@ import React, { CSSProperties, useEffect, useState } from 'react'; import { useFocused, useSlate } from 'slate-react'; -import CustomEditor from '@/domain/editor/slate/CustomEditor.ts'; -import { isSelected } from '@/domain/editor/slate/utils/selection.ts'; +import CustomEditor from '@/domain/editor/slate/CustomEditor'; +import { isSelected } from '@/domain/editor/slate/utils/selection'; import { FaBold, FaItalic, FaUnderline, FaStrikethrough, FaCode } from 'react-icons/fa'; -import { InlineStyle } from '@notespace/shared/types/styles.ts'; +import { InlineStyle } from '@notespace/shared/types/styles'; type ToolbarProps = { onApplyMark: (mark: InlineStyle) => void; diff --git a/code/client/src/ui/pages/home/Home.scss b/code/client/src/ui/pages/home/Home.scss new file mode 100644 index 00000000..d364dfa4 --- /dev/null +++ b/code/client/src/ui/pages/home/Home.scss @@ -0,0 +1,40 @@ +.home { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2vh; + + button { + background-color: cornflowerblue; + } + ul { + padding: 0; + text-align: center; + + li { + list-style-type: none; + margin: 1vh; + + .doc-title { + background-color: cornflowerblue; + color: white; + margin: 1vh; + padding: 0.5vh 2vh 0.5vh 2vh; + border-radius: 5px; + font-size: smaller; + } + + button { + background-color: white; + color: gray; + margin: 0; + padding: 0; + } + + button:hover { + color: red; + } + } + } +} diff --git a/code/client/src/ui/pages/home/Home.tsx b/code/client/src/ui/pages/home/Home.tsx index fa38c5b3..e72a667d 100644 --- a/code/client/src/ui/pages/home/Home.tsx +++ b/code/client/src/ui/pages/home/Home.tsx @@ -1,19 +1,51 @@ -import { useContext, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { CommunicationContext } from '@/contexts/CommunicationContext.tsx'; +import { useEffect, useState } from 'react'; +import { useCommunication } from '@/domain/communication/context/useContext'; +import { Link, useNavigate } from 'react-router-dom'; +import { Document } from '@notespace/shared/crdt/types/document'; +import { MdDelete } from 'react-icons/md'; +import './Home.scss'; function Home() { const navigate = useNavigate(); - const communication = useContext(CommunicationContext); + const communication = useCommunication(); + const [docs, setDocs] = useState([]); + + async function createDocument() { + const { id } = await communication.http.post('/documents'); + navigate(`/documents/${id}`); + } + + async function onDeleteDocument(id: string) { + await communication.http.delete(`/documents/${id}`); + setDocs(docs.filter(doc => doc.id !== id)); + } + useEffect(() => { - async function createDocument() { - const { id } = await communication.http.post('/documents'); - navigate(`/documents/${id}`); + async function getDocuments() { + const documents = await communication.http.get('/documents'); + setDocs(documents); } - createDocument(); - }, [communication.http, navigate]); + getDocuments(); + }, [communication]); - return
; + return ( +
+

Documents

+ +
    + {docs.map(doc => ( +
  • + + {doc.title || 'Untitled'} + + +
  • + ))} +
+
+ ); } export default Home; diff --git a/code/client/tests/editor/crdt/fugue.test.ts b/code/client/tests/editor/crdt/fugue.test.ts index dae193c1..14f819a1 100644 --- a/code/client/tests/editor/crdt/fugue.test.ts +++ b/code/client/tests/editor/crdt/fugue.test.ts @@ -5,8 +5,8 @@ import { InlineStyleOperation, BlockStyleOperation, ReviveOperation, -} from '@notespace/shared/crdt/types/operations.ts'; -import { Selection, Cursor } from '@notespace/shared/types/cursor.ts'; +} from '@notespace/shared/crdt/types/operations'; +import { Selection, Cursor } from '@notespace/shared/types/cursor'; import { describe, it, expect, beforeEach } from 'vitest'; import { FugueNode } from '@/domain/editor/crdt/types'; diff --git a/code/client/tests/editor/crdt/tree.test.ts b/code/client/tests/editor/crdt/tree.test.ts index 328ac794..3e924d25 100644 --- a/code/client/tests/editor/crdt/tree.test.ts +++ b/code/client/tests/editor/crdt/tree.test.ts @@ -1,8 +1,8 @@ -import { FugueTree } from '@notespace/shared/crdt/FugueTree.ts'; -import { InsertOperation } from '@notespace/shared/crdt/types/operations.ts'; +import { FugueTree } from '@notespace/shared/crdt/FugueTree'; +import { InsertOperation } from '@notespace/shared/crdt/types/operations'; import { describe, it, expect, beforeEach } from 'vitest'; import { FugueNode } from '@/domain/editor/crdt/types'; -import { Nodes } from '@notespace/shared/crdt/types/nodes.ts'; +import { Nodes } from '@notespace/shared/crdt/types/nodes'; describe('FugueTree', () => { let tree: FugueTree; diff --git a/code/client/tests/editor/slate/SlateEditor.test.tsx b/code/client/tests/editor/slate/SlateEditor.test.tsx index e089598d..58d929d2 100644 --- a/code/client/tests/editor/slate/SlateEditor.test.tsx +++ b/code/client/tests/editor/slate/SlateEditor.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { render, screen } from '@tests/test-utils.ts'; -import { mockCommunication } from '../../mocks/mockCommunication.ts'; -import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor.tsx'; +import { render, screen } from '@tests/test-utils'; +import { mockCommunication } from '../../mocks/mockCommunication'; +import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor'; import { Fugue } from '@/domain/editor/crdt/fugue'; describe('SlateEditor', () => { diff --git a/code/client/tests/editor/slate/operations/Deletions.test.tsx b/code/client/tests/editor/slate/operations/Deletions.test.tsx index 90be934f..575b7d70 100644 --- a/code/client/tests/editor/slate/operations/Deletions.test.tsx +++ b/code/client/tests/editor/slate/operations/Deletions.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { userEvent } from '@tests/test-utils.ts'; -import { setupEditor } from '../utils.tsx'; +import { userEvent } from '@tests/test-utils'; +import { setupEditor } from '../utils'; const EDITOR_PLACEHOLDER = 'Start writing...'; diff --git a/code/client/tests/editor/slate/operations/Inserts.test.tsx b/code/client/tests/editor/slate/operations/Inserts.test.tsx index 2e4f27ec..b63782f9 100644 --- a/code/client/tests/editor/slate/operations/Inserts.test.tsx +++ b/code/client/tests/editor/slate/operations/Inserts.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { userEvent } from '@tests/test-utils.ts'; -import { setupEditor } from '../utils.tsx'; +import { userEvent } from '@tests/test-utils'; +import { setupEditor } from '../utils'; describe('Inserts', () => { let editor: HTMLElement; diff --git a/code/client/tests/editor/slate/toSlate.test.ts b/code/client/tests/editor/slate/toSlate.test.ts index 8b167b89..7626bb3f 100644 --- a/code/client/tests/editor/slate/toSlate.test.ts +++ b/code/client/tests/editor/slate/toSlate.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { Fugue } from '@/domain/editor/crdt/fugue'; -import { Cursor, Selection } from '@notespace/shared/types/cursor.ts'; -import { toSlate } from '@/domain/editor/slate/utils/slate.ts'; +import { Cursor, Selection } from '@notespace/shared/types/cursor'; +import { toSlate } from '@/domain/editor/slate/utils/slate'; import { Descendant } from 'slate'; describe('toSlate', () => { diff --git a/code/client/tests/editor/slate/utils.tsx b/code/client/tests/editor/slate/utils.tsx index adc3729d..6cc69116 100644 --- a/code/client/tests/editor/slate/utils.tsx +++ b/code/client/tests/editor/slate/utils.tsx @@ -1,6 +1,6 @@ -import { setup } from '@tests/test-utils.ts'; -import { mockCommunication } from '../../mocks/mockCommunication.ts'; -import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor.tsx'; +import { setup } from '@tests/test-utils'; +import { mockCommunication } from '../../mocks/mockCommunication'; +import SlateEditor from '@/ui/pages/editor/components/slate-editor/SlateEditor'; import { Fugue } from '@/domain/editor/crdt/fugue'; /** diff --git a/code/client/tests/mocks/mock-server.ts b/code/client/tests/mocks/mock-server.ts index 53e65fc3..ab15ce3f 100644 --- a/code/client/tests/mocks/mock-server.ts +++ b/code/client/tests/mocks/mock-server.ts @@ -1,4 +1,4 @@ -import handlers from './mock-handlers.ts'; -import { mockServer } from '@tests/mocks/global-mocks.ts'; +import handlers from './mock-handlers'; +import { mockServer } from '@tests/mocks/global-mocks'; export const server = mockServer(...handlers); diff --git a/code/client/tests/mocks/mockCommunication.ts b/code/client/tests/mocks/mockCommunication.ts index 217879ab..98a29dbb 100644 --- a/code/client/tests/mocks/mockCommunication.ts +++ b/code/client/tests/mocks/mockCommunication.ts @@ -1,4 +1,4 @@ -import { Communication } from '@/domain/communication/communication.ts'; +import { Communication } from '@/domain/communication/communication'; export function mockCommunication(): Communication { return { diff --git a/code/client/tsconfig.json b/code/client/tsconfig.json index 70277791..5aab918c 100644 --- a/code/client/tsconfig.json +++ b/code/client/tsconfig.json @@ -7,7 +7,7 @@ "skipLibCheck": false, "esModuleInterop": false, "allowSyntheticDefaultImports": true, - "allowImportingTsExtensions": true, + "allowImportingTsExtensions": false, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", diff --git a/code/server/package.json b/code/server/package.json index b9fc615d..4ad96725 100644 --- a/code/server/package.json +++ b/code/server/package.json @@ -36,6 +36,7 @@ "@typescript-eslint/parser": "^7.8.0", "babel-jest": "^29.7.0", "eslint": "^8.57.0", + "express-promise-router": "^4.1.1", "jest": "^29.7.0", "knip": "^5.11.0", "prettier": "^3.2.5", @@ -46,4 +47,4 @@ "tsx": "^4.7.3", "typescript": "^5.4.5" } -} \ No newline at end of file +} diff --git a/code/server/src/controllers/http/document/createDocument.ts b/code/server/src/controllers/http/document/createDocument.ts deleted file mode 100644 index 57db670e..00000000 --- a/code/server/src/controllers/http/document/createDocument.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Request, Response } from 'express'; -import { DocumentService } from '@src/types'; - -function createDocument(service: DocumentService) { - return async (req: Request, res: Response) => { - const id = await service.createDocument(); - res.status(201).send({ id }); - }; -} - -export default createDocument; diff --git a/code/server/src/controllers/http/document/deleteDocument.ts b/code/server/src/controllers/http/document/deleteDocument.ts deleted file mode 100644 index 9a66db28..00000000 --- a/code/server/src/controllers/http/document/deleteDocument.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Request, Response } from 'express'; -import { DocumentService } from '@src/types'; - -function deleteDocument(service: DocumentService) { - return (req: Request, res: Response) => { - service.deleteDocument(req.params.id); - res.status(200).send(); - }; -} - -export default deleteDocument; diff --git a/code/server/src/controllers/http/document/getDocument.ts b/code/server/src/controllers/http/document/getDocument.ts deleted file mode 100644 index 2b4afb6f..00000000 --- a/code/server/src/controllers/http/document/getDocument.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Request, Response } from 'express'; -import { DocumentService } from '@src/types'; - -function getDocument(service: DocumentService) { - return async (req: Request, res: Response) => { - const document = await service.getDocument(req.params.id); - res.status(200).send(document); - }; -} - -export default getDocument; diff --git a/code/server/src/controllers/http/documentHandlers.ts b/code/server/src/controllers/http/documentHandlers.ts new file mode 100644 index 00000000..dec18769 --- /dev/null +++ b/code/server/src/controllers/http/documentHandlers.ts @@ -0,0 +1,33 @@ +import { Request, Response } from 'express'; +import { DocumentService } from '@src/types'; + +function documentHandlers(service: DocumentService) { + async function getDocuments(req: Request, res: Response) { + const documents = await service.getDocuments(); + res.status(200).send(documents); + } + + async function createDocument(req: Request, res: Response) { + const id = await service.createDocument(); + res.status(201).send({ id }); + } + + async function getDocument(req: Request, res: Response) { + const document = await service.getDocument(req.params.id); + res.status(200).send(document); + } + + async function deleteDocument(req: Request, res: Response) { + service.deleteDocument(req.params.id); + res.status(200).send(); + } + + return { + getDocuments, + createDocument, + getDocument, + deleteDocument, + }; +} + +export default documentHandlers; diff --git a/code/server/src/controllers/http/errorHandler.ts b/code/server/src/controllers/http/errorHandler.ts new file mode 100644 index 00000000..ff6607f9 --- /dev/null +++ b/code/server/src/controllers/http/errorHandler.ts @@ -0,0 +1,7 @@ +import { Request, Response, NextFunction } from 'express'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export default function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) { + console.error(err.stack); + res.status(500).send({ error: err.message }); +} diff --git a/code/server/src/controllers/http/router.ts b/code/server/src/controllers/http/router.ts index 8755814a..f1c21d96 100644 --- a/code/server/src/controllers/http/router.ts +++ b/code/server/src/controllers/http/router.ts @@ -1,22 +1,26 @@ import express from 'express'; +import PromiseRouter from 'express-promise-router'; import { DocumentService } from '@src/types'; -import getDocument from '@controllers/http/document/getDocument'; -import deleteDocument from '@controllers/http/document/deleteDocument'; -import createDocument from '@controllers/http/document/createDocument'; +import documentHandlers from '@controllers/http/documentHandlers'; +import errorHandler from '@controllers/http/errorHandler'; export default function (service: DocumentService) { if (!service) { throw new Error('Service parameter is required'); } - const router = express.Router(); + const { getDocuments, createDocument, getDocument, deleteDocument } = documentHandlers(service); + + const router = PromiseRouter(); // automatically routes unhandled errors to error handling middleware router.use(express.urlencoded({ extended: true })); + router.use(errorHandler); router.get('/', (req, res) => { res.send('Welcome to NoteSpace'); }); - router.post('/documents', createDocument(service)); - router.get('/documents/:id', getDocument(service)); - router.delete('/documents/:id', deleteDocument(service)); + router.get('/documents', getDocuments); + router.post('/documents', createDocument); + router.get('/documents/:id', getDocument); + router.delete('/documents/:id', deleteDocument); return router; } diff --git a/code/server/src/controllers/ws/document/onCursorChange.ts b/code/server/src/controllers/ws/document/onCursorChange.ts index 53bfe08d..19ba911e 100644 --- a/code/server/src/controllers/ws/document/onCursorChange.ts +++ b/code/server/src/controllers/ws/document/onCursorChange.ts @@ -12,9 +12,8 @@ const cursorColorsMap = new Map(); function onCursorChange() { return (socket: Socket, range: any) => { const documentId = getRoomId(socket); - if (!documentId) { - throw new Error('Document Id is required'); - } + if (!documentId) return; + if (!range) { deleteCursor(socket, documentId); } else { diff --git a/code/server/src/database/memory/operations.ts b/code/server/src/database/memory/operations.ts index ce4237ac..80e9aba0 100644 --- a/code/server/src/database/memory/operations.ts +++ b/code/server/src/database/memory/operations.ts @@ -6,9 +6,14 @@ import { emptyTree } from '@notespace/shared/crdt/utils'; export default function DocumentDatabase(): DocumentDatabase { const documents: Record = {}; + async function getDocuments() { + return Object.values(documents); + } + async function createDocument() { const id = uuid(); documents[id] = { + id, title: '', nodes: emptyTree(), }; @@ -40,6 +45,7 @@ export default function DocumentDatabase(): DocumentDatabase { } return { + getDocuments, createDocument, getDocument, deleteDocument, diff --git a/code/server/src/server.ts b/code/server/src/server.ts index 936aeb13..956888f4 100644 --- a/code/server/src/server.ts +++ b/code/server/src/server.ts @@ -7,7 +7,7 @@ import serviceInit from '@services/documentService'; import eventsInit from '@controllers/ws/events'; import router from '@src/controllers/http/router'; import onConnection from '@controllers/ws/onConnection'; -import config from './config'; +import config from '@src/config'; const database = databaseInit(); const service = serviceInit(database); diff --git a/code/server/src/services/documentService.ts b/code/server/src/services/documentService.ts index 97fad46b..78d06279 100644 --- a/code/server/src/services/documentService.ts +++ b/code/server/src/services/documentService.ts @@ -12,6 +12,10 @@ import { ReviveOperation } from '@notespace/shared/crdt/types/operations'; export default function DocumentService(database: DocumentDatabase): DocumentService { const tree = new FugueTree(); + async function getDocuments() { + return await database.getDocuments(); + } + async function createDocument() { return await database.createDocument(); } @@ -76,6 +80,7 @@ export default function DocumentService(database: DocumentDatabase): DocumentSer } return { + getDocuments, createDocument, getDocument, deleteDocument, diff --git a/code/server/src/types.d.ts b/code/server/src/types.d.ts index f8b3b7d7..f6d88e7b 100644 --- a/code/server/src/types.d.ts +++ b/code/server/src/types.d.ts @@ -9,6 +9,7 @@ import { } from '@notespace/shared/crdt/types/operations'; type DocumentDatabase = { + getDocuments: () => Promise; createDocument: () => Promise; getDocument: (id: string) => Promise; updateDocument: (id: string, document: Partial) => Promise; @@ -16,6 +17,7 @@ type DocumentDatabase = { }; type DocumentService = { + getDocuments: () => Promise; createDocument: () => Promise; getDocument: (id: string) => Promise; deleteDocument: (id: string) => void; diff --git a/code/shared/crdt/types/document.ts b/code/shared/crdt/types/document.ts index f8de4ed9..9151e76e 100644 --- a/code/shared/crdt/types/document.ts +++ b/code/shared/crdt/types/document.ts @@ -1,6 +1,7 @@ import { Nodes } from "./nodes"; export type Document = { + id: string; title: string; nodes: Nodes; };