From 34d2b48578532d387b1466c82ae4a761cd1d1a4f Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sun, 2 Nov 2025 20:13:57 +0000
Subject: feat: Add view options to show tag/title and control image fit. Fixes
 #1960

---
 .../bookmarks/BookmarkLayoutAdaptingCard.tsx       | 61 ++++++++++++++--------
 1 file changed, 40 insertions(+), 21 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 26c1c72b..b53a14c5 100644
--- a/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx
+++ b/apps/web/components/dashboard/bookmarks/BookmarkLayoutAdaptingCard.tsx
@@ -18,6 +18,7 @@ import { useTheme } from "next-themes";
 import type { ZBookmark } from "@karakeep/shared/types/bookmarks";
 import { BookmarkTypes } from "@karakeep/shared/types/bookmarks";
 import { isBookmarkStillTagging } from "@karakeep/shared/utils/bookmarkUtils";
+import { switchCase } from "@karakeep/shared/utils/switch";
 
 import BookmarkActionBar from "./BookmarkActionBar";
 import BookmarkFormattedCreatedAt from "./BookmarkFormattedCreatedAt";
@@ -117,7 +118,12 @@ function ListView({
   footer,
   className,
 }: Props) {
-  const { showNotes } = useBookmarkDisplaySettings();
+  const { showNotes, showTags, showTitle, imageFit } =
+    useBookmarkDisplaySettings();
+  const imgFitClass = switchCase(imageFit, {
+    cover: "object-cover",
+    contain: "object-contain",
+  });
   const note = showNotes ? bookmark.note?.trim() : undefined;
 
   return (
@@ -129,23 +135,25 @@ function ListView({
     >
       <MultiBookmarkSelector bookmark={bookmark} />
       <div className="flex size-32 items-center justify-center overflow-hidden">
-        {image("list", "object-cover rounded-lg size-32")}
+        {image("list", cn("size-32 rounded-lg", imgFitClass))}
       </div>
       <div className="flex h-full flex-1 flex-col justify-between gap-2 overflow-hidden">
         <div className="flex flex-col gap-2 overflow-hidden">
-          {title && (
+          {showTitle && title && (
             <div className="line-clamp-2 flex-none shrink-0 overflow-hidden text-ellipsis break-words text-lg">
               {title}
             </div>
           )}
           {content && <div className="shrink-1 overflow-hidden">{content}</div>}
           {note && <NotePreview note={note} bookmarkId={bookmark.id} />}
-          <div className="flex shrink-0 flex-wrap gap-1 overflow-hidden">
-            <TagList
-              bookmark={bookmark}
-              loading={isBookmarkStillTagging(bookmark)}
-            />
-          </div>
+          {showTags && (
+            <div className="flex shrink-0 flex-wrap gap-1 overflow-hidden">
+              <TagList
+                bookmark={bookmark}
+                loading={isBookmarkStillTagging(bookmark)}
+              />
+            </div>
+          )}
         </div>
         <BottomRow footer={footer} bookmark={bookmark} />
       </div>
@@ -164,9 +172,17 @@ function GridView({
   layout,
   fitHeight = false,
 }: Props & { layout: BookmarksLayoutTypes }) {
-  const { showNotes } = useBookmarkDisplaySettings();
+  const { showNotes, showTags, showTitle, imageFit } =
+    useBookmarkDisplaySettings();
+  const imgFitClass = switchCase(imageFit, {
+    cover: "object-cover",
+    contain: "object-contain",
+  });
   const note = showNotes ? bookmark.note?.trim() : undefined;
-  const img = image("grid", "h-52 min-h-52 w-full object-cover rounded-t-lg");
+  const img = image(
+    "grid",
+    cn("h-52 min-h-52 w-full rounded-t-lg", imgFitClass),
+  );
 
   return (
     <div
@@ -180,20 +196,22 @@ function GridView({
       {img && <div className="h-52 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">
-          {title && (
+          {showTitle && title && (
             <div className="line-clamp-2 flex-none shrink-0 overflow-hidden text-ellipsis break-words text-lg">
               {title}
             </div>
           )}
           {content && <div className="shrink-1 overflow-hidden">{content}</div>}
           {note && <NotePreview note={note} bookmarkId={bookmark.id} />}
-          <div className="flex shrink-0 flex-wrap gap-1 overflow-hidden">
-            <TagList
-              className={wrapTags ? undefined : "h-full"}
-              bookmark={bookmark}
-              loading={isBookmarkStillTagging(bookmark)}
-            />
-          </div>
+          {showTags && (
+            <div className="flex shrink-0 flex-wrap gap-1 overflow-hidden">
+              <TagList
+                className={wrapTags ? undefined : "h-full"}
+                bookmark={bookmark}
+                loading={isBookmarkStillTagging(bookmark)}
+              />
+            </div>
+          )}
         </div>
         <BottomRow footer={footer} bookmark={bookmark} />
       </div>
@@ -202,6 +220,7 @@ function GridView({
 }
 
 function CompactView({ bookmark, title, footer, className }: Props) {
+  const { showTitle } = useBookmarkDisplaySettings();
   return (
     <div
       className={cn(
@@ -230,11 +249,11 @@ function CompactView({ bookmark, title, footer, className }: Props) {
           {bookmark.content.type === BookmarkTypes.ASSET && (
             <ImageIcon className="size-5" />
           )}
-          {
+          {showTitle && (
             <div className="shrink-1 text-md line-clamp-1 overflow-hidden text-ellipsis break-words">
               {title ?? "Untitled"}
             </div>
-          }
+          )}
           {footer && (
             <p className="flex shrink-0 gap-2 text-gray-500">•{footer}</p>
           )}
-- 
cgit v1.2.3-70-g09d2

