From 40c5262a9c2fcb8c89d7c464ccfdc3016f933eb3 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Sat, 21 Dec 2024 14:09:30 +0100 Subject: [PATCH] feature: WYSIWYG markdown for notes. Fixes #701 (#715) * #701 Improve note support : WYSIWYG markdown First implementation with a wysiwyg markdown editor. Update: - Add Lexical markdown editor - consistent rendering between card and preview - removed edit modal, replaced by preview with save action - simple markdown shortcut: underline, bold, italic etc... * #701 Improve note support : WYSIWYG markdown improved performance to not rerender all note card when one is updated * Use markdown shortcuts * Remove the alignment actions * Drop history buttons * Fix code and highlighting buttons * Remove the unneeded update markdown plugin * Remove underline support as it's not markdown native * - added ListPlugin because if absent, there's a bug where you can't escape a list with enter + enter - added codeblock plugin - added prose dark:prose-invert prose-p:m-0 like you said (there's room for improvement I think, don't took the time too deep dive in) and removed theme - Added a switch to show raw markdown - Added back the react markdown for card (SSR) * delete theme.ts * add theme back for code element to be more like prism theme from markdown-readonly * move the new editor back to the edit menu * move the bookmark markdown component into dashboard/bookmark * move the tooltip into its own component * move save button to toolbar * Better raw markdown --------- Co-authored-by: Giuseppe Lapenta Co-authored-by: Mohamed Bassem --- .../bookmarks/BookmarkMarkdownComponent.tsx | 43 ++ .../bookmarks/BookmarkedTextEditor.tsx | 67 +-- .../dashboard/bookmarks/TextCard.tsx | 11 +- .../dashboard/preview/TextContentSection.tsx | 7 +- .../ui/markdown/markdown-editor.tsx | 124 +++++ .../markdown-readonly.tsx} | 118 ++--- .../ui/markdown/plugins/toolbar-plugin.tsx | 290 ++++++++++ apps/web/components/ui/markdown/theme.ts | 35 ++ apps/web/components/ui/switch.tsx | 28 + apps/web/lib/i18n/locales/de/translation.json | 15 +- apps/web/lib/i18n/locales/en/translation.json | 50 +- apps/web/lib/i18n/locales/fr/translation.json | 15 +- apps/web/package.json | 7 + pnpm-lock.yaml | 496 +++++++++++++++++- 14 files changed, 1177 insertions(+), 129 deletions(-) create mode 100644 apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx create mode 100644 apps/web/components/ui/markdown/markdown-editor.tsx rename apps/web/components/ui/{markdown-component.tsx => markdown/markdown-readonly.tsx} (92%) create mode 100644 apps/web/components/ui/markdown/plugins/toolbar-plugin.tsx create mode 100644 apps/web/components/ui/markdown/theme.ts create mode 100644 apps/web/components/ui/switch.tsx diff --git a/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx b/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx new file mode 100644 index 00000000..74eb0868 --- /dev/null +++ b/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx @@ -0,0 +1,43 @@ +import MarkdownEditor from "@/components/ui/markdown/markdown-editor"; +import { MarkdownReadonly } from "@/components/ui/markdown/markdown-readonly"; +import { toast } from "@/components/ui/use-toast"; + +import type { ZBookmarkTypeText } from "@hoarder/shared/types/bookmarks"; +import { useUpdateBookmarkText } from "@hoarder/shared-react/hooks/bookmarks"; + +export function BookmarkMarkdownComponent({ + children: bookmark, + readOnly = true, +}: { + children: ZBookmarkTypeText; + readOnly?: boolean; +}) { + const { mutate: updateBookmarkMutator, isPending } = useUpdateBookmarkText({ + onSuccess: () => { + toast({ + description: "Note updated!", + }); + }, + onError: () => { + toast({ description: "Something went wrong", variant: "destructive" }); + }, + }); + + const onSave = (text: string) => { + updateBookmarkMutator({ + bookmarkId: bookmark.id, + text, + }); + }; + return ( +
+ {readOnly ? ( + {bookmark.content.text} + ) : ( + + {bookmark.content.text} + + )} +
+ ); +} diff --git a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx index e0434943..b2c27c7e 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx @@ -1,20 +1,12 @@ -import { useState } from "react"; -import { ActionButton } from "@/components/ui/action-button"; -import { Button } from "@/components/ui/button"; +import { BookmarkMarkdownComponent } from "@/components/dashboard/bookmarks/BookmarkMarkdownComponent"; import { Dialog, - DialogClose, DialogContent, - DialogDescription, - DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { Textarea } from "@/components/ui/textarea"; -import { toast } from "@/components/ui/use-toast"; -import { useUpdateBookmarkText } from "@hoarder/shared-react/hooks/bookmarks"; -import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks"; +import { ZBookmark, ZBookmarkTypeText } from "@hoarder/shared/types/bookmarks"; export function BookmarkedTextEditor({ bookmark, @@ -26,55 +18,20 @@ export function BookmarkedTextEditor({ setOpen: (open: boolean) => void; }) { const isNewBookmark = bookmark === undefined; - const [noteText, setNoteText] = useState( - bookmark && bookmark.content.type == BookmarkTypes.TEXT - ? bookmark.content.text - : "", - ); - - const { mutate: updateBookmarkMutator, isPending } = useUpdateBookmarkText({ - onSuccess: () => { - toast({ - description: "Note updated!", - }); - setOpen(false); - }, - onError: () => { - toast({ description: "Something went wrong", variant: "destructive" }); - }, - }); - - const onSave = () => { - updateBookmarkMutator({ - bookmarkId: bookmark.id, - text: noteText, - }); - }; return ( - - - {isNewBookmark ? "New Note" : "Edit Note"} - - Write your note with markdown support - + + + + {isNewBookmark ? "New Note" : "Edit Note"} + -