Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,61 @@ button.preview {
background-color: #fff;
}

.preview {
display: flex;
position: relative;
.containerCollapsed {
max-width: 100%;
width: 478px;
height: 200px;
background-size: cover;
background-position: center;
border: none;
padding: 0;
width: calc(478px - 32px);
/* minus the padding */
display: flex;
border: 1px solid var(--cpd-color-border-interactive-primary);
border-radius: 12px;
/* Get radius from cpd */
flex-direction: row;
color: var(--cpd-color-gray-900);
overflow: clip;
gap: 8px;
padding: 12px 16px;

.playButton[data-kind="primary"] {
padding: 0;
width: 50px;
height: 50px;
margin: auto;
background: var(--cpd-color-text-on-solid-primary);
> svg {
margin: auto;
border-radius: 50px;
color: var(--cpd-color-icon-primary);
}
background: var(--cpd-color-bg-subtle-secondary);

.textContent {
display: flex;
flex-direction: column;
}

.preview {
width: 40px;
height: 40px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 8px;
border: none;
flex-shrink: 0;
}

.siteName {
line-height: 17.5px;
}

.title,
.siteName>span {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
line-clamp: 1;
overflow: hidden;
min-width: 0;
}
}

.container {
.containerExpanded {
box-sizing: border-box;
max-width: 100%;
width: 478px;
display: flex;
border: 1px solid var(--cpd-color-border-interactive-secondary);
border-radius: 12px; /* Get radius from cpd */
border-radius: 12px;
/* Get radius from cpd */
flex-direction: column;
color: var(--cpd-color-gray-900);
overflow: clip;
Expand All @@ -67,9 +90,11 @@ button.preview {

.textContent {
padding: var(--cpd-space-3x) var(--cpd-space-4x);

&.inline {
padding: 0;
}

display: flex;
flex-direction: column;
gap: var(--cpd-space-1x);
Expand All @@ -78,20 +103,59 @@ button.preview {
.caption {
display: inline-flex;
flex-direction: column;
min-width: 0; /* Prevent blowout */
min-width: 0;
/* Prevent blowout */
}

.caption {
flex: 1;
overflow: hidden; /* cause it to wrap rather than clip */
overflow: hidden;
/* cause it to wrap rather than clip */
}

.preview {
display: flex;
position: relative;
max-width: 100%;
width: 478px;
height: 200px;
background-size: cover;
background-position: center;
border: none;
padding: 0;

.playButton[data-kind="primary"] {
padding: 0;
width: 50px;
height: 50px;
margin: auto;
background: var(--cpd-color-text-on-solid-primary);

>svg {
margin: auto;
border-radius: 50px;
color: var(--cpd-color-icon-primary);
}
}
}

.siteName {
margin-top: var(--cpd-space-1x);
}

.title,
.description {
line-clamp: 2;
-webkit-line-clamp: 2;
}
}

.siteName {
margin-top: var(--cpd-space-1x);
vertical-align: middle;
display: flex;
gap: var(--cpd-space-1-5x);
> * {

>* {
/* Center everything */
margin: auto 0;
}
Expand All @@ -103,8 +167,6 @@ button.preview {
-webkit-box-orient: vertical;
overflow: hidden;
white-space: normal;
line-clamp: 2;
-webkit-line-clamp: 2;
margin: 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

import React, { type MouseEventHandler, type JSX, useCallback } from "react";
import React, { type JSX } from "react";
import { Tooltip, Text, Avatar, Button } from "@vector-im/compound-web";
import PlaySolidIcon from "@vector-im/compound-design-tokens/assets/web/icons/play-solid";
import classNames from "classnames";
Expand All @@ -19,7 +19,7 @@ export interface LinkPreviewActions {
onImageClick: () => void;
}

export type LinkPreviewProps = UrlPreview & LinkPreviewActions;
export type LinkPreviewProps = UrlPreview & LinkPreviewActions & { collapsed: boolean };

export function LinkTitle({
title,
Expand Down Expand Up @@ -66,7 +66,7 @@ function LinkPreviewInline({
link,
}: Omit<LinkPreviewProps, "image" | "description" | "author" | "onImageClick">): JSX.Element {
return (
<div className={classNames(styles.container, styles.inline)}>
<div className={classNames(styles.containerExpanded, styles.inline)}>
{siteIcon && (
<div className={styles.siteAvatar}>
<Avatar type="square" size="48px" name={title} id={title} src={siteIcon} />
Expand All @@ -84,21 +84,56 @@ function LinkPreviewInline({
* LinkPreview renders a single preview component for a single link on an event. It is usually rendered as part of
* a `UrlPreviewGroupView`.
*/
export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX.Element {
export function LinkPreview(props: LinkPreviewProps): JSX.Element {
if (props.collapsed) {
return <LinkPreviewCollapsed {...props} />;
} else {
return <LinkPreviewExpanded {...props} />;
}
}

function createImageClickHandler({ onImageClick, ...preview }: LinkPreviewProps): React.MouseEventHandler {
return (ev) => {
if (ev.button != 0 || ev.metaKey) return;
ev.preventDefault();

if (!preview.image?.imageFull) {
return;
}
onImageClick();
};
}

export function LinkPreviewCollapsed(preview: LinkPreviewProps): JSX.Element {
const { translate: _t } = useI18n();
let img: JSX.Element | undefined;

if (preview.image && !preview.image.playable) {
img = (
<button
style={{
backgroundImage: `url('${preview.image.imageThumb}')`,
}}
className={styles.preview}
onClick={createImageClickHandler(preview)}
aria-label={_t("timeline|url_preview|view_image")}
/>
);
}

const onImageClickHandler = useCallback<MouseEventHandler>(
(ev) => {
if (ev.button != 0 || ev.metaKey) return;
ev.preventDefault();

if (!preview.image?.imageFull) {
return;
}
onImageClick();
},
[preview.image?.imageFull, onImageClick],
return (
<div className={styles.containerCollapsed}>
{img}
<div className={styles.textContent}>
<LinkTitle title={preview.title} showTooltipOnLink={preview.showTooltipOnLink} link={preview.link} />
{preview.siteName && <LinkSiteName siteName={preview.siteName} />}
</div>
</div>
);
}

export function LinkPreviewExpanded(preview: LinkPreviewProps): JSX.Element {
const { translate: _t } = useI18n();

if (!preview.image && !preview.author && !preview.description) {
return <LinkPreviewInline {...preview} />;
Expand Down Expand Up @@ -139,15 +174,15 @@ export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX
backgroundImage: `url('${preview.image.imageThumb}')`,
}}
className={styles.preview}
onClick={onImageClickHandler}
onClick={createImageClickHandler(preview)}
aria-label={_t("timeline|url_preview|view_image")}
/>
);
}
}

return (
<div className={styles.container}>
<div className={styles.containerExpanded}>
{img}
<div className={styles.textContent}>
{preview.author && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,13 @@ export function UrlPreviewGroupView({ vm, className }: UrlPreviewGroupViewProps)
<div className={classNames(className, styles.wrapper)} {...eventPresentationAttributes}>
<HideButton onHideClick={vm.onHideClick} />
<div className={styles.previewGroup}>
{previews.map((preview) => (
{previews.map((preview, i) => (
<LinkPreview
key={preview.link}
onImageClick={() => vm.onImageClick(preview)}
{...preview}
image={preview.image}
collapsed={i !== 0}
/>
))}
{toggleButton}
Expand Down
Loading