Add image viewer with zoom and pan controls#22
Conversation
|
@copilot this has poor mobile support, moving/dragging the big zoomed-in image around to see other parts of it only work on desktop but not when using a touchscreen |
Added touch event handlers for mobile support in commit 8cacaf7. The image viewer now supports:
The implementation mirrors the mouse drag functionality using |
There was a problem hiding this comment.
Pull request overview
This PR implements an image enlargement feature for PixelSocial, adding a modal image viewer with zoom and pan controls. The implementation follows WebXDC patterns and adds interactive image viewing capabilities similar to mainstream social media platforms.
Key Changes:
- New
ImageViewermodal component with zoom controls (0.5x-4x), mouse wheel zoom, and click-and-drag panning - Integration of the viewer into
PostImagecomponent with click-to-open functionality - Touch support for mobile devices with pan gestures
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/components/modals/ImageViewer.tsx | New modal component implementing image viewer with zoom/pan controls and mouse/touch event handlers |
| src/components/modals/ImageViewer.module.css | Styling for the image viewer modal with pixelart aesthetic (backdrop, controls, container layout) |
| src/components/PostImage.tsx | Added state management and click handler to open ImageViewer modal when image is clicked |
| <button className={styles.controlBtn} onClick={handleZoomOut}> | ||
| <PixelarticonsZoomOut /> | ||
| </button> | ||
| <button className={styles.controlBtn} onClick={handleReset}> | ||
| <PixelarticonsReload /> | ||
| </button> | ||
| <button className={styles.controlBtn} onClick={handleZoomIn}> | ||
| <PixelarticonsZoomIn /> | ||
| </button> | ||
| <button className={styles.controlBtn} onClick={onClose}> |
There was a problem hiding this comment.
The control buttons lack accessible labels. Screen readers will not be able to announce what each button does since the icon components don't provide text alternatives.
Add aria-label attributes to each button:
<button className={styles.controlBtn} onClick={handleZoomOut} aria-label="Zoom out">
<PixelarticonsZoomOut />
</button>
<button className={styles.controlBtn} onClick={handleReset} aria-label="Reset zoom">
<PixelarticonsReload />
</button>
<button className={styles.controlBtn} onClick={handleZoomIn} aria-label="Zoom in">
<PixelarticonsZoomIn />
</button>
<button className={styles.controlBtn} onClick={onClose} aria-label="Close image viewer">
<PixelarticonsClose />
</button>| <button className={styles.controlBtn} onClick={handleZoomOut}> | |
| <PixelarticonsZoomOut /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={handleReset}> | |
| <PixelarticonsReload /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={handleZoomIn}> | |
| <PixelarticonsZoomIn /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={onClose}> | |
| <button className={styles.controlBtn} onClick={handleZoomOut} aria-label="Zoom out"> | |
| <PixelarticonsZoomOut /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={handleReset} aria-label="Reset zoom"> | |
| <PixelarticonsReload /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={handleZoomIn} aria-label="Zoom in"> | |
| <PixelarticonsZoomIn /> | |
| </button> | |
| <button className={styles.controlBtn} onClick={onClose} aria-label="Close image viewer"> |
There was a problem hiding this comment.
yes, but we have _ function at i18n.ts and src/lib/langs/es.json, avoid using hardcoded text in english
| .controlBtn { | ||
| background-color: rgba(24, 24, 33, 0.9); | ||
| border: 1px solid #6364ff; | ||
| color: white; | ||
| padding: 0.5em; | ||
| cursor: pointer; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: 2.5em; | ||
| height: 2.5em; | ||
| } | ||
|
|
||
| .controlBtn:hover { | ||
| background-color: rgba(99, 100, 255, 0.2); | ||
| } | ||
|
|
||
| .controlBtn:active { | ||
| background-color: rgba(99, 100, 255, 0.4); | ||
| } |
There was a problem hiding this comment.
Hardcoded color values duplicate constants from src/constants.ts. These colors should be applied via inline styles in the TypeScript component using the imported constants, following the pattern used in other components like PrimaryButton.tsx and Modal.tsx.
The hardcoded values are:
- Line 30:
rgba(24, 24, 33, 0.9)should useBG_COLOR(#181821) - Line 31:
#6364ffshould useMAIN_COLOR - Line 43:
rgba(99, 100, 255, 0.2)should useMAIN_COLORorACCENT_COLORwith opacity - Line 47:
rgba(99, 100, 255, 0.4)should useMAIN_COLORorACCENT_COLORwith opacity
Consider moving these styles to inline styles in the component using the constants, or create CSS custom properties (CSS variables) that are set from the TypeScript constants.
8cacaf7 to
fee5cfb
Compare
|
@copilot but we have |
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
Updated in commit 255d4a4. All aria-labels and alt text now use the
|

Implement Image Enlargement Feature ✅
This PR adds the ability to enlarge images in posts by clicking on them, similar to typical social media image viewers.
Changes Made
Features
Screenshots
Normal post view with clickable image:

Image viewer opened (mobile view):

Desktop image viewer:

Mobile Support
The image viewer now fully supports touch interactions on mobile devices:
Internationalization
All user-facing text in the ImageViewer is now internationalized:
Security Summary
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.