diff --git a/src/app/components/RenderMessageContent.tsx b/src/app/components/RenderMessageContent.tsx index bc937427..4cfcb7dc 100644 --- a/src/app/components/RenderMessageContent.tsx +++ b/src/app/components/RenderMessageContent.tsx @@ -64,12 +64,7 @@ export function RenderMessageContent({ return ( {filteredUrls.map((url) => ( - } - ts={ts} - /> + ))} ); diff --git a/src/app/components/url-preview/UrlPreview.css.tsx b/src/app/components/url-preview/UrlPreview.css.tsx index 3192dc49..cd0b2528 100644 --- a/src/app/components/url-preview/UrlPreview.css.tsx +++ b/src/app/components/url-preview/UrlPreview.css.tsx @@ -23,6 +23,11 @@ export const UrlPreviewImg = style([ objectPosition: 'center', flexShrink: 0, overflow: 'hidden', + cursor: 'pointer', + + ':hover': { + filter: 'brightness(0.8)', + }, }, ]); diff --git a/src/app/components/url-preview/UrlPreviewCard.tsx b/src/app/components/url-preview/UrlPreviewCard.tsx index f4efd33a..ee8967af 100644 --- a/src/app/components/url-preview/UrlPreviewCard.tsx +++ b/src/app/components/url-preview/UrlPreviewCard.tsx @@ -1,7 +1,7 @@ -import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { IPreviewUrlResponse } from 'matrix-js-sdk'; import { Box, Icon, IconButton, Icons, Scroll, Spinner, Text, as, color, config } from 'folds'; -import { RenderViewerProps, ImageOverlay } from '../ImageOverlay'; +import { ImageOverlay } from '../ImageOverlay'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { UrlPreview, UrlPreviewContent, UrlPreviewDescription, UrlPreviewImg } from './UrlPreview'; @@ -13,97 +13,100 @@ import * as css from './UrlPreviewCard.css'; import { tryDecodeURIComponent } from '../../utils/dom'; import { mxcUrlToHttp } from '../../utils/matrix'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; +import { ImageViewer } from '../image-viewer'; +import { onEnterOrSpace } from '../../utils/keyboard'; const linkStyles = { color: color.Success.Main }; -export const UrlPreviewCard = as< - 'div', - { url: string; ts: number; renderViewer: (props: RenderViewerProps) => ReactNode } ->(({ url, ts, renderViewer, ...props }, ref) => { - const mx = useMatrixClient(); - const useAuthentication = useMediaAuthentication(); - const [viewer, setViewer] = useState(false); - const [previewStatus, loadPreview] = useAsyncCallback( - useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx]) - ); - - useEffect(() => { - loadPreview(); - }, [loadPreview]); - - if (previewStatus.status === AsyncStatus.Error) return null; - - const renderContent = (prev: IPreviewUrlResponse) => { - const thumbUrl = mxcUrlToHttp( - mx, - prev['og:image'] || '', - useAuthentication, - 256, - 256, - 'scale', - false +export const UrlPreviewCard = as<'div', { url: string; ts: number }>( + ({ url, ts, ...props }, ref) => { + const mx = useMatrixClient(); + const useAuthentication = useMediaAuthentication(); + const [viewer, setViewer] = useState(false); + const [previewStatus, loadPreview] = useAsyncCallback( + useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx]) ); - const imgUrl = mxcUrlToHttp(mx, prev['og:image'] || '', useAuthentication); + useEffect(() => { + loadPreview(); + }, [loadPreview]); + + if (previewStatus.status === AsyncStatus.Error) return null; + + const renderContent = (prev: IPreviewUrlResponse) => { + const thumbUrl = mxcUrlToHttp( + mx, + prev['og:image'] || '', + useAuthentication, + 256, + 256, + 'scale', + false + ); + + const imgUrl = mxcUrlToHttp(mx, prev['og:image'] || '', useAuthentication); + + return ( + <> + {thumbUrl && ( + onEnterOrSpace(() => setViewer(true))(evt)} + onClick={() => setViewer(true)} + /> + )} + {imgUrl && ( + { + setViewer(false); + }} + renderViewer={(p) => } + /> + )} + + + {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `} + {tryDecodeURIComponent(url)} + + + {prev['og:title']} + + + {prev['og:description']} + + + + ); + }; return ( - <> - {thumbUrl && ( - setViewer(true)} - /> + + {previewStatus.status === AsyncStatus.Success ? ( + renderContent(previewStatus.data) + ) : ( + + + )} - {imgUrl && ( - { - setViewer(false); - }} - renderViewer={renderViewer} - /> - )} - - - {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `} - {tryDecodeURIComponent(url)} - - - {prev['og:title']} - - - {prev['og:description']} - - - + ); - }; - - return ( - - {previewStatus.status === AsyncStatus.Success ? ( - renderContent(previewStatus.data) - ) : ( - - - - )} - - ); -}); + } +); export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => { const scrollRef = useRef(null);