Skip to content

feat(desktop): render links as rich previews - #3818

Open
tellaho wants to merge 35 commits into
mainfrom
tho/link-preview-rich-setting
Open

feat(desktop): render links as rich previews#3818
tellaho wants to merge 35 commits into
mainfrom
tho/link-preview-rich-setting

Conversation

@tellaho

@tellaho tellaho commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Category: new-feature
User Impact: Links render as informative previews with page context, safe imagery, and clear site identity without losing control of conversation density.

Problem: Plain links do not provide enough visual context, while a single preview treatment cannot serve both compact conversations and content-forward browsing. Preview identity, imagery, loading geometry, and author controls also need to remain consistent across message surfaces.

Solution: Render supported links as safe, metadata-rich previews and add an Appearance → Links preference with two presentations:

  • Compact (default): a conservative horizontal card with a responsive thumbnail, favicon, normalized hostname, title, and description.
  • Rich (optional): a content-forward unfurl with a left rail, larger OpenGraph image, and image visibility control.

The preference persists on the device and updates rendered previews immediately. The metadata pipeline safely discovers and sanitizes page imagery and favicons while enforcing SSRF, type, size, animation, and dimension limits. Preview data is preserved across message, inbox, feed, and forum surfaces, and authors can remove previews with concise confirmation copy.

File changes
  • Adds bounded metadata and media discovery with safe favicon and preview-image sanitization.
  • Carries resolved preview metadata through native events, message delivery, and forum messages.
  • Preserves preview attachments while formatting timelines and rendering message surfaces.
  • Adds dedicated Compact and Rich renderers and routes previews through the selected presentation.
  • Adds the persisted Appearance → Links preference, defaulting to Compact.
  • Adds deterministic unit and E2E coverage for metadata resolution, presentation switching, persistence, removal, and responsive layout.
  • Extracts native command input and preview helpers to satisfy lint and file-size boundaries without suppressions.

Reproduction Steps

  1. Open the desktop composer and share each real URL below:
  2. Confirm each resolves to a Compact horizontal preview by default, including normalized hostname, title/description, favicon, and a thumbnail when available.
  3. Open Settings → Appearance and change Links from Compact to Rich.
  4. Return to the channel and confirm the previews update to the larger content-forward presentation.
  5. Reload the app and confirm Rich remains selected, then switch back to Compact.
  6. Confirm the same preview data is retained across timeline, inbox, feed, and forum surfaces.

Validation

  • Pre-push desktop check and test passed.
  • Pre-push Rust tests and desktop Tauri checks passed.
  • The unrelated mobile-test baseline failure was excluded with explicit authorization after reproducing it at origin/main.

Screenshots / Demos

Placeholder: Refresh with latest Compact and Rich captures using the three real URLs in the reproduction steps before merge.

Setting — Appearance → Links

Appearance Links setting with Compact and Rich options

Compact (default) vs Rich (optional)

Compact and Rich link preview presentations

Supersedes #3770 by combining the complete metadata pipeline, Compact default, and optional Rich presentation into one reviewable change.

@tellaho
tellaho force-pushed the tho/link-preview-rich-setting branch 2 times, most recently from 76a5892 to 85ef69d Compare July 30, 2026 23:22
@tellaho
tellaho marked this pull request as ready for review July 30, 2026 23:37
@tellaho
tellaho requested a review from a team as a code owner July 30, 2026 23:37
@tellaho
tellaho force-pushed the tho/link-preview-images branch from 502f8fd to 3990447 Compare July 31, 2026 00:14
npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w and others added 24 commits July 30, 2026 23:20
Co-authored-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Signed-off-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Co-authored-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Signed-off-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Signed-off-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Co-authored-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Signed-off-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Co-authored-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
Signed-off-by: npub14vtk7pvazqrq9639qu7e560wnqtl0d53ca4gjuvq6jzf3k2el23qqlwa7f <ab176f059d100602ea25073d9a69ee9817f7b691c76a897180d48498d959faa2@buzz.block.builderlab.xyz>
…eview 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 <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
…cards

- Remove the "Automatic preview from {domain}" gradient overlay on preview
  images; simplify the img alt text to "Preview from {domain}"
- Drop the "· {typeLabel}" suffix (PR/issue/repo/file/link/etc.) from the
  card metadata row — the provider name and logo already convey the source,
  so the row now shows just the provider
