feat: fullscreen editor

This commit is contained in:
boojack 2022-07-09 23:16:20 +08:00
parent a2b32e0b75
commit b85af714f5
6 changed files with 55 additions and 14 deletions

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M6.1 44 4 41.9 18.9 27H9v-3h15v15h-3v-9.9ZM24 24V9h3v9.9L41.9 4 44 6.1 29.1 21H39v3Z"/></svg>

After

Width:  |  Height:  |  Size: 165 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M6 42V27h3v9.9L36.9 9H27V6h15v15h-3v-9.9L11.1 39H21v3Z"/></svg>

After

Width:  |  Height:  |  Size: 135 B

View File

@ -15,6 +15,7 @@ interface EditorProps {
className: string; className: string;
initialContent: string; initialContent: string;
placeholder: string; placeholder: string;
fullscreen: boolean;
showConfirmBtn: boolean; showConfirmBtn: boolean;
showCancelBtn: boolean; showCancelBtn: boolean;
tools?: ReactNode; tools?: ReactNode;
@ -29,6 +30,7 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
className, className,
initialContent, initialContent,
placeholder, placeholder,
fullscreen,
showConfirmBtn, showConfirmBtn,
showCancelBtn, showCancelBtn,
onConfirmBtnClick: handleConfirmBtnClickCallback, onConfirmBtnClick: handleConfirmBtnClickCallback,
@ -45,11 +47,11 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
}, []); }, []);
useEffect(() => { useEffect(() => {
if (editorRef.current) { if (editorRef.current && !fullscreen) {
editorRef.current.style.height = "auto"; editorRef.current.style.height = "auto";
editorRef.current.style.height = (editorRef.current.scrollHeight ?? 0) + "px"; editorRef.current.style.height = (editorRef.current.scrollHeight ?? 0) + "px";
} }
}, [editorRef.current?.value]); }, [editorRef.current?.value, fullscreen]);
useImperativeHandle( useImperativeHandle(
ref, ref,

View File

@ -1,19 +1,26 @@
import React, { useCallback, useEffect, useMemo, useRef } from "react"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { UNKNOWN_ID } from "../helpers/consts"; import { UNKNOWN_ID } from "../helpers/consts";
import { editorStateService, locationService, memoService, resourceService } from "../services"; import { editorStateService, locationService, memoService, resourceService } from "../services";
import { useAppSelector } from "../store"; import { useAppSelector } from "../store";
import * as storage from "../helpers/storage"; import * as storage from "../helpers/storage";
import useToggle from "../hooks/useToggle";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
import Editor, { EditorRefActions } from "./Editor/Editor"; import Editor, { EditorRefActions } from "./Editor/Editor";
import "../less/memo-editor.less"; import "../less/memo-editor.less";
interface Props {} interface Props {}
interface State {
isUploadingResource: boolean;
fullscreen: boolean;
}
const MemoEditor: React.FC<Props> = () => { const MemoEditor: React.FC<Props> = () => {
const editorState = useAppSelector((state) => state.editor); const editorState = useAppSelector((state) => state.editor);
const tags = useAppSelector((state) => state.memo.tags); const tags = useAppSelector((state) => state.memo.tags);
const [isUploadingResource, setIsUploadingResource] = useToggle(false); const [state, setState] = useState<State>({
isUploadingResource: false,
fullscreen: false,
});
const editorRef = useRef<EditorRefActions>(null); const editorRef = useRef<EditorRefActions>(null);
const prevGlobalStateRef = useRef(editorState); const prevGlobalStateRef = useRef(editorState);
const tagSeletorRef = useRef<HTMLDivElement>(null); const tagSeletorRef = useRef<HTMLDivElement>(null);
@ -89,11 +96,14 @@ const MemoEditor: React.FC<Props> = () => {
const handleUploadFile = useCallback( const handleUploadFile = useCallback(
async (file: File) => { async (file: File) => {
if (isUploadingResource) { if (state.isUploadingResource) {
return; return;
} }
setIsUploadingResource(true); setState({
...state,
isUploadingResource: true,
});
const { type } = file; const { type } = file;
if (!type.startsWith("image")) { if (!type.startsWith("image")) {
@ -108,10 +118,13 @@ const MemoEditor: React.FC<Props> = () => {
} catch (error: any) { } catch (error: any) {
toastHelper.error(error); toastHelper.error(error);
} finally { } finally {
setIsUploadingResource(false); setState({
...state,
isUploadingResource: false,
});
} }
}, },
[isUploadingResource] [state]
); );
const handleSaveBtnClick = useCallback(async (content: string) => { const handleSaveBtnClick = useCallback(async (content: string) => {
@ -175,6 +188,13 @@ const MemoEditor: React.FC<Props> = () => {
inputEl.click(); inputEl.click();
}, []); }, []);
const handleFullscreenBtnClick = () => {
setState({
...state,
fullscreen: !state.fullscreen,
});
};
const handleTagSeletorClick = useCallback((event: React.MouseEvent) => { const handleTagSeletorClick = useCallback((event: React.MouseEvent) => {
if (tagSeletorRef.current !== event.target && tagSeletorRef.current?.contains(event.target as Node)) { if (tagSeletorRef.current !== event.target && tagSeletorRef.current?.contains(event.target as Node)) {
editorRef.current?.insertText(`#${(event.target as HTMLElement).textContent} ` ?? ""); editorRef.current?.insertText(`#${(event.target as HTMLElement).textContent} ` ?? "");
@ -189,17 +209,18 @@ const MemoEditor: React.FC<Props> = () => {
className: "memo-editor", className: "memo-editor",
initialContent: getEditorContentCache(), initialContent: getEditorContentCache(),
placeholder: "Any thoughts...", placeholder: "Any thoughts...",
fullscreen: state.fullscreen,
showConfirmBtn: true, showConfirmBtn: true,
showCancelBtn: isEditing, showCancelBtn: isEditing,
onConfirmBtnClick: handleSaveBtnClick, onConfirmBtnClick: handleSaveBtnClick,
onCancelBtnClick: handleCancelBtnClick, onCancelBtnClick: handleCancelBtnClick,
onContentChange: handleContentChange, onContentChange: handleContentChange,
}), }),
[isEditing] [isEditing, state.fullscreen]
); );
return ( return (
<div className={"memo-editor-container " + (isEditing ? "edit-ing" : "")}> <div className={`memo-editor-container ${isEditing ? "edit-ing" : ""} ${state.fullscreen ? "fullscreen" : ""}`}>
<p className={"tip-text " + (isEditing ? "" : "hidden")}>Editting...</p> <p className={"tip-text " + (isEditing ? "" : "hidden")}>Editting...</p>
<Editor <Editor
ref={editorRef} ref={editorRef}
@ -216,8 +237,11 @@ const MemoEditor: React.FC<Props> = () => {
</div> </div>
<div className="action-btn"> <div className="action-btn">
<img className="icon-img" src="/icons/image.svg" onClick={handleUploadFileBtnClick} /> <img className="icon-img" src="/icons/image.svg" onClick={handleUploadFileBtnClick} />
<span className={`tip-text ${isUploadingResource ? "!block" : ""}`}>Uploading</span> <span className={`tip-text ${state.isUploadingResource ? "!block" : ""}`}>Uploading</span>
</div> </div>
<button className="action-btn" onClick={handleFullscreenBtnClick}>
<img className="icon-img" src={`/icons/${state.fullscreen ? "close" : "open"}-fullscreen.svg`} alt="" />
</button>
</> </>
} }
/> />

View File

@ -1,7 +1,20 @@
@import "./mixin.less"; @import "./mixin.less";
.memo-editor-container { .memo-editor-container {
@apply relative w-full max-h-full flex flex-col justify-start items-start bg-white p-4 rounded-lg border-2 border-gray-200; @apply transition-all relative w-full max-h-full flex flex-col justify-start items-start bg-white p-4 rounded-lg border-2 border-gray-200;
&.fullscreen {
@apply fixed w-full h-full top-0 left-0 z-1000 border-none rounded-none sm:p-8;
background-color: #f6f5f4;
> .memo-editor {
@apply p-4 rounded-lg border shadow-lg flex flex-col flex-grow justify-start items-start relative w-full h-full bg-white;
> .common-editor-inputer {
@apply flex-grow w-full !h-full max-h-full;
}
}
}
&.edit-ing { &.edit-ing {
border-color: @text-blue; border-color: @text-blue;

View File

@ -1,7 +1,7 @@
@import "./mixin.less"; @import "./mixin.less";
.sidebar-wrapper { .sidebar-wrapper {
@apply fixed sm:sticky top-0 left-0 hidden sm:!flex flex-col justify-start items-start w-64 h-screen py-4 pl-2 z-10 bg-white sm:bg-transparent shadow-2xl sm:shadow-none overflow-x-hidden overflow-y-auto transition-all; @apply fixed sm:sticky top-0 left-0 hidden sm:!flex flex-col justify-start items-start w-64 h-screen py-4 pl-2 z-10 sm:z-0 bg-white sm:bg-transparent shadow-2xl sm:shadow-none overflow-x-hidden overflow-y-auto transition-all;
.hide-scroll-bar(); .hide-scroll-bar();
> .close-container { > .close-container {