From 0d3f29515e3ec8f1aab179914aa6634d323b2ded Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Thu, 30 Jun 2022 19:34:04 +0100 Subject: [PATCH] feat: port `ImageViewer` --- .../messaging/attachments/ImageFile.tsx | 10 ++-- .../common/messaging/embed/Embed.tsx | 7 ++- .../common/messaging/embed/EmbedMedia.tsx | 8 +-- src/context/intermediate/Popovers.tsx | 3 - .../popovers/ChannelInfo.module.scss | 16 ------ .../intermediate/popovers/ChannelInfo.tsx | 41 -------------- .../popovers/ImageViewer.module.scss | 20 ------- .../intermediate/popovers/UserProfile.tsx | 7 ++- src/controllers/modals/ModalController.tsx | 2 + .../modals/components}/ImageViewer.tsx | 55 ++++++++++++------- src/controllers/modals/types.ts | 5 ++ 11 files changed, 58 insertions(+), 116 deletions(-) delete mode 100644 src/context/intermediate/popovers/ChannelInfo.module.scss delete mode 100644 src/context/intermediate/popovers/ChannelInfo.tsx delete mode 100644 src/context/intermediate/popovers/ImageViewer.module.scss rename src/{context/intermediate/popovers => controllers/modals/components}/ImageViewer.tsx (58%) diff --git a/src/components/common/messaging/attachments/ImageFile.tsx b/src/components/common/messaging/attachments/ImageFile.tsx index 76723e20..7c2364d2 100644 --- a/src/components/common/messaging/attachments/ImageFile.tsx +++ b/src/components/common/messaging/attachments/ImageFile.tsx @@ -2,11 +2,10 @@ import { API } from "revolt.js"; import styles from "./Attachment.module.scss"; import classNames from "classnames"; -import { useContext, useState } from "preact/hooks"; - -import { useIntermediate } from "../../../../context/intermediate/Intermediate"; +import { useState } from "preact/hooks"; import { useClient } from "../../../../controllers/client/ClientController"; +import { modalController } from "../../../../controllers/modals/ModalController"; enum ImageLoadingState { Loading, @@ -21,7 +20,6 @@ type Props = JSX.HTMLAttributes & { export default function ImageFile({ attachment, ...props }: Props) { const [loading, setLoading] = useState(ImageLoadingState.Loading); const client = useClient(); - const { openScreen } = useIntermediate(); const url = client.generateFileURL(attachment)!; return ( @@ -33,7 +31,9 @@ export default function ImageFile({ attachment, ...props }: Props) { className={classNames(styles.image, { [styles.loading]: loading !== ImageLoadingState.Loaded, })} - onClick={() => openScreen({ id: "image_viewer", attachment })} + onClick={() => + modalController.push({ type: "image_viewer", attachment }) + } onMouseDown={(ev) => ev.button === 1 && window.open(url, "_blank")} onLoad={() => setLoading(ImageLoadingState.Loaded)} onError={() => setLoading(ImageLoadingState.Error)} diff --git a/src/components/common/messaging/embed/Embed.tsx b/src/components/common/messaging/embed/Embed.tsx index 306f6441..822f30b2 100644 --- a/src/components/common/messaging/embed/Embed.tsx +++ b/src/components/common/messaging/embed/Embed.tsx @@ -7,6 +7,7 @@ import { useContext } from "preact/hooks"; import { useIntermediate } from "../../../../context/intermediate/Intermediate"; import { useClient } from "../../../../controllers/client/ClientController"; +import { modalController } from "../../../../controllers/modals/ModalController"; import { MessageAreaWidthContext } from "../../../../pages/channels/messaging/MessageArea"; import Markdown from "../../../markdown/Markdown"; import Attachment from "../attachments/Attachment"; @@ -24,7 +25,7 @@ const MAX_PREVIEW_SIZE = 150; export default function Embed({ embed }: Props) { const client = useClient(); - const { openScreen, openLink } = useIntermediate(); + const { openLink } = useIntermediate(); const maxWidth = Math.min( useContext(MessageAreaWidthContext) - CONTAINER_PADDING, MAX_EMBED_WIDTH, @@ -191,7 +192,9 @@ export default function Embed({ embed }: Props) { type="text/html" frameBorder="0" loading="lazy" - onClick={() => openScreen({ id: "image_viewer", embed })} + onClick={() => + modalController.push({ type: "image_viewer", embed }) + } onMouseDown={(ev) => ev.button === 1 && openLink(embed.url)} /> ); diff --git a/src/components/common/messaging/embed/EmbedMedia.tsx b/src/components/common/messaging/embed/EmbedMedia.tsx index a719f0e3..201b3d84 100644 --- a/src/components/common/messaging/embed/EmbedMedia.tsx +++ b/src/components/common/messaging/embed/EmbedMedia.tsx @@ -3,9 +3,8 @@ import { API } from "revolt.js"; import styles from "./Embed.module.scss"; -import { useIntermediate } from "../../../../context/intermediate/Intermediate"; - import { useClient } from "../../../../controllers/client/ClientController"; +import { modalController } from "../../../../controllers/modals/ModalController"; interface Props { embed: API.Embed; @@ -15,7 +14,6 @@ interface Props { export default function EmbedMedia({ embed, width, height }: Props) { if (embed.type !== "Website") return null; - const { openScreen } = useIntermediate(); const client = useClient(); switch (embed.special?.type) { @@ -118,8 +116,8 @@ export default function EmbedMedia({ embed, width, height }: Props) { loading="lazy" style={{ width, height }} onClick={() => - openScreen({ - id: "image_viewer", + modalController.push({ + type: "image_viewer", embed: embed.image!, }) } diff --git a/src/context/intermediate/Popovers.tsx b/src/context/intermediate/Popovers.tsx index 0dc85eed..20789cfd 100644 --- a/src/context/intermediate/Popovers.tsx +++ b/src/context/intermediate/Popovers.tsx @@ -4,7 +4,6 @@ import { IntermediateContext, useIntermediate } from "./Intermediate"; import { SpecialInputModal } from "./modals/Input"; import { SpecialPromptModal } from "./modals/Prompt"; import { CreateBotModal } from "./popovers/CreateBot"; -import { ImageViewer } from "./popovers/ImageViewer"; import { UserPicker } from "./popovers/UserPicker"; import { UserProfile } from "./popovers/UserProfile"; @@ -24,8 +23,6 @@ export default function Popovers() { case "user_picker": // @ts-expect-error someone figure this out :) return ; - case "image_viewer": - return ; case "create_bot": // @ts-expect-error someone figure this out :) return ; diff --git a/src/context/intermediate/popovers/ChannelInfo.module.scss b/src/context/intermediate/popovers/ChannelInfo.module.scss deleted file mode 100644 index ff37d169..00000000 --- a/src/context/intermediate/popovers/ChannelInfo.module.scss +++ /dev/null @@ -1,16 +0,0 @@ -.info { - .header { - display: flex; - align-items: center; - flex-direction: row; - - h1 { - margin: 0; - flex-grow: 1; - } - - div { - cursor: pointer; - } - } -} diff --git a/src/context/intermediate/popovers/ChannelInfo.tsx b/src/context/intermediate/popovers/ChannelInfo.tsx deleted file mode 100644 index d2a37f42..00000000 --- a/src/context/intermediate/popovers/ChannelInfo.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { X } from "@styled-icons/boxicons-regular"; -import { observer } from "mobx-react-lite"; -import { Channel } from "revolt.js"; - -import styles from "./ChannelInfo.module.scss"; - -import { Modal } from "@revoltchat/ui"; - -import Markdown from "../../../components/markdown/Markdown"; -import { getChannelName } from "../../revoltjs/util"; - -interface Props { - channel: Channel; - onClose: () => void; -} - -export const ChannelInfo = observer(({ channel, onClose }: Props) => { - if ( - channel.channel_type === "DirectMessage" || - channel.channel_type === "SavedMessages" - ) { - onClose(); - return null; - } - - return ( - -
-
-

{getChannelName(channel, true)}

-
- -
-
-

- -

-
-
- ); -}); diff --git a/src/context/intermediate/popovers/ImageViewer.module.scss b/src/context/intermediate/popovers/ImageViewer.module.scss deleted file mode 100644 index a450d0a7..00000000 --- a/src/context/intermediate/popovers/ImageViewer.module.scss +++ /dev/null @@ -1,20 +0,0 @@ -.viewer { - display: flex; - overflow: hidden; - flex-direction: column; - border-end-end-radius: 4px; - border-end-start-radius: 4px; - - max-width: 100vw; - - img { - width: auto; - height: auto; - max-width: 90vw; - max-height: 75vh; - object-fit: contain; - border-bottom: thin solid var(--tertiary-foreground); - - -webkit-touch-callout: default; - } -} diff --git a/src/context/intermediate/popovers/UserProfile.tsx b/src/context/intermediate/popovers/UserProfile.tsx index 5a4eb4c0..764a3b34 100644 --- a/src/context/intermediate/popovers/UserProfile.tsx +++ b/src/context/intermediate/popovers/UserProfile.tsx @@ -13,7 +13,7 @@ import { UserPermission, API } from "revolt.js"; import styles from "./UserProfile.module.scss"; import { Localizer, Text } from "preact-i18n"; -import { useContext, useEffect, useLayoutEffect, useState } from "preact/hooks"; +import { useEffect, useLayoutEffect, useState } from "preact/hooks"; import { Button, @@ -35,6 +35,7 @@ import { Username } from "../../../components/common/user/UserShort"; import UserStatus from "../../../components/common/user/UserStatus"; import Markdown from "../../../components/markdown/Markdown"; import { useSession } from "../../../controllers/client/ClientController"; +import { modalController } from "../../../controllers/modals/ModalController"; import { useIntermediate } from "../Intermediate"; interface Props { @@ -159,8 +160,8 @@ export const UserProfile = observer( hover={typeof user.avatar !== "undefined"} onClick={() => user.avatar && - openScreen({ - id: "image_viewer", + modalController.push({ + type: "image_viewer", attachment: user.avatar, }) } diff --git a/src/controllers/modals/ModalController.tsx b/src/controllers/modals/ModalController.tsx index 3f78b7bc..cc6e7f9a 100644 --- a/src/controllers/modals/ModalController.tsx +++ b/src/controllers/modals/ModalController.tsx @@ -21,6 +21,7 @@ import Changelog from "./components/Changelog"; import ChannelInfo from "./components/ChannelInfo"; import Clipboard from "./components/Clipboard"; import Error from "./components/Error"; +import ImageViewer from "./components/ImageViewer"; import LinkWarning from "./components/LinkWarning"; import MFAEnableTOTP from "./components/MFAEnableTOTP"; import MFAFlow from "./components/MFAFlow"; @@ -222,6 +223,7 @@ export const modalController = new ModalControllerExtended({ channel_info: ChannelInfo, clipboard: Clipboard, error: Error, + image_viewer: ImageViewer, link_warning: LinkWarning, mfa_flow: MFAFlow, mfa_recovery: MFARecovery, diff --git a/src/context/intermediate/popovers/ImageViewer.tsx b/src/controllers/modals/components/ImageViewer.tsx similarity index 58% rename from src/context/intermediate/popovers/ImageViewer.tsx rename to src/controllers/modals/components/ImageViewer.tsx index 12a17f3c..526ec9c4 100644 --- a/src/context/intermediate/popovers/ImageViewer.tsx +++ b/src/controllers/modals/components/ImageViewer.tsx @@ -1,23 +1,40 @@ -/* eslint-disable react-hooks/rules-of-hooks */ -import { API } from "revolt.js"; - -import styles from "./ImageViewer.module.scss"; +import styled from "styled-components"; import { Modal } from "@revoltchat/ui"; import AttachmentActions from "../../../components/common/messaging/attachments/AttachmentActions"; import EmbedMediaActions from "../../../components/common/messaging/embed/EmbedMediaActions"; -import { useClient } from "../../../controllers/client/ClientController"; +import { useClient } from "../../client/ClientController"; +import { ModalProps } from "../types"; -interface Props { - onClose: () => void; - embed?: API.Image; - attachment?: API.File; -} +const Viewer = styled.div` + display: flex; + overflow: hidden; + flex-direction: column; + border-end-end-radius: 4px; + border-end-start-radius: 4px; -type ImageMetadata = API.Metadata & { type: "Image" }; + max-width: 100vw; + + img { + width: auto; + height: auto; + max-width: 90vw; + max-height: 75vh; + object-fit: contain; + border-bottom: thin solid var(--tertiary-foreground); + + -webkit-touch-callout: default; + } +`; + +export default function ImageViewer({ + embed, + attachment, + ...props +}: ModalProps<"image_viewer">) { + const client = useClient(); -export function ImageViewer({ attachment, embed, onClose }: Props) { if (attachment && attachment.metadata.type !== "Image") { console.warn( `Attempted to use a non valid attatchment type in the image viewer: ${attachment.metadata.type}`, @@ -25,20 +42,16 @@ export function ImageViewer({ attachment, embed, onClose }: Props) { return null; } - const client = useClient(); - return ( - -
+ + {attachment && ( <> @@ -54,7 +67,7 @@ export function ImageViewer({ attachment, embed, onClose }: Props) { )} -
+
); } diff --git a/src/controllers/modals/types.ts b/src/controllers/modals/types.ts index 160673af..e2e3b854 100644 --- a/src/controllers/modals/types.ts +++ b/src/controllers/modals/types.ts @@ -80,6 +80,11 @@ export type Modal = { type: "server_info"; server: Server; } + | { + type: "image_viewer"; + embed?: API.Image; + attachment?: API.File; + } ); export type ModalProps = Modal & { type: T } & {