From a5a305feb557f41e352adb506eafcd46658dc13c Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 8 Apr 2018 23:06:33 +0200 Subject: [PATCH 1/5] [Glitch] Allow to open a modal for embedded photo Port 16a49799cfea8519c384ff37c722149e589e0248 to glitch-soc --- .../glitch/features/status/components/card.js | 36 +++++++++++++++++-- .../status/components/detailed_status.js | 2 +- .../features/ui/components/image_loader.js | 4 +-- .../features/ui/components/media_modal.js | 2 +- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js index bb83374b9b..680bf63ab7 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.js +++ b/app/javascript/flavours/glitch/features/status/components/card.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import Immutable from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import punycode from 'punycode'; import classnames from 'classnames'; @@ -24,6 +25,7 @@ export default class Card extends React.PureComponent { static propTypes = { card: ImmutablePropTypes.map, maxDescription: PropTypes.number, + onOpenMedia: PropTypes.func.isRequired, }; static defaultProps = { @@ -34,6 +36,27 @@ export default class Card extends React.PureComponent { width: 0, }; + handlePhotoClick = () => { + const { card, onOpenMedia } = this.props; + + onOpenMedia( + Immutable.fromJS([ + { + type: 'image', + url: card.get('url'), + description: card.get('title'), + meta: { + original: { + width: card.get('width'), + height: card.get('height'), + }, + }, + }, + ]), + 0 + ); + }; + renderLink () { const { card, maxDescription } = this.props; @@ -73,9 +96,16 @@ export default class Card extends React.PureComponent { const { card } = this.props; return ( - - {card.get('title')} - + {card.get('title')} ); } diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 538aa3d288..ed8094e78e 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -75,7 +75,7 @@ export default class DetailedStatus extends ImmutablePureComponent { ); mediaIcon = 'picture-o'; } - } else media = ; + } else media = ; if (status.get('application')) { applicationLink = ยท {status.getIn(['application', 'name'])}; diff --git a/app/javascript/flavours/glitch/features/ui/components/image_loader.js b/app/javascript/flavours/glitch/features/ui/components/image_loader.js index aad594380e..e3e7197c54 100644 --- a/app/javascript/flavours/glitch/features/ui/components/image_loader.js +++ b/app/javascript/flavours/glitch/features/ui/components/image_loader.js @@ -7,7 +7,7 @@ export default class ImageLoader extends React.PureComponent { static propTypes = { alt: PropTypes.string, src: PropTypes.string.isRequired, - previewSrc: PropTypes.string.isRequired, + previewSrc: PropTypes.string, width: PropTypes.number, height: PropTypes.number, } @@ -47,7 +47,7 @@ export default class ImageLoader extends React.PureComponent { this.removeEventListeners(); this.setState({ loading: true, error: false }); Promise.all([ - this.loadPreviewCanvas(props), + props.previewSrc && this.loadPreviewCanvas(props), this.hasSize() && this.loadOriginalImage(props), ].filter(Boolean)) .then(() => { diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js index e56147c5bc..26c7e9ebcc 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -92,7 +92,7 @@ export default class MediaModal extends ImmutablePureComponent { const height = image.getIn(['meta', 'original', 'height']) || null; if (image.get('type') === 'image') { - return ; + return ; } else if (image.get('type') === 'gifv') { return ; } From 89f5ae00a587f50876398eadd0837e3b6d0f4668 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 8 Apr 2018 23:15:25 +0200 Subject: [PATCH 2/5] [Glitch] Improved media modal Port d6e88e29e2fc431c041082af1a374b9545f7cf23 to glitch-soc --- .../components/extended_video_player.js | 8 + .../features/ui/components/image_loader.js | 32 ++-- .../features/ui/components/media_modal.js | 84 ++++++++-- .../features/ui/components/video_modal.js | 2 +- .../features/ui/components/zoomable_image.js | 151 ++++++++++++++++++ .../glitch/styles/components/index.scss | 35 ++-- .../glitch/styles/components/media.scss | 88 +++++++--- .../glitch/styles/components/modal.scss | 23 --- 8 files changed, 330 insertions(+), 93 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/ui/components/zoomable_image.js diff --git a/app/javascript/flavours/glitch/components/extended_video_player.js b/app/javascript/flavours/glitch/components/extended_video_player.js index f8bd067e8e..9e2f6835a8 100644 --- a/app/javascript/flavours/glitch/components/extended_video_player.js +++ b/app/javascript/flavours/glitch/components/extended_video_player.js @@ -11,6 +11,7 @@ export default class ExtendedVideoPlayer extends React.PureComponent { time: PropTypes.number, controls: PropTypes.bool.isRequired, muted: PropTypes.bool.isRequired, + onClick: PropTypes.func, }; handleLoadedData = () => { @@ -31,6 +32,12 @@ export default class ExtendedVideoPlayer extends React.PureComponent { this.video = c; } + handleClick = e => { + e.stopPropagation(); + const handler = this.props.onClick; + if (handler) handler(); + } + render () { const { src, muted, controls, alt } = this.props; @@ -46,6 +53,7 @@ export default class ExtendedVideoPlayer extends React.PureComponent { muted={muted} controls={controls} loop={!controls} + onClick={this.handleClick} /> ); diff --git a/app/javascript/flavours/glitch/features/ui/components/image_loader.js b/app/javascript/flavours/glitch/features/ui/components/image_loader.js index e3e7197c54..c7360a7264 100644 --- a/app/javascript/flavours/glitch/features/ui/components/image_loader.js +++ b/app/javascript/flavours/glitch/features/ui/components/image_loader.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import ZoomableImage from './zoomable_image'; export default class ImageLoader extends React.PureComponent { @@ -10,6 +11,7 @@ export default class ImageLoader extends React.PureComponent { previewSrc: PropTypes.string, width: PropTypes.number, height: PropTypes.number, + onClick: PropTypes.func, } static defaultProps = { @@ -24,6 +26,7 @@ export default class ImageLoader extends React.PureComponent { } removers = []; + canvas = null; get canvasContext() { if (!this.canvas) { @@ -43,6 +46,10 @@ export default class ImageLoader extends React.PureComponent { } } + componentWillUnmount () { + this.removeEventListeners(); + } + loadImage (props) { this.removeEventListeners(); this.setState({ loading: true, error: false }); @@ -118,7 +125,7 @@ export default class ImageLoader extends React.PureComponent { } render () { - const { alt, src, width, height } = this.props; + const { alt, src, width, height, onClick } = this.props; const { loading } = this.state; const className = classNames('image-loader', { @@ -128,22 +135,19 @@ export default class ImageLoader extends React.PureComponent { return (
- - - {!loading && ( - {alt} + ) : ( + )}
); diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js index 26c7e9ebcc..5353b62dbf 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -3,6 +3,7 @@ import ReactSwipeableViews from 'react-swipeable-views'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import ExtendedVideoPlayer from 'flavours/glitch/components/extended_video_player'; +import classNames from 'classnames'; import { defineMessages, injectIntl } from 'react-intl'; import IconButton from 'flavours/glitch/components/icon_button'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -26,6 +27,7 @@ export default class MediaModal extends ImmutablePureComponent { state = { index: null, + navigationHidden: false, }; handleSwipe = (index) => { @@ -68,14 +70,21 @@ export default class MediaModal extends ImmutablePureComponent { return this.state.index !== null ? this.state.index : this.props.index; } + toggleNavigation = () => { + this.setState(prevState => ({ + navigationHidden: !prevState.navigationHidden, + })); + }; + render () { const { media, intl, onClose } = this.props; + const { navigationHidden } = this.state; const index = this.getIndex(); let pagination = []; - const leftNav = media.size > 1 && ; - const rightNav = media.size > 1 && ; + const leftNav = media.size > 1 && ; + const rightNav = media.size > 1 && ; if (media.size > 1) { pagination = media.map((item, i) => { @@ -92,9 +101,30 @@ export default class MediaModal extends ImmutablePureComponent { const height = image.getIn(['meta', 'original', 'height']) || null; if (image.get('type') === 'image') { - return ; + return ( + + ); } else if (image.get('type') === 'gifv') { - return ; + return ( + + ); } return null; @@ -104,21 +134,43 @@ export default class MediaModal extends ImmutablePureComponent { alignItems: 'center', // center vertically }; + const navigationClassName = classNames('media-modal__navigation', { + 'media-modal__navigation--hidden': navigationHidden, + }); + return (
- {leftNav} - -
- - - {content} - +
+
+ + {content} + +
+
+
+ + {leftNav} + {rightNav} +
    + {pagination} +
-
    - {pagination} -
- - {rightNav}
); } diff --git a/app/javascript/flavours/glitch/features/ui/components/video_modal.js b/app/javascript/flavours/glitch/features/ui/components/video_modal.js index 4412fd0f79..e0cb7fc095 100644 --- a/app/javascript/flavours/glitch/features/ui/components/video_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js @@ -16,7 +16,7 @@ export default class VideoModal extends ImmutablePureComponent { const { media, time, onClose } = this.props; return ( -
+
diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss index 31dbb7f58b..588e8d5584 100644 --- a/app/javascript/flavours/glitch/styles/components/media.scss +++ b/app/javascript/flavours/glitch/styles/components/media.scss @@ -171,8 +171,12 @@ img, canvas, video { - max-width: 100vw; - max-height: 100vh; + max-width: 100%; + /* + put margins on top and bottom of image to avoid the screen coverd by + image. + */ + max-height: 80%; width: auto; height: auto; margin: auto; @@ -184,11 +188,6 @@ background: url('~images/void.png') repeat; object-fit: contain; } - - .react-swipeable-view-container { - width: 100vw; - height: 100%; - } } .media-modal__closer { From c2b7080a6e455e9416dbe5307989fe71bf633ae0 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 9 Apr 2018 00:56:59 +0200 Subject: [PATCH 4/5] [Glitch] Refactor scss Port 480131a3767c9bc3d550b68698e82e16eb23efee to glitch-soc --- .../glitch/styles/components/index.scss | 28 ++++++++++++++----- .../glitch/styles/components/media.scss | 21 -------------- .../flavours/glitch/styles/variables.scss | 5 ++++ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index ad446f18b6..afb54056c8 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -355,14 +355,19 @@ position: relative; width: 100%; height: 100%; + display: flex; + align-items: center; + justify-content: center; - &.image-loader--loading { - display: flex; - align-content: center; + .image-loader__preview-canvas { + max-width: $media-modal-media-max-width; + max-height: $media-modal-media-max-height; + background: url('~images/void.png') repeat; + object-fit: contain; + } - .image-loader__preview-canvas { - filter: blur(2px); - } + &.image-loader--loading .image-loader__preview-canvas { + filter: blur(2px); } &.image-loader--amorphous .image-loader__preview-canvas { @@ -375,7 +380,16 @@ width: 100%; height: 100%; display: flex; - align-content: center; + align-items: center; + justify-content: center; + + img { + max-width: $media-modal-media-max-width; + max-height: $media-modal-media-max-height; + width: auto; + height: auto; + object-fit: contain; + } } .dropdown { diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss index 588e8d5584..f029405936 100644 --- a/app/javascript/flavours/glitch/styles/components/media.scss +++ b/app/javascript/flavours/glitch/styles/components/media.scss @@ -167,27 +167,6 @@ width: 100%; height: 100%; position: relative; - - img, - canvas, - video { - max-width: 100%; - /* - put margins on top and bottom of image to avoid the screen coverd by - image. - */ - max-height: 80%; - width: auto; - height: auto; - margin: auto; - } - - img, - canvas { - display: block; - background: url('~images/void.png') repeat; - object-fit: contain; - } } .media-modal__closer { diff --git a/app/javascript/flavours/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss index e8e2bc9e3e..e3ba725c44 100644 --- a/app/javascript/flavours/glitch/styles/variables.scss +++ b/app/javascript/flavours/glitch/styles/variables.scss @@ -31,6 +31,11 @@ $ui-highlight-color: $classic-highlight-color !default; // Vibrant // Language codes that uses CJK fonts $cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW; +// Variables for components +$media-modal-media-max-width: 100%; +// put margins on top and bottom of image to avoid the screen covered by image. +$media-modal-media-max-height: 80%; + // Avatar border size (8% default, 100% for rounded avatars) $ui-avatar-border-size: 8%; From d8dea31e0c56f6146ae93a27443e104828c555e8 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 9 Apr 2018 00:42:26 +0200 Subject: [PATCH 5/5] [Glitch] Fix video player height Port 5eea3f987767610b47f32b367f517f327e239dd5 to glitch-soc --- .../glitch/styles/components/media.scss | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss index f029405936..03e7aba67f 100644 --- a/app/javascript/flavours/glitch/styles/components/media.scss +++ b/app/javascript/flavours/glitch/styles/components/media.scss @@ -161,6 +161,19 @@ max-width: 100vw; max-height: 100vh; position: relative; + + .extended-video-player { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + + video { + max-width: $media-modal-media-max-width; + max-height: $media-modal-media-max-height; + } + } } .media-modal { @@ -274,8 +287,8 @@ @include fullwidth-gallery; video { - height: 100%; - width: 100%; + max-width: 100vw; + max-height: 80vh; z-index: 1; object-fit: cover; position: relative;