2021-06-20 17:09:18 -04:00
|
|
|
import { Embed as EmbedRJS } from "revolt.js/dist/api/objects";
|
2021-07-05 06:23:23 -04:00
|
|
|
|
|
|
|
import styles from "./Embed.module.scss";
|
|
|
|
import classNames from "classnames";
|
|
|
|
import { useContext } from "preact/hooks";
|
|
|
|
|
|
|
|
import { useIntermediate } from "../../../../context/intermediate/Intermediate";
|
2021-07-24 06:22:08 -04:00
|
|
|
import { useClient } from "../../../../context/revoltjs/RevoltClient";
|
2021-07-05 06:23:23 -04:00
|
|
|
|
|
|
|
import { MessageAreaWidthContext } from "../../../../pages/channels/messaging/MessageArea";
|
|
|
|
import EmbedMedia from "./EmbedMedia";
|
2021-06-20 17:09:18 -04:00
|
|
|
|
|
|
|
interface Props {
|
2021-07-05 06:25:20 -04:00
|
|
|
embed: EmbedRJS;
|
2021-06-20 17:09:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const MAX_EMBED_WIDTH = 480;
|
|
|
|
const MAX_EMBED_HEIGHT = 640;
|
|
|
|
const CONTAINER_PADDING = 24;
|
|
|
|
const MAX_PREVIEW_SIZE = 150;
|
|
|
|
|
|
|
|
export default function Embed({ embed }: Props) {
|
2021-07-24 06:22:08 -04:00
|
|
|
const client = useClient();
|
2021-07-05 06:25:20 -04:00
|
|
|
|
|
|
|
const { openScreen } = useIntermediate();
|
|
|
|
const maxWidth = Math.min(
|
|
|
|
useContext(MessageAreaWidthContext) - CONTAINER_PADDING,
|
|
|
|
MAX_EMBED_WIDTH,
|
|
|
|
);
|
|
|
|
|
|
|
|
function calculateSize(
|
|
|
|
w: number,
|
|
|
|
h: number,
|
|
|
|
): { width: number; height: number } {
|
2021-07-10 10:57:29 -04:00
|
|
|
const limitingWidth = Math.min(maxWidth, w);
|
2021-07-05 06:25:20 -04:00
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
const limitingHeight = Math.min(MAX_EMBED_HEIGHT, h);
|
2021-07-05 06:25:20 -04:00
|
|
|
|
|
|
|
// Calculate smallest possible WxH.
|
2021-07-10 10:57:29 -04:00
|
|
|
const width = Math.min(limitingWidth, limitingHeight * (w / h));
|
2021-07-05 06:25:20 -04:00
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
const height = Math.min(limitingHeight, limitingWidth * (h / w));
|
2021-07-05 06:25:20 -04:00
|
|
|
|
|
|
|
return { width, height };
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (embed.type) {
|
|
|
|
case "Website": {
|
|
|
|
// Determine special embed size.
|
|
|
|
let mw, mh;
|
2021-07-10 10:57:29 -04:00
|
|
|
const largeMedia =
|
2021-07-05 06:25:20 -04:00
|
|
|
(embed.special && embed.special.type !== "None") ||
|
|
|
|
embed.image?.size === "Large";
|
|
|
|
switch (embed.special?.type) {
|
|
|
|
case "YouTube":
|
|
|
|
case "Bandcamp": {
|
|
|
|
mw = embed.video?.width ?? 1280;
|
|
|
|
mh = embed.video?.height ?? 720;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case "Twitch": {
|
|
|
|
mw = 1280;
|
|
|
|
mh = 720;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
if (embed.image?.size === "Preview") {
|
|
|
|
mw = MAX_EMBED_WIDTH;
|
|
|
|
mh = Math.min(
|
|
|
|
embed.image.height ?? 0,
|
|
|
|
MAX_PREVIEW_SIZE,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
mw = embed.image?.width ?? MAX_EMBED_WIDTH;
|
|
|
|
mh = embed.image?.height ?? 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-10 10:57:29 -04:00
|
|
|
const { width, height } = calculateSize(mw, mh);
|
2021-07-05 06:25:20 -04:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={classNames(styles.embed, styles.website)}
|
|
|
|
style={{
|
|
|
|
borderInlineStartColor:
|
|
|
|
embed.color ?? "var(--tertiary-background)",
|
|
|
|
width: width + CONTAINER_PADDING,
|
|
|
|
}}>
|
|
|
|
<div>
|
|
|
|
{embed.site_name && (
|
|
|
|
<div className={styles.siteinfo}>
|
|
|
|
{embed.icon_url && (
|
|
|
|
<img
|
|
|
|
className={styles.favicon}
|
2021-07-24 06:22:08 -04:00
|
|
|
src={client.proxyFile(embed.icon_url)}
|
2021-07-05 06:25:20 -04:00
|
|
|
draggable={false}
|
|
|
|
onError={(e) =>
|
|
|
|
(e.currentTarget.style.display =
|
|
|
|
"none")
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<div className={styles.site}>
|
|
|
|
{embed.site_name}{" "}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{/*<span><a href={embed.url} target={"_blank"} className={styles.author}>Author</a></span>*/}
|
|
|
|
{embed.title && (
|
|
|
|
<span>
|
|
|
|
<a
|
|
|
|
href={embed.url}
|
|
|
|
target={"_blank"}
|
2021-07-10 10:57:29 -04:00
|
|
|
className={styles.title}
|
|
|
|
rel="noreferrer">
|
2021-07-05 06:25:20 -04:00
|
|
|
{embed.title}
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
{embed.description && (
|
|
|
|
<div className={styles.description}>
|
|
|
|
{embed.description}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{largeMedia && (
|
|
|
|
<EmbedMedia embed={embed} height={height} />
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
{!largeMedia && (
|
|
|
|
<div>
|
|
|
|
<EmbedMedia
|
|
|
|
embed={embed}
|
|
|
|
width={
|
|
|
|
height *
|
|
|
|
((embed.image?.width ?? 0) /
|
|
|
|
(embed.image?.height ?? 0))
|
|
|
|
}
|
|
|
|
height={height}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
case "Image": {
|
|
|
|
return (
|
|
|
|
<img
|
|
|
|
className={classNames(styles.embed, styles.image)}
|
|
|
|
style={calculateSize(embed.width, embed.height)}
|
2021-07-24 06:22:08 -04:00
|
|
|
src={client.proxyFile(embed.url)}
|
2021-07-05 06:25:20 -04:00
|
|
|
type="text/html"
|
|
|
|
frameBorder="0"
|
2021-07-24 06:22:08 -04:00
|
|
|
loading="lazy"
|
2021-07-05 06:25:20 -04:00
|
|
|
onClick={() => openScreen({ id: "image_viewer", embed })}
|
|
|
|
onMouseDown={(ev) =>
|
|
|
|
ev.button === 1 && window.open(embed.url, "_blank")
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
2021-06-20 17:09:18 -04:00
|
|
|
}
|