From e734292b28126aa2d9024f760f00ba5f28783e30 Mon Sep 17 00:00:00 2001 From: Jaleel Bennett Date: Wed, 18 Sep 2024 23:39:38 -0400 Subject: [PATCH] feat(article): storing content edit changes --- app/article/article-viewer.tsx | 10 ++- app/article/article.tsx | 2 + components/article-toolbar-options.tsx | 104 ++++++++++++++++--------- components/article-toolbar.tsx | 18 +++-- 4 files changed, 88 insertions(+), 46 deletions(-) diff --git a/app/article/article-viewer.tsx b/app/article/article-viewer.tsx index 735b571..99f930f 100644 --- a/app/article/article-viewer.tsx +++ b/app/article/article-viewer.tsx @@ -39,6 +39,7 @@ import { FloatingBubbleMenu } from "@/components/bubble-menu"; import TextAlign from "@tiptap/extension-text-align"; import Color from "@tiptap/extension-color"; import { cn } from "@/lib/utils"; // Make sure you have this utility function +import { useLocalStorage } from "@/hooks/use-local-storage"; function literalTemplate( strings: TemplateStringsArray, @@ -58,15 +59,22 @@ function forceReflow(element: HTMLElement) { export function ArticleViewer({ content, translatedContent, + readingHistoryId, }: { content: string; translatedContent: string | null; + readingHistoryId: number; }) { const zoom = useZoom(); const isEditable = useIsEditable(); const setEditor = useSetEditor(); - const staticHTMLContent = literalTemplate`${content}`; + const [editedContent] = useLocalStorage>( + "readiumx-edited-articles", + {}, + ); + + const staticHTMLContent = literalTemplate`${editedContent[readingHistoryId] || content}`; const editor = useEditor({ content: staticHTMLContent || translatedContent, diff --git a/app/article/article.tsx b/app/article/article.tsx index c5ca56a..9200b58 100644 --- a/app/article/article.tsx +++ b/app/article/article.tsx @@ -453,6 +453,7 @@ export function Article({ @@ -491,6 +492,7 @@ export function Article({ isTranslating={isTranslating} onSummarize={handleSummarize} isSummarizing={isSummarizing} + readingHistoryId={readingHistoryId} /> ); diff --git a/components/article-toolbar-options.tsx b/components/article-toolbar-options.tsx index d683c04..0e9294a 100644 --- a/components/article-toolbar-options.tsx +++ b/components/article-toolbar-options.tsx @@ -48,6 +48,7 @@ import { Eraser, } from "lucide-react"; import { toast } from "sonner"; +import { useLocalStorage } from "@/hooks/use-local-storage"; const languages = [ { value: "en", label: "English" }, @@ -233,65 +234,96 @@ const fontFamilies = [ { value: "Georgia", label: "Georgia" }, ]; -export function EditOption() { +export function EditOption({ readingHistoryId }: { readingHistoryId: number }) { const isEditable = useIsEditable(); const toggleEditable = useToggleEditable(); const editor = useEditor(); + const [editedContent, setEditedContent] = useLocalStorage< + Record + >("readiumx-edited-articles", {}); + useEffect(() => { - if (isEditable) { - toast.info("Editing mode enabled"); + if (isEditable && editor && editedContent[readingHistoryId]) { + editor.commands.setContent(editedContent[readingHistoryId]); + } + }, [isEditable, editor, editedContent, readingHistoryId]); + + const preserveScrollPosition = (callback: () => void) => { + if (editor) { + const scrollPosition = window.scrollY; + callback(); + window.scrollTo(0, scrollPosition); } - }, [isEditable]); + }; const handleToggleEditable = () => { const wasEditable = isEditable; toggleEditable(); if (wasEditable) { toast.info("Editing mode disabled."); + } else { + toast.info("Editing mode enabled"); } }; const setFontFamily = (font: string) => { - if (editor) { - editor.commands.selectAll(); - editor.chain().focus().setFontFamily(font).run(); - editor.commands.setTextSelection({ from: 0, to: 0 }); - } + preserveScrollPosition(() => { + if (editor) { + editor.chain().focus().selectAll().setFontFamily(font).run(); + } + }); }; const clearFormatting = () => { - if (editor) { - editor - .chain() - .focus() - .unsetAllMarks() - .unsetFontFamily() - .unsetTextAlign() - .setTextSelection(editor.state.doc.content.size) - .run(); + preserveScrollPosition(() => { + if (editor) { + editor + .chain() + .focus() + .selectAll() + .unsetAllMarks() + .unsetFontFamily() + .unsetTextAlign() + .setTextSelection(editor.state.doc.content.size) + .run(); - // Manually clear formatting for specific node types - editor.state.doc.descendants((node, pos) => { - if (node.type.name === "paragraph" || node.type.name === "heading") { - editor - .chain() - .focus() - .setNodeSelection(pos) - .unsetAllMarks() - .unsetFontFamily() - .unsetTextAlign() - .run(); - } - }); - } + // Manually clear formatting for specific node types + editor.state.doc.descendants((node, pos) => { + if (node.type.name === "paragraph" || node.type.name === "heading") { + editor + .chain() + .focus() + .setNodeSelection(pos) + .unsetAllMarks() + .unsetFontFamily() + .unsetTextAlign() + .run(); + } + }); + + // Get the updated content and store it in local storage + const updatedContent = editor.getHTML(); + setEditedContent((prev) => ({ + ...prev, + [readingHistoryId]: updatedContent, + })); + } + }); + toast.success("Formatting cleared and changes saved"); }; const saveChanges = () => { - if (editor) { - const content = editor.getHTML(); - console.log("Saving changes:", content); + const mainContentDiv = document.querySelector(".main-content"); + if (mainContentDiv) { + const content = mainContentDiv.outerHTML; + setEditedContent((prev) => ({ + ...prev, + [readingHistoryId]: content, + })); toast.success("Changes saved successfully"); + } else { + toast.error("Could not find content to save"); } }; @@ -331,11 +363,9 @@ export function EditOption() { variant="destructive" onClick={clearFormatting} > - Clear Formatting diff --git a/components/article-toolbar.tsx b/components/article-toolbar.tsx index 95c8d95..9a41c67 100644 --- a/components/article-toolbar.tsx +++ b/components/article-toolbar.tsx @@ -35,6 +35,7 @@ interface DynamicToolbarProps { isTranslating: boolean; onSummarize: () => Promise; isSummarizing: boolean; + readingHistoryId: number; } export function DynamicToolbar({ @@ -43,6 +44,7 @@ export function DynamicToolbar({ isTranslating, onSummarize, isSummarizing, + readingHistoryId, }: DynamicToolbarProps) { const [toolbarState, setToolbarState] = useState("initial"); const [selectedFeature, setSelectedFeature] = useState( @@ -75,13 +77,13 @@ export function DynamicToolbar({ { icon: , label: "Edit Article", - content: , - }, - { - icon: , - label: "Share", - content:

Sharing options will appear here.

, + content: , }, + // { + // icon: , + // label: "Share", + // content:

Sharing options will appear here.

, + // }, { icon: , label: "Magnify", @@ -114,7 +116,7 @@ export function DynamicToolbar({ }, }, intermediate: { - width: "270px", + width: "240px", height: "48px", borderRadius: "16px", transition: { @@ -124,7 +126,7 @@ export function DynamicToolbar({ }, }, final: { - width: "350px", + width: "320px", height: "270px", borderRadius: "16px", transition: {