From 7e9240409d01814f7366c16ec416873a788d4561 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Tue, 28 Jul 2026 08:17:31 -0700 Subject: [PATCH] feat(previews): replace remove-previews text link with inline X on preview card - link-preview-attachment.tsx: add optional onRemove prop that renders a small X button floating just outside the card's top-right corner (left-full top-0, z-20 above the link trigger), fading in on message row hover via group-hover/message and reachable by keyboard via focus-visible - link-preview-attachment.tsx: wrap the card in a relative container carrying the width classes (w-80 max-w-full shrink-0) since the card's overflow-hidden would clip a button positioned outside its bounds - link-preview-attachment.tsx: remove the AttachmentActions block with the hover-revealed ExternalLink icon, eliminating the reserved flex gap on card hover - markdown.tsx: drop the "Remove previews for everyone" text button below the preview list and its spacing wrapper; pass onRemove to each LinkPreviewAttachment instead, opening the same confirmation dialog - removal flow and AlertDialog confirmation are unchanged; X only renders when onRemoveLinkPreviewsForEveryone is available (own messages) Co-authored-by: Taylor Ho Signed-off-by: Taylor Ho --- .../src/shared/ui/link-preview-attachment.tsx | 109 +++++++++--------- desktop/src/shared/ui/markdown.tsx | 55 ++++----- 2 files changed, 86 insertions(+), 78 deletions(-) diff --git a/desktop/src/shared/ui/link-preview-attachment.tsx b/desktop/src/shared/ui/link-preview-attachment.tsx index cc01eee95..8c81da33b 100644 --- a/desktop/src/shared/ui/link-preview-attachment.tsx +++ b/desktop/src/shared/ui/link-preview-attachment.tsx @@ -1,10 +1,9 @@ -import { ExternalLink, Globe } from "lucide-react"; +import { Globe, X } from "lucide-react"; import type { SupportedLinkPreview } from "@/shared/lib/linkPreview"; import { cn } from "@/shared/lib/cn"; import { Attachment, - AttachmentActions, AttachmentContent, AttachmentMedia, AttachmentTitle, @@ -113,65 +112,71 @@ function LinkPreviewLogo({ preview }: { preview: SupportedLinkPreview }) { export function LinkPreviewAttachment({ className, + onRemove, preview, }: { className?: string; + onRemove?: () => void; preview: SupportedLinkPreview; }) { const showImage = Boolean(preview.imageDataUrl && preview.imageDomain); return ( - - {showImage ? ( -
- {`Automatic -
- Automatic preview from {preview.imageDomain} +
+ + {showImage ? ( +
+ {`Automatic +
+ Automatic preview from {preview.imageDomain} +
-
- ) : null} - {!showImage ? ( - - - - ) : null} - -
- {preview.provider} - - {preview.typeLabel} -
- {preview.title} -
- - - - + + + ) : null} + +
+ {preview.provider} + + {preview.typeLabel} +
+ {preview.title} +
+ +
+ + Open {preview.provider} {preview.typeLabel}: {preview.title} + + +
+ + {onRemove ? ( + + ) : null} +
); } diff --git a/desktop/src/shared/ui/markdown.tsx b/desktop/src/shared/ui/markdown.tsx index a3135043a..dc4ce00fd 100644 --- a/desktop/src/shared/ui/markdown.tsx +++ b/desktop/src/shared/ui/markdown.tsx @@ -1946,6 +1946,8 @@ function MarkdownInner({ } const resolvedLinkPreviews = useResolvedLinkPreviews(linkPreviews); + const previewNoun = + resolvedLinkPreviews.length === 1 ? "preview" : "previews"; // When a config-nudge suppresses the prose (selectProseOrNudge returns // null), skip the parse entirely — it would be thrown away unrendered. @@ -1996,27 +1998,22 @@ function MarkdownInner({ ) : null} {resolvedLinkPreviews.length > 0 ? ( -
- - {resolvedLinkPreviews.map((preview) => ( - - ))} - - {onRemoveLinkPreviewsForEveryone ? ( -
- -
- ) : null} -
+ + {resolvedLinkPreviews.map((preview) => ( + setRemovePreviewDialogOpen(true) + : undefined + } + preview={preview} + /> + ))} + ) : null} {onRemoveLinkPreviewsForEveryone ? ( - Remove previews for everyone? + Remove {previewNoun} for everyone? - This permanently removes all generated link previews from - this message for supporting clients. The links stay in the - message. This can't be undone. + No one will see{" "} + {resolvedLinkPreviews.length === 1 + ? "the preview" + : "the previews"}{" "} + on this message anymore.{" "} + {resolvedLinkPreviews.length === 1 + ? "The link itself will stay" + : "The links themselves will stay"}{" "} + in the message. This can't be undone. @@ -2051,7 +2054,7 @@ function MarkdownInner({ type="button" variant="destructive" > - Remove previews + Remove {previewNoun}