Skip to content

Commit

Permalink
Merge pull request #181 from Here21/dev/fullScreen
Browse files Browse the repository at this point in the history
Image fullscreen preview
  • Loading branch information
Martín Callegari authored May 29, 2020
2 parents 24f7059 + fe5e732 commit 28ffcb1
Show file tree
Hide file tree
Showing 28 changed files with 571 additions and 47 deletions.
1 change: 1 addition & 0 deletions assets/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/minus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/zoom-in.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/zoom-out.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 14 additions & 8 deletions dev/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export default class App extends Component {
componentDidMount() {
addResponseMessage('Welcome to this awesome chat!');
addLinkSnippet({ link: 'https://google.com', title: 'Google' });
addResponseMessage('![](https://raw.githubusercontent.com/Wolox/press-kit/master/logos/logo_banner.png)');
addResponseMessage('![vertical](https://d2sofvawe08yqg.cloudfront.net/reintroducing-react/hero2x?1556470143)');
}

handleNewUserMessage = (newMessage: any) => {
Expand Down Expand Up @@ -36,14 +38,18 @@ export default class App extends Component {

render() {
return (
<Widget
title="Bienvenido"
subtitle="Asistente virtual"
senderPlaceHolder="Escribe aquí ..."
handleNewUserMessage={this.handleNewUserMessage}
handleQuickButtonClicked={this.handleQuickButtonClicked}
handleSubmit={this.handleSubmit}
/>
<div>
<button style={{position: 'absolute', right: 40, bottom: 150}}>test</button>
<Widget
title="Bienvenido"
subtitle="Asistente virtual"
senderPlaceHolder="Escribe aquí ..."
handleNewUserMessage={this.handleNewUserMessage}
handleQuickButtonClicked={this.handleQuickButtonClicked}
imagePreview
handleSubmit={this.handleSubmit}
/>
</div>
);
}
}
13 changes: 11 additions & 2 deletions dev/index.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, shrink-to-fit=no">
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no, shrink-to-fit=no"
/>
<title>Dev Widget</title>
<style>
html,
body {
margin: 0;
}
</style>
</head>
<body>
<div id="root"></div>
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@babel/preset-env": "^7.8.7",
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@toycode/markdown-it-class": "^1.2.3",
"@types/classnames": "^2.2.10",
"@types/enzyme": "^3.10.5",
"@types/jest": "^25.1.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import format from 'date-fns/format';
import markdownIt from 'markdown-it';
import markdownItSup from 'markdown-it-sup';
import markdownItSanitizer from 'markdown-it-sanitizer';
import markdownItClass from '@toycode/markdown-it-class';
import markdownItLinkAttributes from 'markdown-it-link-attributes';

import { Message } from 'src/store/types';
Expand All @@ -15,7 +16,11 @@ type Props = {
}

function Message({ message, showTimeStamp }: Props) {
const sanitizedHTML = markdownIt().use(markdownItSup)
const sanitizedHTML = markdownIt()
.use(markdownItClass, {
img: ['rcw-message-img']
})
.use(markdownItSup)
.use(markdownItSanitizer)
.use(markdownItLinkAttributes, { attrs: { target: '_blank', rel: 'noopener' } })
.render(message.text);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
display: flex;
flex-direction: column;
margin-left: auto;

.rcw-message-text {
@include message-bubble($turqois-2);
}
Expand All @@ -38,10 +38,14 @@

/* For markdown elements created with default styles */
.rcw-message-text {

p {
margin: 0;
}

img {
width: 100%;
object-fit: contain;
}
}

.rcw-avatar {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState, ElementRef, ImgHTMLAttributes, MouseEvent } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import format from 'date-fns/format';

Expand All @@ -23,7 +23,7 @@ function Messages({ profileAvatar, showTimeStamp }: Props) {
showChat: state.behavior.showChat
}));

const messageRef = useRef(null);
const messageRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
// @ts-ignore
scrollToBottom(messageRef.current);
Expand Down
6 changes: 3 additions & 3 deletions src/components/Widget/components/Conversation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
.rcw-conversation-container {
border-radius: 10px;
box-shadow: 0px 2px 10px 1px $grey-3;


&.active {
opacity: 1;
transform: translateY(0px);
transition: opacity 0.3s ease, transform 0.3s ease;
transition: opacity 0.3s ease, transform 0.3s ease;
}

&.hidden {
z-index: -1;
pointer-events: none;
opacity: 0;
transform: translateY(10px);
transition: opacity 0.3s ease, transform 0.3s ease;
transition: opacity 0.3s ease, transform 0.3s ease;
}
}

Expand Down
91 changes: 91 additions & 0 deletions src/components/Widget/components/FullScreenPreview/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useEffect, ReactNode } from 'react';
import ReactDOM from 'react-dom';
import { useSelector, useDispatch } from 'react-redux';
import usePreview from './usePreview';
import usePortal from './usePortal';
import './styles.scss';
import { GlobalState } from '../../../../store/types';
import { closeFullscreenPreview } from '../../../../store/actions';

