From 86d74e3f32dd5bccc8df195b55391e206df9a1c4 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Fri, 27 Dec 2024 16:09:29 +0000
Subject: feat: Implement highlights support for links. Fixes #620

---
 .../dashboard/preview/LinkContentSection.tsx       | 94 ++++++++++++++++++++--
 1 file changed, 88 insertions(+), 6 deletions(-)

(limited to 'apps/web/components/dashboard/preview/LinkContentSection.tsx')

diff --git a/apps/web/components/dashboard/preview/LinkContentSection.tsx b/apps/web/components/dashboard/preview/LinkContentSection.tsx
index 320fc561..f09cc31f 100644
--- a/apps/web/components/dashboard/preview/LinkContentSection.tsx
+++ b/apps/web/components/dashboard/preview/LinkContentSection.tsx
@@ -1,5 +1,6 @@
 import { useState } from "react";
 import Image from "next/image";
+import BookmarkHTMLHighlighter from "@/components/dashboard/preview/BookmarkHtmlHighlighter";
 import {
   Select,
   SelectContent,
@@ -8,9 +9,16 @@ import {
   SelectTrigger,
   SelectValue,
 } from "@/components/ui/select";
+import { toast } from "@/components/ui/use-toast";
 import { useTranslation } from "@/lib/i18n/client";
+import { api } from "@/lib/trpc";
 import { ScrollArea } from "@radix-ui/react-scroll-area";
 
+import {
+  useCreateHighlight,
+  useDeleteHighlight,
+  useUpdateHighlight,
+} from "@hoarder/shared-react/hooks/highlights";
 import {
   BookmarkTypes,
   ZBookmark,
@@ -42,7 +50,59 @@ function ScreenshotSection({ link }: { link: ZBookmarkedLink }) {
   );
 }
 
-function CachedContentSection({ link }: { link: ZBookmarkedLink }) {
+function CachedContentSection({
+  bookmarkId,
+  link,
+}: {
+  bookmarkId: string;
+  link: ZBookmarkedLink;
+}) {
+  const { data } = api.highlights.getForBookmark.useQuery({
+    bookmarkId,
+  });
+
+  const { mutate: createHighlight } = useCreateHighlight({
+    onSuccess: () => {
+      toast({
+        description: "Highlight has been created!",
+      });
+    },
+    onError: () => {
+      toast({
+        variant: "destructive",
+        description: "Something went wrong",
+      });
+    },
+  });
+
+  const { mutate: updateHighlight } = useUpdateHighlight({
+    onSuccess: () => {
+      toast({
+        description: "Highlight has been updated!",
+      });
+    },
+    onError: () => {
+      toast({
+        variant: "destructive",
+        description: "Something went wrong",
+      });
+    },
+  });
+
+  const { mutate: deleteHighlight } = useDeleteHighlight({
+    onSuccess: () => {
+      toast({
+        description: "Highlight has been deleted!",
+      });
+    },
+    onError: () => {
+      toast({
+        variant: "destructive",
+        description: "Something went wrong",
+      });
+    },
+  });
+
   let content;
   if (!link.htmlContent) {
     content = (
@@ -50,11 +110,31 @@ function CachedContentSection({ link }: { link: ZBookmarkedLink }) {
     );
   } else {
     content = (
-      <div
-        dangerouslySetInnerHTML={{
-          __html: link.htmlContent || "",
-        }}
+      <BookmarkHTMLHighlighter
+        htmlContent={link.htmlContent || ""}
         className="prose mx-auto dark:prose-invert"
+        highlights={data?.highlights ?? []}
+        onDeleteHighlight={(h) =>
+          deleteHighlight({
+            highlightId: h.id,
+          })
+        }
+        onUpdateHighlight={(h) =>
+          updateHighlight({
+            highlightId: h.id,
+            color: h.color,
+          })
+        }
+        onHighlight={(h) =>
+          createHighlight({
+            startOffset: h.startOffset,
+            endOffset: h.endOffset,
+            color: h.color,
+            bookmarkId,
+            text: h.text,
+            note: null,
+          })
+        }
       />
     );
   }
@@ -89,7 +169,9 @@ export default function LinkContentSection({
 
   let content;
   if (section === "cached") {
-    content = <CachedContentSection link={bookmark.content} />;
+    content = (
+      <CachedContentSection bookmarkId={bookmark.id} link={bookmark.content} />
+    );
   } else if (section === "archive") {
     content = <FullPageArchiveSection link={bookmark.content} />;
   } else if (section === "video") {
-- 
cgit v1.3-1-g0d28

