diff --git a/src/components/messaging/EmbedMedia.tsx b/src/components/messaging/EmbedMedia.tsx index 06771ce..977ea1b 100644 --- a/src/components/messaging/EmbedMedia.tsx +++ b/src/components/messaging/EmbedMedia.tsx @@ -2,6 +2,7 @@ // https://github.com/revoltchat/revite/blob/master/src/components/common/messaging/embed/Embed.tsx import { APIEmbed, EmbedType } from "@spacebarchat/spacebar-api-types/v9"; +import { modalController } from "../../controllers/modals"; import styles from "./Embed.module.css"; interface Props { @@ -111,7 +112,16 @@ function EmbedMedia({ embed, width, height, thumbnail }: Props) { src={url} loading="lazy" style={{ width: "100%", height: "100%" }} - onClick={() => window.open(url, "_blank")} + onClick={() => { + if (!embed.image) { + console.error("embed has no image... wtf"); + return; + } + modalController.push({ + type: "image_viewer", + attachment: embed.image, + }); + }} /> ); } else if (embed.thumbnail) { @@ -123,7 +133,16 @@ function EmbedMedia({ embed, width, height, thumbnail }: Props) { src={url} loading="lazy" style={{ width, height }} - onClick={() => window.open(url, "_blank")} + onClick={() => { + if (!embed.thumbnail) { + console.error("embed has no thumbnail... wtf"); + return; + } + modalController.push({ + type: "image_viewer", + attachment: embed.thumbnail, + }); + }} /> ); } diff --git a/src/components/messaging/MessageAttachment.tsx b/src/components/messaging/MessageAttachment.tsx index 878f542..fd36021 100644 --- a/src/components/messaging/MessageAttachment.tsx +++ b/src/components/messaging/MessageAttachment.tsx @@ -1,5 +1,6 @@ import { APIAttachment } from "@spacebarchat/spacebar-api-types/v9"; import styled from "styled-components"; +import { modalController } from "../../controllers/modals"; import useLogger from "../../hooks/useLogger"; import { calculateImageRatio, calculateScaledDimensions } from "../../utils/Message"; import { getFileDetails, zoomFit } from "../../utils/Utils"; @@ -57,7 +58,12 @@ export default function MessageAttachment({ attachment, maxWidth, maxHeight }: A onClick={() => { if (!attachment.content_type?.startsWith("image")) return; const { width, height } = zoomFit(attachment.width!, attachment.height!); - // TODO: preview modal + modalController.push({ + type: "image_viewer", + attachment, + width, + height, + }); }} > {finalElement} diff --git a/src/components/modals/AttachmentPreviewModal.tsx b/src/components/modals/AttachmentPreviewModal.tsx deleted file mode 100644 index 5589046..0000000 --- a/src/components/modals/AttachmentPreviewModal.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function AttachmentPreviewModal() { - return null; -} diff --git a/src/components/modals/ImageViewerModal.tsx b/src/components/modals/ImageViewerModal.tsx new file mode 100644 index 0000000..795227d --- /dev/null +++ b/src/components/modals/ImageViewerModal.tsx @@ -0,0 +1,36 @@ +import { APIAttachment, APIEmbedImage, APIEmbedThumbnail } from "@spacebarchat/spacebar-api-types/v9"; +import styled from "styled-components"; +import { Modal } from "./ModalComponents"; + +const Container = styled.div` + display: flex; + overflow: hidden; + flex-direction: column; + max-width: 90vw; + max-height: 75vh; + + img { + width: auto; + height: auto; + object-fit: contain; + } +`; + +interface Props { + attachment: APIAttachment | APIEmbedImage | APIEmbedThumbnail; + width?: number; + height?: number; +} + +export function ImageViewerModal(props: Props) { + const width = props.width ?? props.attachment.width ?? 0; + const height = props.height ?? props.attachment.height ?? 0; + + return ( + + + + + + ); +} diff --git a/src/components/modals/ModalComponents.tsx b/src/components/modals/ModalComponents.tsx index ade391f..eb0cd8d 100644 --- a/src/components/modals/ModalComponents.tsx +++ b/src/components/modals/ModalComponents.tsx @@ -26,6 +26,7 @@ interface ModalProps { actions?: ModalAction[]; disabled?: boolean; withEmptyActionBar?: boolean; + withoutCloseButton?: boolean; } /** @@ -205,13 +206,15 @@ export function Modal({ title, description, ...props }: ModalProps) { !props.nonDismissable && closeModal()}> e.stopPropagation()} actions={false}> -
- {!props.nonDismissable && ( - - - - )} -
+ {!props.withoutCloseButton && ( +
+ {!props.nonDismissable && ( + + + + )} +
+ )} {(title || description) && ( {title && typeof title === "string" ? {title} : title} diff --git a/src/components/modals/index.ts b/src/components/modals/index.ts index 08916cb..7d64b47 100644 --- a/src/components/modals/index.ts +++ b/src/components/modals/index.ts @@ -1,11 +1,11 @@ export * from "./AddServerModal"; -export * from "./AttachmentPreviewModal"; export * from "./BanMemberModal"; export * from "./CreateInviteModal"; export * from "./CreateServerModal"; export * from "./DeleteMessageModal"; export * from "./ErrorModal"; export * from "./ForgotPasswordModal"; +export * from "./ImageViewerModal"; export * from "./JoinServerModal"; export * from "./KickMemberModal"; export * from "./LeaveServerModal"; diff --git a/src/controllers/modals/ModalController.tsx b/src/controllers/modals/ModalController.tsx index 4f34d2b..df99e80 100644 --- a/src/controllers/modals/ModalController.tsx +++ b/src/controllers/modals/ModalController.tsx @@ -8,6 +8,7 @@ import { CreateServerModal, DeleteMessageModal, ErrorModal, + ImageViewerModal, JoinServerModal, KickMemberModal, LeaveServerModal, @@ -162,7 +163,7 @@ export const modalController = new ModalControllerExtended({ // custom_status: CustomStatus, delete_message: DeleteMessageModal, error: ErrorModal, - // image_viewer: ImageViewer, + image_viewer: ImageViewerModal, kick_member: KickMemberModal, // link_warning: LinkWarning, // mfa_flow: MFAFlow, diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index c7289a5..688b544 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -1,5 +1,6 @@ // adapted from https://github.com/revoltchat/revite/blob/master/src/controllers/modals/types.ts +import { APIAttachment, APIEmbedImage, APIEmbedThumbnail } from "@spacebarchat/spacebar-api-types/v9"; import Channel from "../../stores/objects/Channel"; import Guild from "../../stores/objects/Guild"; import GuildMember from "../../stores/objects/GuildMember"; @@ -42,6 +43,12 @@ export type Modal = { type: "leave_server"; target: Guild; } + | { + type: "image_viewer"; + attachment: APIAttachment | APIEmbedImage | APIEmbedThumbnail; + width?: number; + height?: number; + } ); export type ModalProps = Modal & { type: T } & {