Skip to content

Commit 8e67dba

Browse files
authored
Merge pull request #264 from piko-piko/urlpreview-middleclick
Middle click to open the url preview card thumbnail in a new tab
2 parents 28073b5 + 02aa299 commit 8e67dba

2 files changed

Lines changed: 32 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
default: patch
3+
---
4+
5+
Handles a middle-click on the url preview card thumbnail image by downloading the full image from the homeserver proxy through a fetch request and opening received blob in the new tab

src/app/components/url-preview/UrlPreviewCard.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
getIntersectionObserverEntry,
88
useIntersectionObserver,
99
} from '$hooks/useIntersectionObserver';
10-
import { mxcUrlToHttp } from '$utils/matrix';
10+
import { mxcUrlToHttp, downloadMedia } from '$utils/matrix';
1111
import { useMediaAuthentication } from '$hooks/useMediaAuthentication';
1212
import * as css from './UrlPreviewCard.css';
1313
import { UrlPreview, UrlPreviewContent, UrlPreviewDescription } from './UrlPreview';
@@ -17,6 +17,16 @@ import { ImageViewer } from '../image-viewer';
1717

1818
const linkStyles = { color: color.Success.Main };
1919

20+
const openMediaInNewTab = async (url: string | undefined) => {
21+
if (!url) {
22+
console.warn('Attempted to open an empty url');
23+
return;
24+
}
25+
const blob = await downloadMedia(url);
26+
const blobUrl = URL.createObjectURL(blob);
27+
window.open(blobUrl, '_blank');
28+
};
29+
2030
export const UrlPreviewCard = as<'div', { url: string; ts: number; mediaType?: string | null }>(
2131
({ url, ts, mediaType, ...props }, ref) => {
2232
const mx = useMatrixClient();
@@ -50,6 +60,21 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number; mediaType?: s
5060
'scale',
5161
false
5262
);
63+
const handleAuxClick = (ev: React.MouseEvent) => {
64+
if (!prev['og:image']) {
65+
console.warn('No image');
66+
return;
67+
}
68+
if (ev.button === 1) {
69+
ev.preventDefault();
70+
const mxcUrl = mxcUrlToHttp(mx, prev['og:image'], /* useAuthentication */ true);
71+
if (!mxcUrl) {
72+
console.error('Error converting mxc:// url.');
73+
return;
74+
}
75+
openMediaInNewTab(mxcUrl);
76+
}
77+
};
5378

5479
return (
5580
<Box
@@ -128,6 +153,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number; mediaType?: s
128153
<ImageContent
129154
style={{ width: '100%', height: '100%', position: 'absolute', inset: 0 }}
130155
autoPlay
156+
onAuxClick={handleAuxClick}
131157
body={prev['og:title']}
132158
url={prev['og:image']}
133159
renderViewer={(p) => <ImageViewer {...p} />}
@@ -187,7 +213,6 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number; mediaType?: s
187213
</Box>
188214
);
189215
}
190-
191216
return (
192217
<UrlPreview
193218
{...props}

0 commit comments

Comments
 (0)