diff --git a/src/components/Video.tsx b/src/components/Video.tsx new file mode 100644 index 00000000..cd7bb28e --- /dev/null +++ b/src/components/Video.tsx @@ -0,0 +1,77 @@ +import { APIAttachment } from "@spacebarchat/spacebar-api-types/v9"; +import React from "react"; +import { PuffLoader } from "react-spinners"; +import styled from "styled-components"; +import { calculateImageRatio, calculateScaledDimensions } from "../utils/Message"; + +const Container = styled.div` + display: flex; + justify-content: center; + align-items: center; + min-height: 300px; + min-width: 300px; + background-color: var(--background-primary); + border-radius: 10px; +`; + +interface Props { + attachment: APIAttachment; +} + +function Video({ attachment }: Props) { + const ref = React.useRef(null); + const [isLoading, setLoading] = React.useState(true); + const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 }); + const [isErrored, setErrored] = React.useState(false); + + const url = attachment.proxy_url && attachment.proxy_url.length > 0 ? attachment.proxy_url : attachment.url; + + const onLoadedMetadata = (e: React.SyntheticEvent) => { + const video = e.target as HTMLVideoElement; + const width = video.videoWidth; + const height = video.videoHeight; + const ratio = calculateImageRatio(width, height, 300, 300); + const scaledDimensions = calculateScaledDimensions(width, height, ratio, 300, 300); + setDimensions({ width: scaledDimensions.scaledWidth, height: scaledDimensions.scaledHeight }); + setLoading(false); + }; + + const onError = () => { + setErrored(true); + }; + + // TODO: poster + // TODO: the server doesn't return height and width yet for videos + return ( + <> + {isLoading && !isErrored && ( + + + + )} + {isErrored && ( + +

Failed to load video

+
+ )} + + {!isErrored && ( + + )} + + ); +} + +export default Video; diff --git a/src/components/messaging/Message.tsx b/src/components/messaging/Message.tsx index 8a28f7b1..b8644e73 100644 --- a/src/components/messaging/Message.tsx +++ b/src/components/messaging/Message.tsx @@ -22,6 +22,7 @@ const Container = styled.div<{ isHeader?: boolean }>` flex-direction: row; position: relative; padding: 2px 12px; + margin-top: ${(props) => (props.isHeader ? "20px" : undefined)}; &:hover { background-color: var(--background-primary-highlight); @@ -138,6 +139,7 @@ function Message({ message, isHeader, isSending, isFailed }: Props) { // }, [isSending, isFailed]); // handles creating the message content based on the message type + // TODO: probably move this to a separate component const renderMessageContent = React.useCallback(() => { switch (message.type) { case MessageType.Default: @@ -158,7 +160,6 @@ function Message({ message, isHeader, isSending, isFailed }: Props) { {"embeds" in message ? message.embeds.map((embed, index) => ( - {" "} ; )) diff --git a/src/components/messaging/MessageAttachment.tsx b/src/components/messaging/MessageAttachment.tsx index 7dde2e2f..4508e6f5 100644 --- a/src/components/messaging/MessageAttachment.tsx +++ b/src/components/messaging/MessageAttachment.tsx @@ -6,6 +6,7 @@ import { ContextMenuContext } from "../../contexts/ContextMenuContext"; import useLogger from "../../hooks/useLogger"; import { calculateImageRatio, calculateScaledDimensions } from "../../utils/Message"; import { IContextMenuItem } from "../ContextMenuItem"; +import Video from "../Video"; import AttachmentPreviewModal from "../modals/AttachmentPreviewModal"; const Attachment = styled.div<{ withPointer?: boolean }>` @@ -44,15 +45,7 @@ export default function MessageAttachment({ attachment, contextMenuItems, maxWid ); finalElement = {attachment.filename}; } else if (attachment.content_type?.startsWith("video")) { - { - /* TODO: poster thumbnail */ - } - finalElement = ( - - ); + finalElement =