From d193d9bf89e8a88bf70b673ea5e438d73cf40c0c Mon Sep 17 00:00:00 2001
From: Md Saban <45597394+mdsaban@users.noreply.github.com>
Date: Tue, 2 Jul 2024 03:51:23 +0530
Subject: feat: Add bulk edit option for bookmarks. Fixes #84 (#259)

* feat: add bulk edit option for bookmarks

* fix: resolve comments

* fix: resolve comments

* fix: resolve comments

* fix: resolve comments

* rename bulk action store, simplify the bulk action toolbar

---------

Co-authored-by: MohamedBassem <me@mbassem.com>
---
 .../bookmarks/BookmarkLayoutAdaptingCard.tsx       | 62 ++++++++++++++++++++--
 1 file changed, 59 insertions(+), 3 deletions(-)

(limited to 'apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx')

diff --git a/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx b/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx
index e1cc1f7c..33b65108 100644
--- a/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx
+++ b/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx
@@ -1,12 +1,15 @@
 import type { BookmarksLayoutTypes } from "@/lib/userLocalSettings/types";
-import React from "react";
+import React, { useEffect, useState } from "react";
 import Link from "next/link";
+import useBulkActionsStore from "@/lib/bulkActions";
 import {
   bookmarkLayoutSwitch,
   useBookmarkLayout,
 } from "@/lib/userLocalSettings/bookmarksLayout";
 import { cn } from "@/lib/utils";
 import dayjs from "dayjs";
+import { Check } from "lucide-react";
+import { useTheme } from "next-themes";
 
 import type { ZBookmark } from "@hoarder/shared/types/bookmarks";
 import { isBookmarkStillTagging } from "@hoarder/shared-react/utils/bookmarkUtils";
@@ -45,6 +48,57 @@ function BottomRow({
   );
 }
 
+function MultiBookmarkSelector({ bookmark }: { bookmark: ZBookmark }) {
+  const { selectedBookmarks, isBulkEditEnabled } = useBulkActionsStore();
+  const toggleBookmark = useBulkActionsStore((state) => state.toggleBookmark);
+  const [isSelected, setIsSelected] = useState(false);
+  const { theme } = useTheme();
+
+  useEffect(() => {
+    setIsSelected(selectedBookmarks.some((item) => item.id === bookmark.id));
+  }, [selectedBookmarks]);
+
+  if (!isBulkEditEnabled) return null;
+
+  const getIconColor = () => {
+    if (theme === "dark") {
+      return isSelected ? "black" : "white";
+    }
+    return isSelected ? "white" : "black";
+  };
+
+  const getIconBackgroundColor = () => {
+    if (theme === "dark") {
+      return isSelected ? "bg-white" : "bg-white bg-opacity-10";
+    }
+    return isSelected ? "bg-black" : "bg-white bg-opacity-40";
+  };
+
+  return (
+    <button
+      className={cn(
+        "absolute left-0 top-0 z-50 h-full w-full bg-opacity-0",
+        {
+          "bg-opacity-10": isSelected,
+        },
+        theme === "dark" ? "bg-white" : "bg-black",
+      )}
+      onClick={() => toggleBookmark(bookmark)}
+    >
+      <button className="absolute right-2 top-2 z-50 opacity-100">
+        <div
+          className={cn(
+            "flex h-4 w-4 items-center justify-center rounded-full border border-gray-600",
+            getIconBackgroundColor(),
+          )}
+        >
+          <Check size={12} color={getIconColor()} />
+        </div>
+      </button>
+    </button>
+  );
+}
+
 function ListView({
   bookmark,
   image,
@@ -56,10 +110,11 @@ function ListView({
   return (
     <div
       className={cn(
-        "flex max-h-96 gap-4 overflow-hidden rounded-lg p-2 shadow-md",
+        "relative flex max-h-96 gap-4 overflow-hidden rounded-lg p-2 shadow-md",
         className,
       )}
     >
+      <MultiBookmarkSelector bookmark={bookmark} />
       <div className="flex size-32 items-center justify-center overflow-hidden">
         {image("list", "object-cover rounded-lg size-32")}
       </div>
@@ -100,11 +155,12 @@ function GridView({
   return (
     <div
       className={cn(
-        "flex flex-col overflow-hidden rounded-lg shadow-md",
+        "relative flex flex-col overflow-hidden rounded-lg shadow-md",
         className,
         fitHeight && layout != "grid" ? "max-h-96" : "h-96",
       )}
     >
+      <MultiBookmarkSelector bookmark={bookmark} />
       {img && <div className="h-56 w-full shrink-0 overflow-hidden">{img}</div>}
       <div className="flex h-full flex-col justify-between gap-2 overflow-hidden p-2">
         <div className="grow-1 flex flex-col gap-2 overflow-hidden">
-- 
cgit v1.2.3-70-g09d2

