feat: select visibility in editor (#421)

* feat: editing visibility selection

* update

* update

* update variable name

* update

Co-authored-by: boojack <stevenlgtm@gmail.com>
This commit is contained in:
Zeng1998 2022-11-10 21:43:49 +08:00 committed by GitHub
parent 8f119c4265
commit 421f4dbf60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 7 deletions

View File

@ -18,12 +18,13 @@ interface Props {
fullscreen: boolean;
tools?: ReactNode;
onPaste: (event: React.ClipboardEvent) => void;
onFocus: () => void;
onContentChange: (content: string) => void;
}
// eslint-disable-next-line react/display-name
const Editor = forwardRef((props: Props, ref: React.ForwardedRef<EditorRefActions>) => {
const { className, initialContent, placeholder, fullscreen, onPaste, onContentChange: handleContentChangeCallback } = props;
const { className, initialContent, placeholder, fullscreen, onPaste, onFocus, onContentChange: handleContentChangeCallback } = props;
const editorRef = useRef<HTMLTextAreaElement>(null);
const refresh = useRefresh();
@ -105,6 +106,7 @@ const Editor = forwardRef((props: Props, ref: React.ForwardedRef<EditorRefAction
ref={editorRef}
onPaste={onPaste}
onInput={handleEditorInput}
onFocus={onFocus}
></textarea>
</div>
);

View File

@ -2,14 +2,16 @@ import { IEmojiData } from "emoji-picker-react";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { deleteMemoResource, upsertMemoResource } from "../helpers/api";
import { TAB_SPACE_WIDTH, UNKNOWN_ID } from "../helpers/consts";
import { TAB_SPACE_WIDTH, UNKNOWN_ID, VISIBILITY_SELECTOR_ITEMS } from "../helpers/consts";
import { editorStateService, locationService, memoService, resourceService } from "../services";
import { useAppSelector } from "../store";
import * as storage from "../helpers/storage";
import Icon from "./Icon";
import toastHelper from "./Toast";
import Selector from "./common/Selector";
import Editor, { EditorRefActions } from "./Editor/Editor";
import EmojiPicker from "./Editor/EmojiPicker";
import { toLower } from "lodash";
import "../less/memo-editor.less";
const getEditorContentCache = (): string => {
@ -22,16 +24,24 @@ const setEditorContentCache = (content: string) => {
});
};
const setEditingMemoVisibilityCache = (visibility: Visibility) => {
storage.set({
editingMemoVisibilityCache: visibility,
});
};
interface State {
fullscreen: boolean;
isUploadingResource: boolean;
shouldShowEmojiPicker: boolean;
resourceList: Resource[];
hasFocused: boolean;
}
const MemoEditor: React.FC = () => {
const { t, i18n } = useTranslation();
const user = useAppSelector((state) => state.user.user);
const { setting } = useAppSelector((state) => state.user.user as User);
const editorState = useAppSelector((state) => state.editor);
const tags = useAppSelector((state) => state.memo.tags);
const [state, setState] = useState<State>({
@ -39,6 +49,7 @@ const MemoEditor: React.FC = () => {
fullscreen: false,
shouldShowEmojiPicker: false,
resourceList: [],
hasFocused: false,
});
const [allowSave, setAllowSave] = useState<boolean>(false);
const prevGlobalStateRef = useRef(editorState);
@ -48,10 +59,15 @@ const MemoEditor: React.FC = () => {
const mobileEditorStyle = user?.setting.mobileEditorStyle || "normal";
useEffect(() => {
const { editingMemoIdCache } = storage.get(["editingMemoIdCache"]);
const { editingMemoIdCache, editingMemoVisibilityCache } = storage.get(["editingMemoIdCache", "editingMemoVisibilityCache"]);
if (editingMemoIdCache) {
editorStateService.setEditMemoWithId(editingMemoIdCache);
}
if (editingMemoVisibilityCache) {
editorStateService.setMemoVisibility(editingMemoVisibilityCache as "PUBLIC" | "PROTECTED" | "PRIVATE");
} else {
editorStateService.setMemoVisibility(setting.memoVisibility);
}
}, []);
useEffect(() => {
@ -75,6 +91,7 @@ const MemoEditor: React.FC = () => {
...state,
resourceList: memo.resourceList,
});
editorStateService.setMemoVisibility(memo.visibility);
editorRef.current?.setContent(memo.content ?? "");
editorRef.current?.focus();
}
@ -196,6 +213,7 @@ const MemoEditor: React.FC = () => {
await memoService.patchMemo({
id: prevMemo.id,
content,
visibility: editorState.memoVisibility,
resourceIdList: state.resourceList.map((resource) => resource.id),
});
}
@ -203,6 +221,7 @@ const MemoEditor: React.FC = () => {
} else {
await memoService.createMemo({
content,
visibility: editorState.memoVisibility,
resourceIdList: state.resourceList.map((resource) => resource.id),
});
locationService.clearQuery();
@ -217,7 +236,9 @@ const MemoEditor: React.FC = () => {
fullscreen: false,
resourceList: [],
});
editorStateService.setMemoVisibility(setting.memoVisibility);
setEditorContentCache("");
storage.remove(["editingMemoVisibilityCache"]);
editorRef.current?.setContent("");
};
@ -229,6 +250,7 @@ const MemoEditor: React.FC = () => {
editorStateService.clearEditMemo();
editorRef.current?.setContent("");
setEditorContentCache("");
storage.remove(["editingMemoVisibilityCache"]);
};
const handleContentChange = (content: string) => {
@ -355,6 +377,26 @@ const MemoEditor: React.FC = () => {
[state.fullscreen, i18n.language, editorFontStyle]
);
const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
return {
value: item.value,
text: t(`memo.visibility.${toLower(item.value)}`),
};
});
const handleMemoVisibilityOptionChanged = async (value: string) => {
const visibilityValue = value as Visibility;
editorStateService.setMemoVisibility(visibilityValue);
setEditingMemoVisibilityCache(visibilityValue);
};
const handleEditorFocus = () => {
setState({
...state,
hasFocused: true,
});
};
return (
<div
className={`memo-editor-container ${mobileEditorStyle} ${isEditing ? "edit-ing" : ""} ${state.fullscreen ? "fullscreen" : ""}`}
@ -367,7 +409,19 @@ const MemoEditor: React.FC = () => {
{t("common.cancel")}
</button>
</div>
<Editor ref={editorRef} {...editorConfig} onPaste={handlePasteEvent} />
<Editor ref={editorRef} {...editorConfig} onPaste={handlePasteEvent} onFocus={handleEditorFocus} />
<div className={`visibility-selector-container ${state.hasFocused || allowSave ? "" : "!hidden"}`}>
<div className="memo-visibility-selector">
<label className="form-label selector">
<Selector
className="w-36"
value={editorState.memoVisibility}
dataSource={memoVisibilityOptionSelectorItems}
handleValueChanged={handleMemoVisibilityOptionChanged}
/>
</label>
</div>
</div>
<div className="common-tools-wrapper">
<div className="common-tools-container">
<div className="action-btn tag-action">

View File

@ -6,6 +6,8 @@ interface StorageData {
editorContentCache: string;
// Editing memo id cache
editingMemoIdCache: MemoId;
// Editing memo visibility
editingMemoVisibilityCache: Visibility;
// locale
locale: Locale;
// skipped version

View File

@ -62,12 +62,16 @@
}
}
> .visibility-selector-container{
@apply w-full border-b py-2;
}
> .memo-editor {
@apply flex flex-col justify-start items-start relative w-full h-auto bg-white;
}
> .common-tools-wrapper {
@apply relative w-full flex flex-row justify-between items-center;
@apply relative w-full flex flex-row justify-between items-center pt-2;
> .common-tools-container {
@apply flex flex-row justify-start items-center;

View File

@ -1,5 +1,5 @@
import store from "../store";
import { setEditMemoId, setMarkMemoId } from "../store/modules/editor";
import { setEditMemoId, setMarkMemoId, setMemoVisibility } from "../store/modules/editor";
const editorStateService = {
getState: () => {
@ -21,6 +21,10 @@ const editorStateService = {
clearMarkMemo: () => {
store.dispatch(setMarkMemoId());
},
setMemoVisibility: (memoVisibility: Visibility) => {
store.dispatch(setMemoVisibility(memoVisibility));
},
};
export default editorStateService;

View File

@ -3,6 +3,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
interface State {
markMemoId?: MemoId;
editMemoId?: MemoId;
memoVisibility: Visibility;
}
const editorSlice = createSlice({
@ -21,9 +22,15 @@ const editorSlice = createSlice({
editMemoId: action.payload,
};
},
setMemoVisibility: (state, action: PayloadAction<Visibility>) => {
return {
...state,
memoVisibility: action.payload,
};
},
},
});
export const { setEditMemoId, setMarkMemoId } = editorSlice.actions;
export const { setEditMemoId, setMarkMemoId, setMemoVisibility } = editorSlice.actions;
export default editorSlice.reducer;