Improve link preview look and feel (#33981)

* Update link previews to match design

* Preview updates

* snap update for pw

* Retain tall image snap

* Move icon to the right.

* cleanup

* Fix bubbles

* resnappening
This commit is contained in:
Will Hunt
2026-06-29 18:50:20 +00:00
committed by GitHub
parent 3e40e58b12
commit 6ce24e2668
25 changed files with 192 additions and 195 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 170 KiB

@@ -6,20 +6,22 @@
*/ */
button.preview { button.preview {
background: #fff; background-color: #fff;
} }
.preview { .preview {
display: flex; display: flex;
position: relative; position: relative;
width: 100%; max-width: 100%;
width: 478px;
height: 200px; height: 200px;
background-size: cover; background-size: cover;
background-position: center; background-position: center;
border: none; border: none;
padding: 0; padding: 0;
> img { > img {
width: 100%; height: 200px;
width: 478px;
object-fit: cover; object-fit: cover;
} }
.playButton[data-kind="primary"] { .playButton[data-kind="primary"] {
@@ -37,9 +39,10 @@ button.preview {
} }
.container { .container {
max-width: 478px; max-width: 100%;
width: 478px;
display: flex; display: flex;
border: 1px solid var(--cpd-color-bg-subtle-secondary); border: 1px solid var(--cpd-color-border-interactive-primary);
border-radius: 12px; /* Get radius from cpd */ border-radius: 12px; /* Get radius from cpd */
flex-direction: column; flex-direction: column;
color: var(--cpd-color-gray-900); color: var(--cpd-color-gray-900);
@@ -87,29 +90,20 @@ button.preview {
.title, .title,
.description { .description {
display: inline-block; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
white-space: normal; white-space: normal;
line-clamp: 2;
-webkit-line-clamp: 2;
margin: 0;
} }
.title { .title {
display: inline-block;
line-clamp: 2;
-webkit-line-clamp: 2;
color: var(--cpd-color-text-primary); color: var(--cpd-color-text-primary);
text-decoration-line: none; text-decoration-line: none;
} }
.description {
margin: 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
}
.siteName { .siteName {
margin-top: var(--cpd-space-1x); margin-top: var(--cpd-space-1x);
vertical-align: middle; vertical-align: middle;
@@ -13,6 +13,7 @@ import { LinkPreview } from "./LinkPreview";
import { LinkedTextContext } from "../../../../../core/utils/LinkedText"; import { LinkedTextContext } from "../../../../../core/utils/LinkedText";
import imageFile from "../../../../../../static/element.png"; import imageFile from "../../../../../../static/element.png";
import imageFileWide from "../../../../../../static/wideImage.png"; import imageFileWide from "../../../../../../static/wideImage.png";
import imageFileTall from "../../../../../../static/tallImage.png";
export default { export default {
title: "EventTiles/LinkPreview", title: "EventTiles/LinkPreview",
@@ -167,3 +168,17 @@ WithVeryLongText.args = {
playable: false, playable: false,
}, },
}; };
export const WithTallImage = Template.bind({});
WithTallImage.args = {
title: "A simple title",
description: "A simple description",
link: "https://matrix.org",
siteName: "Site name",
image: {
imageThumb: imageFileTall,
imageFull: imageFileTall,
alt: "Element logo",
playable: false,
},
};
@@ -135,12 +135,13 @@ export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX
// Otherwise, the preview can be clicked on. // Otherwise, the preview can be clicked on.
img = ( img = (
<button <button
style={{
backgroundImage: `url('${preview.image.imageThumb}')`,
}}
className={styles.preview} className={styles.preview}
onClick={onImageClickHandler} onClick={onImageClickHandler}
aria-label={_t("timeline|url_preview|view_image")} aria-label={_t("timeline|url_preview|view_image")}
> />
<img src={preview.image.imageThumb} alt={preview.image.alt} title={preview.image.alt} />
</button>
); );
} }
} }
@@ -71,13 +71,8 @@ exports[`LinkPreview > renders a preview 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="Element logo"
src="/static/element.png"
title="Element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -5,13 +5,20 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
.hideButton {
position: absolute;
top: var(--cpd-space-2x);
right: var(--cpd-space-2x);
z-index: 1;
}
.wrapper { .wrapper {
margin-top: var(--cpd-space-4x); margin-top: var(--cpd-space-4x);
display: flex; position: relative;
flex-direction: row; width: fit-content;
max-width: 100%;
.previewGroup { .previewGroup {
flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--cpd-space-4x); gap: var(--cpd-space-4x);
@@ -54,6 +54,22 @@ export interface UrlPreviewGroupViewActions {
/** View model contract for the URL preview group view. */ /** View model contract for the URL preview group view. */
export type UrlPreviewGroupViewModel = ViewModel<UrlPreviewGroupViewSnapshot, UrlPreviewGroupViewActions>; export type UrlPreviewGroupViewModel = ViewModel<UrlPreviewGroupViewSnapshot, UrlPreviewGroupViewActions>;
function HideButton({ onHideClick }: { onHideClick: UrlPreviewGroupViewActions["onHideClick"] }): JSX.Element {
const { translate: _t } = useI18n();
return (
<div className={styles.hideButton}>
<IconButton
kind="secondary"
size="28px"
onClick={onHideClick}
aria-label={_t("timeline|url_preview|close")}
>
<CloseIcon />
</IconButton>
</div>
);
}
/** /**
* Renders the URL preview group attached to a single event. * Renders the URL preview group attached to a single event.
* *
@@ -81,20 +97,13 @@ export function UrlPreviewGroupView({ vm, className }: UrlPreviewGroupViewProps)
return ( return (
<div className={classNames(className, styles.wrapper)} {...eventPresentationAttributes}> <div className={classNames(className, styles.wrapper)} {...eventPresentationAttributes}>
<HideButton onHideClick={vm.onHideClick} />
<div className={styles.previewGroup}> <div className={styles.previewGroup}>
{previews.map((preview) => ( {previews.map((preview) => (
<LinkPreview key={preview.link} onImageClick={() => vm.onImageClick(preview)} {...preview} /> <LinkPreview key={preview.link} onImageClick={() => vm.onImageClick(preview)} {...preview} />
))} ))}
{toggleButton} {toggleButton}
</div> </div>
<IconButton
kind="secondary"
size="28px"
onClick={vm.onHideClick}
aria-label={_t("timeline|url_preview|close")}
>
<CloseIcon />
</IconButton>
</div> </div>
); );
} }
@@ -7,6 +7,35 @@ exports[`UrlPreviewGroupView > renders a single preview 1`] = `
data-event-density="default" data-event-density="default"
data-event-layout="group" data-event-layout="group"
> >
<div
class="UrlPreviewGroupView-module_hideButton"
>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div>
<div <div
class="UrlPreviewGroupView-module_previewGroup" class="UrlPreviewGroupView-module_previewGroup"
> >
@@ -16,13 +45,8 @@ exports[`UrlPreviewGroupView > renders a single preview 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -51,31 +75,6 @@ exports[`UrlPreviewGroupView > renders a single preview 1`] = `
</div> </div>
</div> </div>
</div> </div>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div> </div>
</div> </div>
`; `;
@@ -87,6 +86,35 @@ exports[`UrlPreviewGroupView > renders multiple previews 1`] = `
data-event-density="default" data-event-density="default"
data-event-layout="group" data-event-layout="group"
> >
<div
class="UrlPreviewGroupView-module_hideButton"
>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div>
<div <div
class="UrlPreviewGroupView-module_previewGroup" class="UrlPreviewGroupView-module_previewGroup"
> >
@@ -96,13 +124,8 @@ exports[`UrlPreviewGroupView > renders multiple previews 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -136,13 +159,8 @@ exports[`UrlPreviewGroupView > renders multiple previews 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/tallImage.png");"
<img />
alt="A dog"
src="/static/tallImage.png"
title="A dog"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -176,13 +194,8 @@ exports[`UrlPreviewGroupView > renders multiple previews 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -220,31 +233,6 @@ exports[`UrlPreviewGroupView > renders multiple previews 1`] = `
Collapse Collapse
</button> </button>
</div> </div>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div> </div>
</div> </div>
`; `;
@@ -256,6 +244,35 @@ exports[`UrlPreviewGroupView > renders multiple previews which are hidden 1`] =
data-event-density="default" data-event-density="default"
data-event-layout="group" data-event-layout="group"
> >
<div
class="UrlPreviewGroupView-module_hideButton"
>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div>
<div <div
class="UrlPreviewGroupView-module_previewGroup" class="UrlPreviewGroupView-module_previewGroup"
> >
@@ -265,13 +282,8 @@ exports[`UrlPreviewGroupView > renders multiple previews which are hidden 1`] =
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -309,31 +321,6 @@ exports[`UrlPreviewGroupView > renders multiple previews which are hidden 1`] =
Show 9 other previews Show 9 other previews
</button> </button>
</div> </div>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div> </div>
</div> </div>
`; `;
@@ -345,6 +332,35 @@ exports[`UrlPreviewGroupView > renders with compact density 1`] = `
data-event-density="compact" data-event-density="compact"
data-event-layout="group" data-event-layout="group"
> >
<div
class="UrlPreviewGroupView-module_hideButton"
>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div>
<div <div
class="UrlPreviewGroupView-module_previewGroup" class="UrlPreviewGroupView-module_previewGroup"
> >
@@ -354,13 +370,8 @@ exports[`UrlPreviewGroupView > renders with compact density 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -394,13 +405,8 @@ exports[`UrlPreviewGroupView > renders with compact density 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/tallImage.png");"
<img />
alt="A dog"
src="/static/tallImage.png"
title="A dog"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -434,13 +440,8 @@ exports[`UrlPreviewGroupView > renders with compact density 1`] = `
<button <button
aria-label="View image" aria-label="View image"
class="LinkPreview-module_preview" class="LinkPreview-module_preview"
> style="background-image: url("/static/element.png");"
<img />
alt="The element logo"
src="/static/element.png"
title="The element logo"
/>
</button>
<div <div
class="LinkPreview-module_textContent" class="LinkPreview-module_textContent"
> >
@@ -478,31 +479,6 @@ exports[`UrlPreviewGroupView > renders with compact density 1`] = `
Collapse Collapse
</button> </button>
</div> </div>
<button
aria-label="Close preview"
class="_icon-button_1215g_8"
data-kind="secondary"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414"
/>
</svg>
</div>
</button>
</div> </div>
</div> </div>
`; `;