Add modal for images (#60)

This commit is contained in:
Maria Rushkova 2021-10-08 17:40:53 +02:00 committed by GitHub
parent a722e8527a
commit 173e400e80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 4 deletions

View File

@ -12,6 +12,7 @@ import { Channels } from "./Channels";
import { ChatBody } from "./Chat/ChatBody"; import { ChatBody } from "./Chat/ChatBody";
import { Members } from "./Members"; import { Members } from "./Members";
import { CommunityModal } from "./Modals/CommunityModal"; import { CommunityModal } from "./Modals/CommunityModal";
import { PictureModal } from "./Modals/PictureModal";
interface ChatProps { interface ChatProps {
theme: Theme; theme: Theme;
@ -40,6 +41,7 @@ export function Chat({ theme, community, fetchMetadata }: ChatProps) {
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => setIsModalVisible(true); const showModal = () => setIsModalVisible(true);
const [image, setImage] = useState("");
return ( return (
<ChatWrapper> <ChatWrapper>
@ -70,6 +72,7 @@ export function Chat({ theme, community, fetchMetadata }: ChatProps) {
onCommunityClick={showModal} onCommunityClick={showModal}
lastMessage={lastMessage} lastMessage={lastMessage}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
setImage={setImage}
/> />
{showMembers && !narrow && ( {showMembers && !narrow && (
<Members community={community} setShowChannels={setShowChannels} /> <Members community={community} setShowChannels={setShowChannels} />
@ -83,6 +86,11 @@ export function Chat({ theme, community, fetchMetadata }: ChatProps) {
description={community.description} description={community.description}
publicKey="0xD95DBdaB08A9FED2D71ac9C3028AAc40905d8CF3" publicKey="0xD95DBdaB08A9FED2D71ac9C3028AAc40905d8CF3"
/> />
<PictureModal
isVisible={!!image}
onClose={() => setImage("")}
image={image}
/>
</ChatWrapper> </ChatWrapper>
); );
} }

View File

@ -36,6 +36,7 @@ interface ChatBodyProps {
onCommunityClick: () => void; onCommunityClick: () => void;
lastMessage: Date; lastMessage: Date;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
setImage: (image: string) => void;
} }
export function ChatBody({ export function ChatBody({
@ -55,6 +56,7 @@ export function ChatBody({
onCommunityClick, onCommunityClick,
lastMessage, lastMessage,
fetchMetadata, fetchMetadata,
setImage,
}: ChatBodyProps) { }: ChatBodyProps) {
const narrow = useNarrow(); const narrow = useNarrow();
const [showChannelsList, setShowChannelsList] = useState(false); const [showChannelsList, setShowChannelsList] = useState(false);
@ -117,6 +119,7 @@ export function ChatBody({
messages={messages} messages={messages}
loadNextDay={loadNextDay} loadNextDay={loadNextDay}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
setImage={setImage}
/> />
) : ( ) : (
<LoadingSkeleton /> <LoadingSkeleton />

View File

@ -13,11 +13,15 @@ const regEx =
type ChatMessageContentProps = { type ChatMessageContentProps = {
message: ChatMessage; message: ChatMessage;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
setImage: (image: string) => void;
}; };
export function ChatMessageContent({ export function ChatMessageContent({
message, message,
fetchMetadata, fetchMetadata,
setImage,
}: ChatMessageContentProps) { }: ChatMessageContentProps) {
const { content, image } = useMemo(() => message, [message]); const { content, image } = useMemo(() => message, [message]);
const [elements, setElements] = useState<(string | React.ReactElement)[]>([ const [elements, setElements] = useState<(string | React.ReactElement)[]>([
@ -71,7 +75,15 @@ export function ChatMessageContent({
return ( return (
<ContentWrapper> <ContentWrapper>
<div>{elements.map((el) => el)}</div> <div>{elements.map((el) => el)}</div>
{image && <MessageImage src={image} />} {image && (
<MessageImageWrapper
onClick={() => {
setImage(image);
}}
>
<MessageImage src={image} />
</MessageImageWrapper>
)}
{openGraph && ( {openGraph && (
<PreviewWrapper <PreviewWrapper
onClick={() => window?.open(link, "_blank", "noopener")?.focus()} onClick={() => window?.open(link, "_blank", "noopener")?.focus()}
@ -87,13 +99,19 @@ export function ChatMessageContent({
); );
} }
const MessageImage = styled.img` const MessageImageWrapper = styled.div`
width: 147px; width: 147px;
height: 196px; height: 196px;
border-radius: 16px;
margin-top: 8px; margin-top: 8px;
`; `;
const MessageImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 16px;
`;
const PreviewSiteNameWrapper = styled.div` const PreviewSiteNameWrapper = styled.div`
font-family: Inter; font-family: Inter;
font-style: normal; font-style: normal;

View File

@ -12,12 +12,16 @@ type ChatMessagesProps = {
messages: ChatMessage[]; messages: ChatMessage[];
loadNextDay: () => void; loadNextDay: () => void;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
setImage: (image: string) => void;
}; };
export function ChatMessages({ export function ChatMessages({
messages, messages,
loadNextDay, loadNextDay,
fetchMetadata, fetchMetadata,
setImage,
}: ChatMessagesProps) { }: ChatMessagesProps) {
const [scrollOnBot, setScrollOnBot] = useState(true); const [scrollOnBot, setScrollOnBot] = useState(true);
const ref = useRef<HTMLHeadingElement>(null); const ref = useRef<HTMLHeadingElement>(null);
@ -80,6 +84,7 @@ export function ChatMessages({
<ChatMessageContent <ChatMessageContent
message={message} message={message}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
setImage={setImage}
/> />
</MessageText> </MessageText>
</ContentWrapper> </ContentWrapper>

View File

@ -44,7 +44,7 @@ export const Modal = ({
<ModalView> <ModalView>
<ModalOverlay onClick={onClose} /> <ModalOverlay onClick={onClose} />
<ModalBody className={className}> <ModalBody className={className}>
<CloseButton onClick={onClose}> <CloseButton onClick={onClose} className={className}>
<CrossIcon /> <CrossIcon />
</CloseButton> </CloseButton>
{children} {children}
@ -75,6 +75,11 @@ const ModalBody = styled.div`
background: ${({ theme }) => theme.bodyBackgroundColor}; background: ${({ theme }) => theme.bodyBackgroundColor};
border-radius: 8px; border-radius: 8px;
overflow-y: auto; overflow-y: auto;
&.picture {
max-width: 820px;
border-radius: 0;
}
`; `;
const ModalOverlay = styled.div` const ModalOverlay = styled.div`
@ -94,4 +99,8 @@ const CloseButton = styled.button`
top: 12px; top: 12px;
right: 12px; right: 12px;
padding: 10px; padding: 10px;
&.picture {
display: none;
}
`; `;

View File

@ -0,0 +1,33 @@
import React from "react";
import styled from "styled-components";
import { BasicModalProps, Modal } from "./Modal";
interface PictureModalProps extends BasicModalProps {
image: string;
}
export const PictureModal = ({
isVisible,
onClose,
image,
}: PictureModalProps) => {
return (
<Modal isVisible={isVisible} onClose={onClose} className="picture">
<ModalImageWrapper>
<ModalImage src={image}></ModalImage>
</ModalImageWrapper>
</Modal>
);
};
const ModalImageWrapper = styled.div`
display: flex;
max-width: 820px;
max-height: 820px;
`;
const ModalImage = styled.img`
width: 100%;
height: 100%;
`;