Skip to content

fix(web): preserve share export layout fidelity - #1277

Merged
tiann merged 3 commits into
tiann:mainfrom
techotaku39:fix/share-export-layout-fidelity
Aug 1, 2026
Merged

fix(web): preserve share export layout fidelity#1277
tiann merged 3 commits into
tiann:mainfrom
techotaku39:fix/share-export-layout-fidelity

Conversation

@techotaku39

@techotaku39 techotaku39 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Improve share-image layout fidelity across desktop and mobile exports.

  • preserve the source conversation width for desktop exports while retaining the stable 960px / 2x mobile export path
  • keep the preview width bounded independently from the final export width
  • prevent mixed CJK and Latin text from using different canvas baselines during export
  • normalize inline-code glyph alignment and pill height without changing the browser or preview layout
  • preserve mixed landscape and portrait attachment aspect ratios in the preview and exported image
  • retain the existing interactive preview behavior for code wrapping, copying, and image zooming

Implementation

Desktop exports now capture the source message-container width and use it to calculate the export viewport, with reasonable minimum and maximum bounds.

Mobile exports continue to use the fixed 960px layout and 2x output for predictable high-resolution images.

Export-only normalization disables non-zero letter spacing because html2canvas-pro otherwise renders mixed CJK and Latin graphemes separately with different baselines.

Inline-code text is wrapped in the cloned export DOM so its glyph alignment can be adjusted without moving the original border or background. Its export-only line height is normalized to prevent both user and assistant inline-code pills from inheriting an oversized chat line box.

Multi-image previews now use a non-wrapping flex layout with proportional shrinking, preserving the natural aspect ratios of landscape and portrait attachments.

Testing

  • bun typecheck
  • bun run test:web
  • manually verified desktop and mobile exports against their source conversations
  • manually verified mixed CJK/Latin text and inline code in user and assistant messages
  • manually verified light and dark themes, mixed image attachments, long content, and mobile 2x output
  • Playwright coverage includes:
    • desktop, mobile, and mobile dark exports
    • source-width desktop and fixed-width mobile behavior, including landscape touch devices
    • mixed CJK/Latin text and inline code
    • mixed landscape and portrait attachments, including 3+ image wrapping
    • text-only user fallback
    • tool-content exclusion
    • localized actions
    • interactive code wrapping, copying, and image zoom
    • native share user activation

AI disclosure

Implementation and testing were assisted by OpenAI GPT-5.6 Codex.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Minor] Landscape phones are classified as desktop exports at 640px, so they no longer retain the fixed 960px / 2x mobile output. Evidence: web/src/components/AssistantChat/ShareTurnDialog.tsx:541.
  • [Minor] Every attachment set with 2+ images is forced into one non-wrapping row, making 3+ image exports progressively unreadable. Evidence: web/src/components/AssistantChat/ShareTurnDialog.tsx:739.

Summary
Review mode: initial

Two layout regressions found in the new responsive export behavior.

Testing
Not run locally (automation security constraint: PR code treated as untrusted). GitHub test check passed. Missing targeted coverage: 844×390 landscape-mobile export width and 3+/5-image attachment layout.

HAPI Bot

const preserveSourceLayout = Boolean(
props.sourceContentWidth
&& props.sourceContentWidth > 0
&& window.matchMedia('(min-width: 640px)').matches

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] Keep landscape phones on the fixed mobile export path

This treats every viewport at least 640px wide as desktop. HAPI's responsive config uses 920px specifically to stay clear of phone-landscape widths (web/tailwind.config.ts:7). On an 844×390 phone, the measured source width is below 960px, so this branch produces an export narrower than the promised fixed 1920px output; the new test covers only 390px portrait.

Suggested fix:

const preserveSourceLayout = Boolean(
    props.sourceContentWidth
    && props.sourceContentWidth > 0
    && window.matchMedia('(min-width: 920px)').matches
)

Also add an 844×390 case asserting a 1920px PNG width.

.hapi-share-preview-root .hapi-share-media-grid:not([data-hapi-image-count="1"]) > button > img {
width: 100% !important;
min-width: 0 !important;
flex-wrap: nowrap !important;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] Do not force every multi-image set into one row

:not([data-hapi-image-count="1"]) matches 2, 3, 4, ... images, and MessageAttachments has no image-count cap. With nowrap plus shrinking buttons, every additional image is squeezed into the same 720px preview/export row; 3+ attachments quickly become too small to read. The fixture exercises only two images.

Suggested fix:

.hapi-share-preview-root .hapi-share-media-grid[data-hapi-image-count="2"] {
    flex-wrap: nowrap !important;
}
.hapi-share-preview-root .hapi-share-media-grid:not([data-hapi-image-count="1"]):not([data-hapi-image-count="2"]) {
    flex-wrap: wrap !important;
}

Add a 3- or 5-image fixture that verifies wrapping and a usable minimum image width.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Minor] Touch-capable desktop devices lose source-width exports — navigator.maxTouchPoints > 0 is true on touchscreen laptops and convertibles even at desktop widths, so the new branch forces their export back to the fixed 960px layout instead of preserving the source conversation width. Evidence web/src/components/AssistantChat/ShareTurnDialog.tsx:538.
    Suggested fix:
    const preserveSourceLayout = Boolean(
        props.sourceContentWidth
        && props.sourceContentWidth > 0
        && window.matchMedia('(min-width: 920px)').matches
    )

Summary
Review mode: follow-up after new commits

One remaining device-classification regression. The previous landscape-phone and 3+ attachment findings are addressed by the new commits.

Testing
Not run (automation security constraint: PR code treated as untrusted). GitHub checks were pending during review. Missing targeted coverage: a wide desktop viewport with maxTouchPoints > 0.

HAPI Bot

naturalHeight: number
} | null>(null)
const showNativeShareButton = true
const isTouchDevice = navigator.maxTouchPoints > 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] Do not use touch capability as the mobile boundary

A wide Windows touchscreen laptop or convertible reports navigator.maxTouchPoints > 0, so isTouchDevice becomes true and exportWidth is forced to 960px even on a 1440px desktop viewport. That directly defeats this PR's source-width desktop export. The repo already uses 920px as the phone-landscape-safe split boundary (web/tailwind.config.ts:7).

Suggested fix:

const preserveSourceLayout = Boolean(
    props.sourceContentWidth
    && props.sourceContentWidth > 0
    && window.matchMedia('(min-width: 920px)').matches
)

Keep the 844×390 test and add a 1440px case with maxTouchPoints = 5 that still expects the 2240px source-width export.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • None.

Questions

  • None.

Summary
Review mode: follow-up after new commits

No high-confidence issues found in the latest full diff. The prior touch-capable desktop export regression is addressed. Residual risk: the visual-fidelity E2E coverage checks output dimensions and selected computed styles, but does not pixel-compare the exported PNG against the source layout.

Testing

  • Not run (automation security constraint: PR code treated as untrusted).
  • GitHub test and pr-review checks were pending at review time.

HAPI Bot

@tiann
tiann merged commit bbcef8c into tiann:main Aug 1, 2026
2 checks passed
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