1
0
mirror of https://github.com/spacebarchat/client.git synced 2024-11-22 10:22:30 +01:00

implement image viewer modal

This commit is contained in:
Puyodead1 2023-12-19 13:19:05 -05:00
parent 126eec5b64
commit f720ce8975
No known key found for this signature in database
GPG Key ID: BA5F91AAEF68E5CE
8 changed files with 84 additions and 15 deletions

View File

@ -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,
});
}}
/>
);
}

View File

@ -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}

View File

@ -1,3 +0,0 @@
export function AttachmentPreviewModal() {
return null;
}

View File

@ -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 (
<Modal {...props} transparent maxWidth="100vw" maxHeight="100vh" withoutCloseButton withEmptyActionBar>
<Container>
<img src={props.attachment.url} width={width} height={height} loading="eager" />
</Container>
</Modal>
);
}

View File

@ -26,6 +26,7 @@ interface ModalProps {
actions?: ModalAction[];
disabled?: boolean;
withEmptyActionBar?: boolean;
withoutCloseButton?: boolean;
}
/**
@ -205,6 +206,7 @@ export function Modal({ title, description, ...props }: ModalProps) {
<Portal>
<ModalBase closing={closing} onClick={() => !props.nonDismissable && closeModal()}>
<ModalWrapper {...props} onClick={(e) => e.stopPropagation()} actions={false}>
{!props.withoutCloseButton && (
<div style={{ position: "relative" }}>
{!props.nonDismissable && (
<ModalCloseWrapper onClick={closeModal}>
@ -212,6 +214,7 @@ export function Modal({ title, description, ...props }: ModalProps) {
</ModalCloseWrapper>
)}
</div>
)}
{(title || description) && (
<ModalHeader>
{title && typeof title === "string" ? <ModalHeaderText>{title}</ModalHeaderText> : title}

View File

@ -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";

View File

@ -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,

View File

@ -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<T extends Modal["type"]> = Modal & { type: T } & {