Put the figure download over the picture, and let a figure be opened - #218
Merged
Merged
Conversation
The MVC chat sample moved its download onto the picture and gained click-to-enlarge in #215, but it did both inline in its own view. The shared chat UI every other surface renders with -- the chat page, the widget and the chat-interaction page -- kept the old shape: a button on a row of its own beneath the picture, and a thumbnail that could not be opened. A figure is capped to a fraction of the viewport so a stack of them does not push the conversation off screen, which makes every one of them a thumbnail; in the widget, 380px wide, more so. So the two things a reader wants are to see it larger and to keep a copy, and the second was costing a band of vertical space under every figure to offer. The download is now drawn over the picture's lower corner and revealed by pointing at the figure, on a pale ground of its own because it sits on whatever the drawing puts in that corner. focus-within keeps it reachable by keyboard, and a touch screen -- which has no hover to reveal it with -- simply always shows it. The link is otherwise untouched: same address, same download attribute, so the existing data-URI interception still names the saved file the way it did. Enlarging is wired to medium-zoom on the same deferred pass as the broken-image handler, because a picture arrives after the markdown is handed back and a streamed answer rewrites it on every chunk. The library is the host's to load: without it the picture is still shown and still downloadable, and only the enlarging is missing, so a host that has not registered it loses nothing it had. The opened copy is matched on its own class, since the library appends it to the body rather than inside the figure -- the widget stylesheet repeats that one rule unscoped for the same reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows #215, which moved the figure download onto the picture and added click-to-enlarge — but did both inline in the MVC chat sample's own view. The shared chat UI that every other surface renders with (
ai-chat.js,chat-interaction.js,ai-chat.css,chat-widget.css) kept the old shape: a button on a row of its own beneath the picture, and a thumbnail that could not be opened. This brings the same two behaviours to the package hosts actually consume.The download
Drawn over the picture's lower corner and revealed by pointing at the figure, instead of a block under it. A figure is capped to a fraction of the viewport so a stack of them does not push the conversation off screen — that cap is what makes every figure a thumbnail, and in the chat widget, 380px wide, more so. Offering the download on a row of its own cost a band of vertical space per figure.
The wrapping
<span class="mt-2 d-block">is gone and the<a>is now a direct child of the figure. Everything about the link itself is unchanged — same address, samedownloadattribute, same title, same classes — so the existing data-URI interception still names a saved file exactly the way it did.Details worth naming:
:focus-withinreveals it too. A control that is invisible until it takes focus, and cannot be brought into view, cannot be used at all.@media (hover: none)always shows it. A touch screen has no hover to reveal it with, and the widget is the surface most likely to be read on one.The enlarging
Wired to medium-zoom on the same deferred pass as the broken-image handler, because a picture arrives after the markdown is handed back — the view writes it, and a streamed answer rewrites it on every chunk — so it cannot be attached once at load.
data-zoom-wiredmarks a picture already attached so a re-render does not bind it twice.The library is the host's to load.
wireImageZoomreturns immediately whenmediumZoomis not a function, so a host that has not registered it sees exactly what it sees today: the picture shown, the download working, no enlarging. Nothing regresses for a host that does nothing.The opened picture is matched as
img.medium-zoom-image--openedrather than through the figure, because the library appends the copy to the document body — a descendant rule never reaches it. That copy carries the thumbnail's classes, so the frame and the viewport cap are taken off there, and only there, leaving the thumbnail in the conversation exactly as it was.chat-widget.cssrepeats that one rule unscoped for the same reason: a page that mounts only the widget loads only that file, and the copy lands outside the widget entirely.Scope
Deliberately not ported from #215: the SVG-to-PNG conversion on click and the filename derived from the alt text. Both are specific to the tabular previews that PR introduced, and both would change what every host's figures download as. The sample keeps them.
wwwroot/is the gulp output, rebuilt withnpm run build.npm run test:unitpasses (112 tests).🤖 Generated with Claude Code