From ad7e85bfaddfeba29f6858bbe0ea35d8e3af360e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 30 Jun 2022 11:14:24 +0500 Subject: [PATCH] feat: add tiptap in diffviewer --- apps/web/src/components/diff-viewer/diff.css | 14 -- apps/web/src/components/diff-viewer/differ.js | 50 ------ apps/web/src/components/diff-viewer/index.js | 146 ++++-------------- apps/web/src/components/editor/index.tsx | 117 +++++++++----- apps/web/src/components/editor/tiptap.tsx | 2 + apps/web/src/views/home.js | 4 +- 6 files changed, 112 insertions(+), 221 deletions(-) delete mode 100644 apps/web/src/components/diff-viewer/diff.css delete mode 100644 apps/web/src/components/diff-viewer/differ.js diff --git a/apps/web/src/components/diff-viewer/diff.css b/apps/web/src/components/diff-viewer/diff.css deleted file mode 100644 index 01b2d8734..000000000 --- a/apps/web/src/components/diff-viewer/diff.css +++ /dev/null @@ -1,14 +0,0 @@ -span.diff-del { - background-color: #fdb0c0; -} - -span.diff-ins { - background-color: #cafffb; -} - -.diffviewer img { - height: auto !important; - max-width: 100% !important; - background-color: var(--bgSecondary); - border-radius: 5px; -} diff --git a/apps/web/src/components/diff-viewer/differ.js b/apps/web/src/components/diff-viewer/differ.js deleted file mode 100644 index d5b300df3..000000000 --- a/apps/web/src/components/diff-viewer/differ.js +++ /dev/null @@ -1,50 +0,0 @@ -export default class HTMLDiffer { - constructor() { - this.isReady = false; - this.initializing = false; - this.promiseQueue = []; - } - - async _initialize() { - if (this.isReady) return; - this.initializing = true; - this.worker = new Worker("/diff.worker.js"); - this.isReady = true; - this.initializing = false; - } - - _communicate(type, data, transferables = [], init = true) { - return new Promise(async (resolve, reject) => { - if (init) await this._initialize(); - const messageId = Math.random().toString(36).substr(2, 9); - const onMessage = (e) => { - const { type: _type, messageId: _mId, data } = e.data; - if (_type === type && _mId === messageId) { - this.worker.removeEventListener("message", onMessage); - if (data.error) { - console.error(data.error); - return reject(data.error); - } - resolve(data); - } - }; - this.worker.addEventListener("message", onMessage); - this.worker.postMessage( - { - type, - data, - messageId, - }, - transferables - ); - }); - } - - generate = (before, after) => { - return this._communicate("generate", { before, after }); - }; - - clean = (html) => { - return this._communicate("clean", { html }); - }; -} diff --git a/apps/web/src/components/diff-viewer/index.js b/apps/web/src/components/diff-viewer/index.js index e5812289c..be8650b67 100644 --- a/apps/web/src/components/diff-viewer/index.js +++ b/apps/web/src/components/diff-viewer/index.js @@ -1,48 +1,20 @@ -import "./diff.css"; -import "../editor/plugins/attachmentshandler.css"; import { useState, useEffect, useCallback } from "react"; -import { Flex, Box, Text, Button } from "rebass"; +import { Flex, Text, Button } from "rebass"; import * as Icon from "../icons"; import ContentToggle from "./content-toggle"; import { store as notesStore } from "../../stores/note-store"; import { db } from "../../common/db"; import { useStore as useAppStore } from "../../stores/app-store"; -import { useStore as useThemeStore } from "../../stores/theme-store"; import { useStore as useEditorStore } from "../../stores/editor-store"; import { hashNavigate } from "../../navigation"; -import HTMLDiffer from "./differ"; import { showToast } from "../../utils/toast"; import { ScrollSync, ScrollSyncPane } from "react-scroll-sync"; -import { injectCssSrc, removeCss } from "../../utils/css"; -import { EV, EVENTS } from "notes-core/common"; - -const differ = new HTMLDiffer(); -var conflicts = undefined; -var currentConflict = undefined; - -function navigateConflicts(prev) { - if (!conflicts) - conflicts = [ - ...document.querySelectorAll("span.diff-ins"), - ...document.querySelectorAll("span.diff-del"), - ]; - let nextConflict; - if (currentConflict) { - const scrollTop = document.getElementById("diffViewAfter").scrollTop; - nextConflict = conflicts.find((conflict) => - prev ? conflict.offsetTop < scrollTop : conflict.offsetTop > scrollTop - ); - } else nextConflict = conflicts[0]; - if (!nextConflict) return false; - currentConflict = nextConflict; - currentConflict.scrollIntoView({ block: "center" }); -} +import { Editor } from "../editor"; function DiffViewer(props) { const { noteId } = props; const setIsEditorOpen = useAppStore((store) => store.setIsEditorOpen); - const theme = useThemeStore((store) => store.theme); const sync = useAppStore((store) => store.sync); const clearSession = useEditorStore((store) => store.clearSession); const [conflictedNote, setConflictedNote] = useState(); @@ -50,6 +22,7 @@ function DiffViewer(props) { const [localContent, setLocalContent] = useState(); const [isDownloadingImages, setIsDownloadingImages] = useState(false); const [htmlDiff, setHtmlDiff] = useState({}); + const [selectedContent, setSelectedContent] = useState(-1); const resolveConflict = useCallback( async ({ toKeep, toCopy, toKeepDateEdited, dateResolved }) => { @@ -125,39 +98,15 @@ function DiffViewer(props) { setLocalContent({ ...content, conflicted: false }); setRemoteContent(content.conflicted); - differ - .generate(content.data, content.conflicted.data) - .then(async ({ before, after }) => { - setHtmlDiff({ before, after }); - conflicts = undefined; - currentConflict = undefined; - }); - setHtmlDiff({ before: content.data, after: content.conflicted.data }); - - conflicts = undefined; - currentConflict = undefined; })(); }, [noteId, resolveConflict]); - useEffect(() => { - let cssPath = ""; - if (theme === "dark") - cssPath = "/skins/notesnook-dark/content.inline.min.css"; - else cssPath = "/skins/notesnook/content.inline.min.css"; - injectCssSrc("tmce", cssPath); - return () => { - removeCss("tmce"); - }; - }, [theme]); - useEffect(() => { clearSession(false); setIsEditorOpen(true); }, [setIsEditorOpen, clearSession]); - const [selectedContent, setSelectedContent] = useState(-1); - if (!conflictedNote || !localContent || !remoteContent) return null; return ( - - - + > + + - + + + diff --git a/apps/web/src/components/editor/index.tsx b/apps/web/src/components/editor/index.tsx index 6db6490b8..bfd67bbab 100644 --- a/apps/web/src/components/editor/index.tsx +++ b/apps/web/src/components/editor/index.tsx @@ -1,4 +1,10 @@ -import { useEffect, useCallback, useState, useRef } from "react"; +import { + useEffect, + useCallback, + useState, + useRef, + PropsWithChildren, +} from "react"; import { Box, Button, Flex, Text } from "rebass"; import Properties from "../properties"; import { useStore, store as editorstore } from "../../stores/editor-store"; @@ -132,8 +138,10 @@ export default function EditorManager({ nonce={timestamp} title={title} content={content} - readonly={isReadonly} - onRequestFocus={() => toggleProperties(false)} + options={{ + readonly: isReadonly, + onRequestFocus: () => toggleProperties(false), + }} /> {arePropertiesVisible && } @@ -141,18 +149,27 @@ export default function EditorManager({ ); } -type EditorProps = { - title: string; +type EditorOptions = { + headless?: boolean; readonly?: boolean; focusMode?: boolean; - nonce?: number; - content: string; onRequestFocus?: () => void; }; -function Editor(props: EditorProps) { - const { content, readonly, focusMode, onRequestFocus, title, nonce } = props; +type EditorProps = { + title?: string; + nonce?: number; + content: string; + options?: EditorOptions; +}; +export function Editor(props: EditorProps) { + const { content, nonce, options } = props; + const { readonly, headless } = options || { + headless: false, + readonly: false, + focusMode: false, + }; + const editor = useEditorInstance(); - const isMobile = useMobile(); useEffect(() => { if (!editor) return; @@ -190,6 +207,44 @@ function Editor(props: EditorProps) { }; }, [editor]); + return ( + + { + const { id, sessionId } = editorstore.get().session; + debouncedOnEditorChange(sessionId, id, sessionId, content); + if (counter) debouncedUpdateWordCount(counter); + }} + onDownloadAttachment={(attachment) => + downloadAttachment(attachment.hash) + } + onInsertAttachment={(type) => { + const mime = type === "file" ? "*/*" : "image/*"; + insertAttachment(mime).then((file) => { + if (!file) return; + editor?.attachFile(file); + }); + }} + /> + + ); +} + +function EditorChrome(props: PropsWithChildren) { + const { title, nonce, options, children } = props; + const { readonly, focusMode, headless, onRequestFocus } = options || { + headless: false, + readonly: false, + focusMode: false, + }; + const isMobile: boolean | null = useMobile(); + + if (headless) return <>{children}; + return ( <> @@ -223,37 +278,19 @@ function Editor(props: EditorProps) { }} /> )} - { - const { sessionId, id } = editorstore.get().session; - debouncedOnTitleChange(sessionId, id, title); - }} - title={title} - /> + {title !== undefined ? ( + { + const { sessionId, id } = editorstore.get().session; + debouncedOnTitleChange(sessionId, id, title); + }} + title={title} + /> + ) : null}
- { - const { id, sessionId } = editorstore.get().session; - debouncedOnEditorChange(sessionId, id, sessionId, content); - if (counter) debouncedUpdateWordCount(counter); - }} - onDownloadAttachment={(attachment) => - downloadAttachment(attachment.hash) - } - onInsertAttachment={(type) => { - const mime = type === "file" ? "*/*" : "image/*"; - insertAttachment(mime).then((file) => { - if (!file) return; - editor?.attachFile(file); - }); - }} - /> + {children} diff --git a/apps/web/src/components/editor/tiptap.tsx b/apps/web/src/components/editor/tiptap.tsx index 4ad00301d..cc3e3f39f 100644 --- a/apps/web/src/components/editor/tiptap.tsx +++ b/apps/web/src/components/editor/tiptap.tsx @@ -100,6 +100,8 @@ function TipTap(props: TipTapProps) { if (isSearching && !isEditorSearching) toggleSearch(); }, [toggleSearch, editor?.storage.searchreplace?.isSearching]); + if (!toolbarContainerId) return null; + return ( <> diff --git a/apps/web/src/views/home.js b/apps/web/src/views/home.js index 92717d1b5..54c9fbc36 100644 --- a/apps/web/src/views/home.js +++ b/apps/web/src/views/home.js @@ -24,10 +24,10 @@ function Home() { store.refresh(); setIsLoading(false); } - // const note = db.notes.note("f90f344ee3c13c2f686bd5c1").data; + // const note = db.notes.note("62bc3f28a1a1a10000707077").data; // const data = await db.content.raw(note.contentId); - // const note2 = db.notes.note("3e9a515cc63199a101ec49bb").data; + // const note2 = db.notes.note("62bc3f1ca1a1a10000707075").data; // const data2 = await db.content.raw(note2.contentId); // const data3 = { ...data, conflicted: data2 };