const close = require('../../../../../assets/close.svg') as string;
const plus = require('../../../../../assets/plus.svg') as string;
const minus = require('../../../../../assets/minus.svg') as string;
const zoomIn = require('../../../../../assets/zoom-in.svg') as string;
const zoomOut = require('../../../../../assets/zoom-out.svg') as string;

type Props = {
fullScreenMode?: boolean;
zoomStep?: number
}

export default function FullScreenPreview({ fullScreenMode, zoomStep }:Props) {
const {
state,
initFileSize,
onZoomIn,
onZoomOut,
onResizePageZoom
} = usePreview(zoomStep);

const dispatch = useDispatch();
const { src, alt, width, height, visible } = useSelector((state: GlobalState) => ({
src: state.preview.src,
alt: state.preview.alt,
width: state.preview.width,
height: state.preview.height,
visible: state.preview.visible
}));

useEffect(() => {
if(src) {
initFileSize(width, height);
}
}, [src])

const pDom = usePortal()

const onClosePreview = () => {
dispatch(closeFullscreenPreview())
}

const childNode: ReactNode = (
<div className="rcw-previewer-container">
<div className="rcw-previewer-veil">
<img {...state.layout} src={src} className="rcw-previewer-image" alt={alt} />
</div>
<button
className="rcw-previewer-button rcw-previewer-close-button"
onClick={onClosePreview}
>
<img src={close} className="rcw-previewer-icon" />
</button>
<div className="rcw-previewer-tools">
<button
className="rcw-previewer-button"
onClick={onResizePageZoom}
>
<img
src={state.zoom ? zoomOut : zoomIn}
className="rcw-previewer-icon"
alt="reset zoom"
/>
</button>

<button
className="rcw-previewer-button"
onClick={onZoomIn}
>
<img src={plus} className="rcw-previewer-icon" alt="zoom in"/>
</button>
<button
className="rcw-previewer-button"
onClick={onZoomOut}
>
<img src={minus} className="rcw-previewer-icon" alt="zoom out"/>
</button>
</div>
</div>
)

return visible ? ReactDOM.createPortal(childNode, pDom) : null;
}
60 changes: 60 additions & 0 deletions src/components/Widget/components/FullScreenPreview/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@import 'variables/colors';

.rcw-previewer-container {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.75);
overflow: hidden;
position: fixed;
z-index: 9999;
left: 0;
top: 0;

.rcw-previewer-image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
transition: all 0.3s ease;
}

.rcw-previewer-tools {
position: fixed;
right: 16px;
bottom: 16px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.rcw-previewer-button {
padding: 0;
margin: 16px;
box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.3);
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
outline: none;
background-color: $white;
border: none;
}

.rcw-previewer-close-button {
position: absolute;
right: 0;
top: 0;
}

.rcw-previewer-veil {
width: 100%;
height: 100%;
overflow: scroll;
position: relative;
}
}
52 changes: 52 additions & 0 deletions src/components/Widget/components/FullScreenPreview/usePortal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useRef, useEffect } from 'react';

function createRootElement(id: string):HTMLDivElement {
const rootContainer = document.createElement('div');
rootContainer.setAttribute('id', id);
return rootContainer;
}

function addRootElement(rootElem: HTMLDivElement):void {
document.body.appendChild(rootElem);
}

function usePortal():HTMLDivElement {
const rootElemRef = useRef<HTMLElement | null>(null);

useEffect(() => {
// Look for existing target dom element to append to
const existingParent: HTMLDivElement | null = document.querySelector('#rcw-image-preview');
// Parent is either a new root or the existing dom element
const parentElem: HTMLDivElement = existingParent || createRootElement('#rcw-image-preview');

// If there is no existing DOM element, add a new one.
if (!existingParent) {
addRootElement(parentElem);
}

// Add the detached element to the parent
if(rootElemRef.current) {
parentElem.appendChild(rootElemRef.current);
}

return function removeElement() {
if(rootElemRef.current) {
rootElemRef.current.remove();
}
if (parentElem.childNodes.length === -1) {
parentElem.remove();
}
};
}, []);

function getRootElem():HTMLDivElement {
if (!rootElemRef.current) {
rootElemRef.current = document.createElement('div');
}
return rootElemRef.current as HTMLDivElement;
}

return getRootElem();
}

export default usePortal;
Loading

0 comments on commit 28ffcb1

Please sign in to comment.