From 4553a6ec30214a17ef76cb662982f9da4e0f81b6 Mon Sep 17 00:00:00 2001 From: choidabom Date: Sat, 7 Sep 2024 23:33:08 +0900 Subject: [PATCH 1/9] Add Vim binding for CodePair using CodeMirror 6 --- frontend/package-lock.json | 13 ++++ frontend/package.json | 1 + .../src/components/editor/DocumentView.tsx | 45 ++++++++---- frontend/src/components/editor/Editor.tsx | 6 +- .../src/components/editor/EditorBottomBar.tsx | 68 +++++++++++++++++++ frontend/src/components/editor/Preview.tsx | 2 +- .../src/components/headers/DocumentHeader.tsx | 7 +- frontend/src/store/editorSlice.ts | 30 ++++++-- 8 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 frontend/src/components/editor/EditorBottomBar.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d6ba95e8..d853b4fb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,6 +20,7 @@ "@mui/x-date-pickers": "^7.13.0", "@react-hook/window-size": "^3.1.1", "@reduxjs/toolkit": "^2.0.1", + "@replit/codemirror-vim": "^6.2.1", "@sentry/react": "^7.99.0", "@swc/helpers": "^0.5.3", "@tanstack/react-query": "^5.17.15", @@ -1973,6 +1974,18 @@ "node": ">=14.0.0" } }, + "node_modules/@replit/codemirror-vim": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@replit/codemirror-vim/-/codemirror-vim-6.2.1.tgz", + "integrity": "sha512-qDAcGSHBYU5RrdO//qCmD8K9t6vbP327iCj/iqrkVnjbrpFhrjOt92weGXGHmTNRh16cUtkUZ7Xq7rZf+8HVow==", + "peerDependencies": { + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.1.0", + "@codemirror/search": "^6.2.0", + "@codemirror/state": "^6.0.1", + "@codemirror/view": "^6.0.3" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6f83a6f1..cdcd38dd 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,6 +33,7 @@ "@mui/x-date-pickers": "^7.13.0", "@react-hook/window-size": "^3.1.1", "@reduxjs/toolkit": "^2.0.1", + "@replit/codemirror-vim": "^6.2.1", "@sentry/react": "^7.99.0", "@swc/helpers": "^0.5.3", "@tanstack/react-query": "^5.17.15", diff --git a/frontend/src/components/editor/DocumentView.tsx b/frontend/src/components/editor/DocumentView.tsx index 7b8613e4..4e2befd1 100644 --- a/frontend/src/components/editor/DocumentView.tsx +++ b/frontend/src/components/editor/DocumentView.tsx @@ -1,13 +1,14 @@ +import { Backdrop, Box, CircularProgress, Paper } from "@mui/material"; +import { useWindowWidth } from "@react-hook/window-size"; import { useSelector } from "react-redux"; -import { selectEditor } from "../../store/editorSlice"; import Resizable from "react-resizable-layout"; -import { useWindowWidth } from "@react-hook/window-size"; +import { ScrollSync, ScrollSyncPane } from "react-scroll-sync"; +import { EditorModeType, selectEditor } from "../../store/editorSlice"; import Editor from "./Editor"; -import { Backdrop, Box, CircularProgress, Paper } from "@mui/material"; +import EditorBottomBar, { BOTTOM_BAR_HEIGHT } from "./EditorBottomBar"; import Preview from "./Preview"; -import { ScrollSync, ScrollSyncPane } from "react-scroll-sync"; -function DocumentView() { +const DocumentView = () => { const editorStore = useSelector(selectEditor); const windowWidth = useWindowWidth(); @@ -20,9 +21,7 @@ function DocumentView() { return ( <> - {/* For Markdown Preview Theme */} -
- {editorStore.mode === "both" && ( + {editorStore.mode === EditorModeType.both && ( {({ position: width, separatorProps }) => ( @@ -32,10 +31,21 @@ function DocumentView() { display: "flex", height: "100%", overflow: "hidden", + position: "relative", }} > -
- +
+
+ +
+
)} - {editorStore.mode === "read" && ( + + {editorStore.mode === EditorModeType.edit && ( +
+
+ +
+ +
+ )} + + {editorStore.mode === EditorModeType.read && ( )} - {editorStore.mode === "edit" && } ); -} +}; export default DocumentView; diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx index 31f9cae4..f9b4c6c2 100644 --- a/frontend/src/components/editor/Editor.tsx +++ b/frontend/src/components/editor/Editor.tsx @@ -1,6 +1,7 @@ import { markdown } from "@codemirror/lang-markdown"; import { EditorState } from "@codemirror/state"; import { keymap } from "@codemirror/view"; +import { vim } from "@replit/codemirror-vim"; import { xcodeDark, xcodeLight } from "@uiw/codemirror-theme-xcode"; import { basicSetup, EditorView } from "codemirror"; import { useCallback, useEffect, useState } from "react"; @@ -10,7 +11,7 @@ import { useCreateUploadUrlMutation, useUploadFileMutation } from "../../hooks/a import { useCurrentTheme } from "../../hooks/useCurrentTheme"; import { useFormatUtils } from "../../hooks/useFormatUtils"; import { useToolBar } from "../../hooks/useToolBar"; -import { selectEditor, setCmView } from "../../store/editorSlice"; +import { CodeKeyType, selectEditor, setCmView } from "../../store/editorSlice"; import { selectSetting } from "../../store/settingSlice"; import { selectWorkspace } from "../../store/workspaceSlice"; import { imageUploader } from "../../utils/imageUploader"; @@ -41,6 +42,7 @@ function Editor() { !element || !editorStore.doc || !editorStore.client || + !editorStore.codeKey || typeof settingStore.fileUpload?.enable !== "boolean" ) { return; @@ -66,6 +68,7 @@ function Editor() { keymap.of(setKeymapConfig()), basicSetup, markdown(), + editorStore.codeKey === CodeKeyType.vim ? vim() : [], themeMode == "light" ? xcodeLight : xcodeDark, EditorView.theme({ "&": { width: "100%" } }), EditorView.lineWrapping, @@ -94,6 +97,7 @@ function Editor() { element, editorStore.client, editorStore.doc, + editorStore.codeKey, themeMode, workspaceStore.data, settingStore.fileUpload?.enable, diff --git a/frontend/src/components/editor/EditorBottomBar.tsx b/frontend/src/components/editor/EditorBottomBar.tsx new file mode 100644 index 00000000..ed01abfa --- /dev/null +++ b/frontend/src/components/editor/EditorBottomBar.tsx @@ -0,0 +1,68 @@ +import { Button, Menu, MenuItem } from "@mui/material"; +import { useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { CodeKeyType, selectEditor, setCodeKeyType } from "../../store/editorSlice"; + +export const BOTTOM_BAR_HEIGHT = 25; + +const EditorBottomBar = (props: { width: number | string }) => { + const { width } = props; + const dispatch = useDispatch(); + const editorStore = useSelector(selectEditor); + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const handleOpen = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const handleChangeCodeKey = (newKeyCode: CodeKeyType) => { + dispatch(setCodeKeyType(newKeyCode)); + handleClose(); + }; + + return ( +
+ + + {Object.values(CodeKeyType).map((keyType) => ( + handleChangeCodeKey(keyType)}> + {keyType} + + ))} + +
+ ); +}; + +export default EditorBottomBar; diff --git a/frontend/src/components/editor/Preview.tsx b/frontend/src/components/editor/Preview.tsx index 6e1d493b..c9d7a3bc 100644 --- a/frontend/src/components/editor/Preview.tsx +++ b/frontend/src/components/editor/Preview.tsx @@ -6,8 +6,8 @@ import { useEffect, useState } from "react"; import { useSelector } from "react-redux"; import rehypeExternalLinks from "rehype-external-links"; import rehypeKatex from "rehype-katex"; -import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; import { getCodeString } from "rehype-rewrite"; +import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; import remarkMath from "remark-math"; import { useCurrentTheme } from "../../hooks/useCurrentTheme"; import { selectEditor } from "../../store/editorSlice"; diff --git a/frontend/src/components/headers/DocumentHeader.tsx b/frontend/src/components/headers/DocumentHeader.tsx index 75f014b4..c314071f 100644 --- a/frontend/src/components/headers/DocumentHeader.tsx +++ b/frontend/src/components/headers/DocumentHeader.tsx @@ -18,6 +18,7 @@ import { useNavigate } from "react-router-dom"; import { useUserPresence } from "../../hooks/useUserPresence"; import { EditorModeType, selectEditor, setMode } from "../../store/editorSlice"; import { selectWorkspace } from "../../store/workspaceSlice"; +import { ShareRole } from "../../utils/share"; import DownloadMenu from "../common/DownloadMenu"; import ShareButton from "../common/ShareButton"; import ThemeButton from "../common/ThemeButton"; @@ -31,8 +32,8 @@ function DocumentHeader() { const { presenceList } = useUserPresence(editorState.doc); useEffect(() => { - if (editorState.shareRole === "READ") { - dispatch(setMode("read")); + if (editorState.shareRole === ShareRole.READ) { + dispatch(setMode(EditorModeType.read)); } }, [dispatch, editorState.shareRole]); @@ -58,7 +59,7 @@ function DocumentHeader() { )} - {editorState.shareRole !== "READ" && ( + {editorState.shareRole !== ShareRole.READ && ( ) => { state.mode = action.payload; }, + setCodeKeyType: (state, action: PayloadAction) => { + state.codeKey = action.payload; + }, setShareRole: (state, action: PayloadAction) => { state.shareRole = action.payload; }, @@ -50,7 +65,8 @@ export const editorSlice = createSlice({ }, }); -export const { setMode, setDoc, setClient, setShareRole, setCmView } = editorSlice.actions; +export const { setMode, setCodeKeyType, setShareRole, setDoc, setClient, setCmView } = + editorSlice.actions; export const selectEditor = (state: RootState) => state.editor; From cb6924084803c3f713b28090397a134f712c3864 Mon Sep 17 00:00:00 2001 From: choidabom Date: Sun, 8 Sep 2024 00:17:30 +0900 Subject: [PATCH 2/9] Add vim key mapping 'jj' for insert mode --- frontend/src/components/editor/Editor.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx index f9b4c6c2..0b964632 100644 --- a/frontend/src/components/editor/Editor.tsx +++ b/frontend/src/components/editor/Editor.tsx @@ -1,7 +1,7 @@ import { markdown } from "@codemirror/lang-markdown"; import { EditorState } from "@codemirror/state"; import { keymap } from "@codemirror/view"; -import { vim } from "@replit/codemirror-vim"; +import { Vim, vim } from "@replit/codemirror-vim"; import { xcodeDark, xcodeLight } from "@uiw/codemirror-theme-xcode"; import { basicSetup, EditorView } from "codemirror"; import { useCallback, useEffect, useState } from "react"; @@ -86,8 +86,10 @@ function Editor() { ], }); - const view = new EditorView({ state, parent: element }); + // Vim key mapping: Map 'jj' to '' in insert mode + Vim.map("jj", "", "insert"); + const view = new EditorView({ state, parent: element }); dispatch(setCmView(view)); return () => { From 41bc134505de3bff9f9db59effee75d0739e5df5 Mon Sep 17 00:00:00 2001 From: choidabom Date: Sun, 8 Sep 2024 00:26:58 +0900 Subject: [PATCH 3/9] Fix argument type --- .../src/pages/workspace/document/share/Index.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/workspace/document/share/Index.tsx b/frontend/src/pages/workspace/document/share/Index.tsx index 365da099..803e9a8c 100644 --- a/frontend/src/pages/workspace/document/share/Index.tsx +++ b/frontend/src/pages/workspace/document/share/Index.tsx @@ -5,8 +5,15 @@ import { Navigate, useLocation, useSearchParams } from "react-router-dom"; import DocumentView from "../../../../components/editor/DocumentView"; import { useGetDocumentBySharingTokenQuery } from "../../../../hooks/api/document"; import { useYorkieDocument } from "../../../../hooks/useYorkieDocument"; -import { setClient, setDoc, setMode, setShareRole } from "../../../../store/editorSlice"; +import { + EditorModeType, + setClient, + setDoc, + setMode, + setShareRole, +} from "../../../../store/editorSlice"; import { selectUser } from "../../../../store/userSlice"; +import { ShareRole } from "../../../../utils/share"; function DocumentShareIndex() { const dispatch = useDispatch(); @@ -25,8 +32,8 @@ function DocumentShareIndex() { dispatch(setShareRole(sharedDocument.role)); - if (sharedDocument.role === "READ") { - dispatch(setMode("read")); + if (sharedDocument.role === ShareRole.READ) { + dispatch(setMode(EditorModeType.read)); } }, [dispatch, sharedDocument?.role]); From f6eca6b4a6feb32f7cfbc1b954ad19999da18537 Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 18:23:47 +0900 Subject: [PATCH 4/9] Fix components to use `function` keyword --- frontend/src/components/editor/DocumentView.tsx | 4 ++-- frontend/src/components/editor/EditorBottomBar.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/editor/DocumentView.tsx b/frontend/src/components/editor/DocumentView.tsx index 4e2befd1..1990ef47 100644 --- a/frontend/src/components/editor/DocumentView.tsx +++ b/frontend/src/components/editor/DocumentView.tsx @@ -8,7 +8,7 @@ import Editor from "./Editor"; import EditorBottomBar, { BOTTOM_BAR_HEIGHT } from "./EditorBottomBar"; import Preview from "./Preview"; -const DocumentView = () => { +function DocumentView() { const editorStore = useSelector(selectEditor); const windowWidth = useWindowWidth(); @@ -93,6 +93,6 @@ const DocumentView = () => { )} ); -}; +} export default DocumentView; diff --git a/frontend/src/components/editor/EditorBottomBar.tsx b/frontend/src/components/editor/EditorBottomBar.tsx index ed01abfa..a2085fe7 100644 --- a/frontend/src/components/editor/EditorBottomBar.tsx +++ b/frontend/src/components/editor/EditorBottomBar.tsx @@ -5,7 +5,7 @@ import { CodeKeyType, selectEditor, setCodeKeyType } from "../../store/editorSli export const BOTTOM_BAR_HEIGHT = 25; -const EditorBottomBar = (props: { width: number | string }) => { +function EditorBottomBar(props: { width: number | string }) { const { width } = props; const dispatch = useDispatch(); const editorStore = useSelector(selectEditor); @@ -63,6 +63,6 @@ const EditorBottomBar = (props: { width: number | string }) => {
); -}; +} export default EditorBottomBar; From 46b02f01dce7d51eb42ac4cf67af94f2e1af1027 Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 18:28:13 +0900 Subject: [PATCH 5/9] Add EditorBottomBar props interface --- frontend/src/components/editor/EditorBottomBar.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/editor/EditorBottomBar.tsx b/frontend/src/components/editor/EditorBottomBar.tsx index a2085fe7..9aaae8b3 100644 --- a/frontend/src/components/editor/EditorBottomBar.tsx +++ b/frontend/src/components/editor/EditorBottomBar.tsx @@ -5,7 +5,11 @@ import { CodeKeyType, selectEditor, setCodeKeyType } from "../../store/editorSli export const BOTTOM_BAR_HEIGHT = 25; -function EditorBottomBar(props: { width: number | string }) { +interface EditorBottomBarProps { + width: number | string; +} + +function EditorBottomBar(props: EditorBottomBarProps) { const { width } = props; const dispatch = useDispatch(); const editorStore = useSelector(selectEditor); From 002396dad922d38246b85c95c96534a484077c9e Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 18:34:18 +0900 Subject: [PATCH 6/9] Fix enum members to use capital letters --- frontend/src/components/editor/DocumentView.tsx | 6 +++--- frontend/src/components/editor/Editor.tsx | 2 +- frontend/src/components/headers/DocumentHeader.tsx | 2 +- .../src/pages/workspace/document/share/Index.tsx | 2 +- frontend/src/store/editorSlice.ts | 14 +++++++------- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/editor/DocumentView.tsx b/frontend/src/components/editor/DocumentView.tsx index 1990ef47..393786d6 100644 --- a/frontend/src/components/editor/DocumentView.tsx +++ b/frontend/src/components/editor/DocumentView.tsx @@ -21,7 +21,7 @@ function DocumentView() { return ( <> - {editorStore.mode === EditorModeType.both && ( + {editorStore.mode === EditorModeType.BOTH && ( {({ position: width, separatorProps }) => ( @@ -77,7 +77,7 @@ function DocumentView() { )} - {editorStore.mode === EditorModeType.edit && ( + {editorStore.mode === EditorModeType.EDIT && (
@@ -86,7 +86,7 @@ function DocumentView() {
)} - {editorStore.mode === EditorModeType.read && ( + {editorStore.mode === EditorModeType.READ && ( diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx index 0b964632..6d1d1a7c 100644 --- a/frontend/src/components/editor/Editor.tsx +++ b/frontend/src/components/editor/Editor.tsx @@ -68,7 +68,7 @@ function Editor() { keymap.of(setKeymapConfig()), basicSetup, markdown(), - editorStore.codeKey === CodeKeyType.vim ? vim() : [], + editorStore.codeKey === CodeKeyType.VIM ? vim() : [], themeMode == "light" ? xcodeLight : xcodeDark, EditorView.theme({ "&": { width: "100%" } }), EditorView.lineWrapping, diff --git a/frontend/src/components/headers/DocumentHeader.tsx b/frontend/src/components/headers/DocumentHeader.tsx index c314071f..89e86769 100644 --- a/frontend/src/components/headers/DocumentHeader.tsx +++ b/frontend/src/components/headers/DocumentHeader.tsx @@ -33,7 +33,7 @@ function DocumentHeader() { useEffect(() => { if (editorState.shareRole === ShareRole.READ) { - dispatch(setMode(EditorModeType.read)); + dispatch(setMode(EditorModeType.READ)); } }, [dispatch, editorState.shareRole]); diff --git a/frontend/src/pages/workspace/document/share/Index.tsx b/frontend/src/pages/workspace/document/share/Index.tsx index 803e9a8c..17132416 100644 --- a/frontend/src/pages/workspace/document/share/Index.tsx +++ b/frontend/src/pages/workspace/document/share/Index.tsx @@ -33,7 +33,7 @@ function DocumentShareIndex() { dispatch(setShareRole(sharedDocument.role)); if (sharedDocument.role === ShareRole.READ) { - dispatch(setMode(EditorModeType.read)); + dispatch(setMode(EditorModeType.READ)); } }, [dispatch, sharedDocument?.role]); diff --git a/frontend/src/store/editorSlice.ts b/frontend/src/store/editorSlice.ts index 6fd6fe16..bff1f0a6 100644 --- a/frontend/src/store/editorSlice.ts +++ b/frontend/src/store/editorSlice.ts @@ -7,14 +7,14 @@ import { YorkieCodeMirrorDocType, YorkieCodeMirrorPresenceType } from "../utils/ import { RootState } from "./store"; export enum EditorModeType { - edit = "edit", - both = "both", - read = "read", + EDIT = "edit", + BOTH = "both", + READ = "read", } export enum CodeKeyType { - sublime = "sublime", - vim = "vim", + SUBLIME = "sublime", + VIM = "vim", } export type CodePairDocType = yorkie.Document< @@ -32,8 +32,8 @@ export interface EditorState { } const initialState: EditorState = { - mode: EditorModeType.both, - codeKey: CodeKeyType.sublime, + mode: EditorModeType.BOTH, + codeKey: CodeKeyType.SUBLIME, shareRole: null, doc: null, client: null, From 7e449a8ae03956a48b352475d8d9c463b2d8d823 Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 19:01:51 +0900 Subject: [PATCH 7/9] Move `EditorBottomBar` into `Editor` components --- .../src/components/editor/DocumentView.tsx | 11 +--- frontend/src/components/editor/Editor.tsx | 54 ++++++++++++------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/editor/DocumentView.tsx b/frontend/src/components/editor/DocumentView.tsx index 393786d6..1209458c 100644 --- a/frontend/src/components/editor/DocumentView.tsx +++ b/frontend/src/components/editor/DocumentView.tsx @@ -5,7 +5,6 @@ import Resizable from "react-resizable-layout"; import { ScrollSync, ScrollSyncPane } from "react-scroll-sync"; import { EditorModeType, selectEditor } from "../../store/editorSlice"; import Editor from "./Editor"; -import EditorBottomBar, { BOTTOM_BAR_HEIGHT } from "./EditorBottomBar"; import Preview from "./Preview"; function DocumentView() { @@ -42,10 +41,7 @@ function DocumentView() { height: "100%", }} > -
- -
- +
-
- -
- +
)} diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx index 6d1d1a7c..920c1216 100644 --- a/frontend/src/components/editor/Editor.tsx +++ b/frontend/src/components/editor/Editor.tsx @@ -18,9 +18,15 @@ import { imageUploader } from "../../utils/imageUploader"; import { intelligencePivot } from "../../utils/intelligence/intelligencePivot"; import { urlHyperlinkInserter } from "../../utils/urlHyperlinkInserter"; import { yorkieCodeMirror } from "../../utils/yorkie"; +import EditorBottomBar, { BOTTOM_BAR_HEIGHT } from "./EditorBottomBar"; import ToolBar from "./ToolBar"; -function Editor() { +interface EditorProps { + width: number | string; +} + +function Editor(props: EditorProps) { + const { width } = props; const dispatch = useDispatch(); const themeMode = useCurrentTheme(); const [element, setElement] = useState(); @@ -112,26 +118,34 @@ function Editor() { ]); return ( - -
-
- {Boolean(toolBarState.show) && ( - - )} + <> +
+ +
+
+ {Boolean(toolBarState.show) && ( + + )} +
+
-
+ + ); } From 5981cb19e51a4399d94bcd355edf5ea1ddbd69e5 Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 19:06:39 +0900 Subject: [PATCH 8/9] Change to `Paper` component --- frontend/src/components/editor/EditorBottomBar.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/editor/EditorBottomBar.tsx b/frontend/src/components/editor/EditorBottomBar.tsx index 9aaae8b3..6b4777ba 100644 --- a/frontend/src/components/editor/EditorBottomBar.tsx +++ b/frontend/src/components/editor/EditorBottomBar.tsx @@ -1,4 +1,4 @@ -import { Button, Menu, MenuItem } from "@mui/material"; +import { Button, Menu, MenuItem, Paper } from "@mui/material"; import { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { CodeKeyType, selectEditor, setCodeKeyType } from "../../store/editorSlice"; @@ -30,16 +30,18 @@ function EditorBottomBar(props: EditorBottomBarProps) { }; return ( -
+ ); } From e8f3ffb2d2f7b0ae5f3783b946c6b0fd610ea77f Mon Sep 17 00:00:00 2001 From: choidabom Date: Mon, 9 Sep 2024 19:42:48 +0900 Subject: [PATCH 9/9] Move codekey options to `configSlice` --- .../src/components/common/ThemeButton.tsx | 8 +++---- frontend/src/components/editor/Editor.tsx | 9 ++++---- .../src/components/editor/EditorBottomBar.tsx | 6 ++--- .../components/popovers/ProfilePopover.tsx | 16 +++++++------- frontend/src/store/configSlice.ts | 22 +++++++++++++++---- frontend/src/store/editorSlice.ts | 13 +---------- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/frontend/src/components/common/ThemeButton.tsx b/frontend/src/components/common/ThemeButton.tsx index c29a036c..6d8afe69 100644 --- a/frontend/src/components/common/ThemeButton.tsx +++ b/frontend/src/components/common/ThemeButton.tsx @@ -1,21 +1,21 @@ -import { IconButton } from "@mui/material"; import DarkModeIcon from "@mui/icons-material/DarkMode"; import LightModeIcon from "@mui/icons-material/LightMode"; +import { IconButton } from "@mui/material"; import { useDispatch } from "react-redux"; -import { setTheme } from "../../store/configSlice"; import { useCurrentTheme } from "../../hooks/useCurrentTheme"; +import { setTheme, ThemeType } from "../../store/configSlice"; function ThemeButton() { const dispatch = useDispatch(); const themeMode = useCurrentTheme(); const handleChangeTheme = () => { - dispatch(setTheme(themeMode == "light" ? "dark" : "light")); + dispatch(setTheme(themeMode == ThemeType.LIGHT ? ThemeType.DARK : ThemeType.LIGHT)); }; return ( - {themeMode === "light" ? : } + {themeMode === ThemeType.LIGHT ? : } ); } diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx index 920c1216..1c6dfe29 100644 --- a/frontend/src/components/editor/Editor.tsx +++ b/frontend/src/components/editor/Editor.tsx @@ -11,7 +11,8 @@ import { useCreateUploadUrlMutation, useUploadFileMutation } from "../../hooks/a import { useCurrentTheme } from "../../hooks/useCurrentTheme"; import { useFormatUtils } from "../../hooks/useFormatUtils"; import { useToolBar } from "../../hooks/useToolBar"; -import { CodeKeyType, selectEditor, setCmView } from "../../store/editorSlice"; +import { CodeKeyType, selectConfig } from "../../store/configSlice"; +import { selectEditor, setCmView } from "../../store/editorSlice"; import { selectSetting } from "../../store/settingSlice"; import { selectWorkspace } from "../../store/workspaceSlice"; import { imageUploader } from "../../utils/imageUploader"; @@ -31,6 +32,7 @@ function Editor(props: EditorProps) { const themeMode = useCurrentTheme(); const [element, setElement] = useState(); const editorStore = useSelector(selectEditor); + const configStore = useSelector(selectConfig); const settingStore = useSelector(selectSetting); const workspaceStore = useSelector(selectWorkspace); const { mutateAsync: createUploadUrl } = useCreateUploadUrlMutation(); @@ -48,7 +50,6 @@ function Editor(props: EditorProps) { !element || !editorStore.doc || !editorStore.client || - !editorStore.codeKey || typeof settingStore.fileUpload?.enable !== "boolean" ) { return; @@ -74,7 +75,7 @@ function Editor(props: EditorProps) { keymap.of(setKeymapConfig()), basicSetup, markdown(), - editorStore.codeKey === CodeKeyType.VIM ? vim() : [], + configStore.codeKey === CodeKeyType.VIM ? vim() : [], themeMode == "light" ? xcodeLight : xcodeDark, EditorView.theme({ "&": { width: "100%" } }), EditorView.lineWrapping, @@ -105,7 +106,7 @@ function Editor(props: EditorProps) { element, editorStore.client, editorStore.doc, - editorStore.codeKey, + configStore.codeKey, themeMode, workspaceStore.data, settingStore.fileUpload?.enable, diff --git a/frontend/src/components/editor/EditorBottomBar.tsx b/frontend/src/components/editor/EditorBottomBar.tsx index 6b4777ba..b3e3d507 100644 --- a/frontend/src/components/editor/EditorBottomBar.tsx +++ b/frontend/src/components/editor/EditorBottomBar.tsx @@ -1,7 +1,7 @@ import { Button, Menu, MenuItem, Paper } from "@mui/material"; import { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { CodeKeyType, selectEditor, setCodeKeyType } from "../../store/editorSlice"; +import { CodeKeyType, selectConfig, setCodeKeyType } from "../../store/configSlice"; export const BOTTOM_BAR_HEIGHT = 25; @@ -12,7 +12,7 @@ interface EditorBottomBarProps { function EditorBottomBar(props: EditorBottomBarProps) { const { width } = props; const dispatch = useDispatch(); - const editorStore = useSelector(selectEditor); + const configStore = useSelector(selectConfig); const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); @@ -45,7 +45,7 @@ function EditorBottomBar(props: EditorBottomBarProps) { }} > { - dispatch(setTheme(themeMode == "light" ? "dark" : "light")); + dispatch(setTheme(themeMode == ThemeType.LIGHT ? ThemeType.DARK : ThemeType.LIGHT)); }; return ( diff --git a/frontend/src/store/configSlice.ts b/frontend/src/store/configSlice.ts index a7eca082..f4f40a09 100644 --- a/frontend/src/store/configSlice.ts +++ b/frontend/src/store/configSlice.ts @@ -2,20 +2,31 @@ import { createSlice } from "@reduxjs/toolkit"; import type { PayloadAction } from "@reduxjs/toolkit"; import { RootState } from "./store"; -type ThemeType = "default" | "dark" | "light"; +export enum ThemeType { + DEFAULT = "default", + DARK = "dark", + LIGHT = "light", +} + +export enum CodeKeyType { + SUBLIME = "sublime", + VIM = "vim", +} export interface ConfigState { theme: ThemeType; drawerOpen: boolean; + codeKey: CodeKeyType; } const initialState: ConfigState = { - theme: "default", + theme: ThemeType.DEFAULT, drawerOpen: true, + codeKey: CodeKeyType.SUBLIME, }; export const configSlice = createSlice({ - name: "editor", + name: "config", initialState, reducers: { setTheme: (state, action: PayloadAction) => { @@ -24,10 +35,13 @@ export const configSlice = createSlice({ setDrawerOpen: (state, action: PayloadAction) => { state.drawerOpen = action.payload; }, + setCodeKeyType: (state, action: PayloadAction) => { + state.codeKey = action.payload; + }, }, }); -export const { setTheme, setDrawerOpen } = configSlice.actions; +export const { setTheme, setDrawerOpen, setCodeKeyType } = configSlice.actions; export const selectConfig = (state: RootState) => state.config; diff --git a/frontend/src/store/editorSlice.ts b/frontend/src/store/editorSlice.ts index bff1f0a6..b4652f32 100644 --- a/frontend/src/store/editorSlice.ts +++ b/frontend/src/store/editorSlice.ts @@ -12,11 +12,6 @@ export enum EditorModeType { READ = "read", } -export enum CodeKeyType { - SUBLIME = "sublime", - VIM = "vim", -} - export type CodePairDocType = yorkie.Document< YorkieCodeMirrorDocType, YorkieCodeMirrorPresenceType @@ -24,7 +19,6 @@ export type CodePairDocType = yorkie.Document< export interface EditorState { mode: EditorModeType; - codeKey: CodeKeyType; shareRole: ShareRole | null; doc: CodePairDocType | null; client: yorkie.Client | null; @@ -33,7 +27,6 @@ export interface EditorState { const initialState: EditorState = { mode: EditorModeType.BOTH, - codeKey: CodeKeyType.SUBLIME, shareRole: null, doc: null, client: null, @@ -47,9 +40,6 @@ export const editorSlice = createSlice({ setMode: (state, action: PayloadAction) => { state.mode = action.payload; }, - setCodeKeyType: (state, action: PayloadAction) => { - state.codeKey = action.payload; - }, setShareRole: (state, action: PayloadAction) => { state.shareRole = action.payload; }, @@ -65,8 +55,7 @@ export const editorSlice = createSlice({ }, }); -export const { setMode, setCodeKeyType, setShareRole, setDoc, setClient, setCmView } = - editorSlice.actions; +export const { setMode, setShareRole, setDoc, setClient, setCmView } = editorSlice.actions; export const selectEditor = (state: RootState) => state.editor;