Update previews again

This commit is contained in:
Half-Shot 2026-04-10 09:16:02 +01:00
parent 2662a9866c
commit 1d88ebd088
8 changed files with 72 additions and 44 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -14,6 +14,7 @@ import { useI18n } from "../../../../../core/i18n/i18nContext";
import type { UrlPreview } from "../types";
import { LinkedText } from "../../../../../core/utils/LinkedText";
import styles from "./LinkPreview.module.css";
import { isPropValid } from "storybook/theming";
export interface LinkPreviewActions {
onImageClick: () => void;
@ -21,6 +22,63 @@ export interface LinkPreviewActions {
export type LinkPreviewProps = UrlPreview & LinkPreviewActions;
function LinkTitle({
title,
showTooltipOnLink,
link,
}: Pick<LinkPreviewProps, "title" | "showTooltipOnLink" | "link">): JSX.Element {
const caption = new URL(link).toString();
const anchor = (
<Text
as="a"
type="body"
weight="semibold"
size="lg"
className={styles.title}
href={link}
target="_blank"
rel="noreferrer noopener"
>
{title}
</Text>
);
return showTooltipOnLink ? <Tooltip label={caption}>{anchor}</Tooltip> : anchor;
}
function LinkSiteName({ siteIcon, siteName }: { siteIcon?: string; siteName: string }): JSX.Element {
return (
<div className={styles.siteName}>
<Avatar size="16px" name={siteName} id={siteName} src={siteIcon} />
<Text as="span" size="sm" weight="regular">
{siteName}
</Text>
</div>
);
}
/**
* A condensed link preview that only contains the site icon, the title of the link and the site name.
*/
function LinkPreviewInline({
title,
showTooltipOnLink,
siteIcon,
siteName,
link,
}: Omit<LinkPreviewProps, "image" | "description" | "author" | "onImageClick">): JSX.Element {
return (
<div className={classNames(styles.container, styles.inline)}>
<div className={styles.siteAvatar}>
<Avatar type="square" size="48px" name={title} id={title} src={siteIcon} />
</div>
<div className={classNames(styles.textContent, styles.inline)}>
<LinkTitle title={title} showTooltipOnLink={showTooltipOnLink} link={link} />
{siteName && <LinkSiteName siteName={siteName} siteIcon={siteIcon} />}
</div>
</div>
);
}
/**
* LinkPreview renders a single preview component for a single link on an event. It is usually rendered as part of
* a `UrlPreviewGroupView`.
@ -28,13 +86,6 @@ export type LinkPreviewProps = UrlPreview & LinkPreviewActions;
export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX.Element {
const { translate: _t } = useI18n();
const tooltipCaption = useMemo(() => {
if (preview.showTooltipOnLink) {
return new URL(preview.link, window.location.href).toString();
}
return null;
}, [preview.link, preview.showTooltipOnLink]);
const onImageClickHandler = useCallback<MouseEventHandler>(
(ev) => {
if (ev.button != 0 || ev.metaKey) return;
@ -48,10 +99,17 @@ export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX
[preview.image?.imageFull, onImageClick],
);
if (!preview.image && !preview.author && !preview.description) {
return <LinkPreviewInline {...preview} />;
}
let img: JSX.Element | undefined;
// Don't render a button to show the image, just hide it outright
if (preview.image) {
if (preview.image.playable) {
// Playable media do not have clickable images so we don't
// overlay buttons atop buttons, instead we render a
// button for them to open the media.
img = (
<div
style={{
@ -73,6 +131,7 @@ export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX
</div>
);
} else {
// Otherwise, the preview can be clicked on.
img = (
<button
className={styles.preview}
@ -85,51 +144,20 @@ export function LinkPreview({ onImageClick, ...preview }: LinkPreviewProps): JSX
}
}
const anchor = (
<Text
as="a"
type="body"
weight="semibold"
size="lg"
className={styles.title}
href={preview.link}
target="_blank"
rel="noreferrer noopener"
>
{preview.title}
</Text>
);
const useInline = !preview.image && !preview.author && !preview.description;
return (
<div className={classNames(styles.container, useInline && styles.inline)}>
<div className={styles.container}>
{img}
{useInline && (
<div className={styles.siteAvatar}>
<Avatar type="square" size="48px" name={preview.title} id={preview.title} src={preview.siteIcon} />
</div>
)}
<div className={classNames(styles.textContent, useInline && styles.inline)}>
<div className={styles.textContent}>
{preview.author && (
<Text as="span" size="md" weight="semibold">
{preview.author}
</Text>
)}
{anchor && tooltipCaption ? <Tooltip label={tooltipCaption}>{anchor}</Tooltip> : anchor}
<LinkTitle title={preview.title} showTooltipOnLink={preview.showTooltipOnLink} link={preview.link} />
<LinkedText type="body" size="md" className={styles.description}>
{preview.description}
</LinkedText>
{preview.siteName && (
<div className={styles.siteName}>
{!useInline && (
<Avatar size="16px" name={preview.siteName} id={preview.siteName} src={preview.siteIcon} />
)}
<Text as="span" size="sm" weight="regular">
{preview.siteName}
</Text>
</div>
)}
{preview.siteName && <LinkSiteName siteName={preview.siteName} siteIcon={preview.siteIcon} />}
</div>
</div>
);

View File

@ -21,7 +21,7 @@ export interface UrlPreview {
/**
* The site name to be displayed alongside the title.
*/
siteName?: string;
siteName: string;
/**
* The HTTP URI of the the sites icon.
*/