- typeLabel stays in the SupportedLinkPreview model since it still powers
  the accessible aria-label ("Open GitHub PR: ...")

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tellaho added 9 commits July 30, 2026 23:21
- Replace separate description and image controls with one Show more/Show less toggle that collapses both elements.
- Expand rich preview text to the full available metadata and widen preview containers for readable 280-character tweets.
- Add vertical padding beside the accent border and cap preview images at 300px while preserving responsive sizing.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Update rich preview cards with wider layouts, compact image sizing, and unified content expansion controls
- Allow link titles to span two lines and preserve full expanded descriptions
- Raise fetched description metadata to the standard 280-character X post limit
- Preserve encoded description line breaks while normalizing intra-line whitespace
- Add metadata tests covering line breaks and description length limits

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Render OG description line breaks instead of collapsing them into spaces
- Group blank-line-separated paragraphs with compact spacing to avoid oversized gaps
- Reuse the rich preview image component for consistent skeleton and lightbox behavior across link types

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Route rich link preview images through the markdown gallery lightbox so preview images support consistent zoom transitions and gallery navigation.
- Extract link preview lightbox behavior and focusable-element discovery into focused markdown modules to keep the main renderer within its size limit.
- Infer image dimensions from loaded thumbnails when explicit lightbox metadata is unavailable.
- Pass the shared lightbox component through the link preview list and attachment layers.
- Render compact preview cards inline with wrapping and place the remove action on the final compact card.
- Preserve rich preview stacking and existing remove behavior for rich layouts.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Add a hover-only vertical ellipsis beside the first compact or rich preview.
- Provide a Link display submenu for switching the global Rich or Compact appearance preference.
- Show an actionable confirmation-backed Remove preview option for message authors while keeping display controls available to everyone.
- Link preference-change toasts to Appearance settings and expand rich preview images to match uploaded image width.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Remove compact card borders and background surfaces while preserving transparent hover behavior.
- Round thumbnail images on every corner and expand cards to the 24rem image-upload width.
- Shorten the preview settings submenu label from Link display to Display.
- Update compact preview geometry coverage for the wider borderless layout and await screenshot animations.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Expand compact preview thumbnails to an 88px height with slightly wider responsive dimensions.
- Reduce the thumbnail-to-content inset so preview text sits closer to its image.
- Allow compact titles to wrap across two lines for better readability.
- De-emphasize hostnames and descriptions with a softer secondary foreground color.
- Update desktop geometry coverage for the revised dimensions, spacing, and title treatment.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Remove legacy provider-specific compact preview logos and layouts in favor of hostname-driven metadata.
- Present imageless compact previews with the same 84px height, description support, and left-rule treatment as image-backed cards.
- Preserve fetched favicons and make favicon/hostname identity rows link directly to their source URL.
- Align rich and compact hostname and description colors on the same secondary foreground treatment.
- Expand messaging E2E coverage for equal-height cards, generic favicons, linked hostnames, and imageless descriptions.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
- Underline compact preview hostnames and titles together whenever the card is hovered.
- Remove independent hostname hover styling so the interaction consistently represents the full destination URL.
- Restore stronger description colors for standard rich previews and tweet content while keeping hostnames secondary.
- Add E2E coverage confirming both compact identity elements receive the shared hover affordance.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho force-pushed the tho/link-preview-rich-setting branch from 85ef69d to a2ffdf8 Compare July 31, 2026 06:42
@tellaho tellaho changed the title feat(desktop): add rich link preview preference feat(desktop): render links as rich previews Jul 31, 2026
@tellaho
tellaho changed the base branch from tho/link-preview-images to main July 31, 2026 06:43
@Chessing234

Copy link
Copy Markdown
Contributor

rich previews are nice. make sure they stay opt-in or gated for private/untrusted hosts so we dont fetch surprise content

npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w and others added 2 commits July 31, 2026 09:24
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
…-setting

* origin/main:
  feat(desktop): import local Pocket voices (#3259)
  fix(desktop): open profiles from avatars (#3751)
  refactor(voice): extract reusable Pocket primitives + Pocket voice settings (relands #2467 + #3208) (#3910)
  docs: add VISION_REMOTE_AGENTS.md (#3924)
  feat(desktop): auto-enable huddle transcription for agents (#3180)
  feat(agent): optional reply guard reminds a silent turn to publish (#3763)
  feat(desktop): upgrade Pocket TTS model (#3266)

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants