From 7a68079b3fc0c80238451eb1f0264ce66e495502 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 20 Apr 2018 15:58:36 +0200 Subject: [PATCH] [Glitch] Show media modal on public pages Port ff7941e652af1d54d9c991254556e7932a8b183c to glitch-soc --- .../glitch/components/media_gallery.js | 6 +- .../flavours/glitch/components/modal_root.js | 84 +++++++++++++++++++ .../containers/media_galleries_container.js | 68 +++++++++++++++ .../containers/media_gallery_container.js | 34 -------- .../features/ui/components/modal_root.js | 79 ++--------------- .../flavours/glitch/packs/public.js | 16 ++-- .../glitch/styles/components/modal.scss | 5 +- .../flavours/glitch/styles/containers.scss | 4 + 8 files changed, 178 insertions(+), 118 deletions(-) create mode 100644 app/javascript/flavours/glitch/components/modal_root.js create mode 100644 app/javascript/flavours/glitch/containers/media_galleries_container.js delete mode 100644 app/javascript/flavours/glitch/containers/media_gallery_container.js diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index 309308d25ad..603aebc8642 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -33,10 +33,6 @@ const messages = defineMessages({ class Item extends React.PureComponent { - static contextTypes = { - router: PropTypes.object, - }; - static propTypes = { attachment: ImmutablePropTypes.map.isRequired, standalone: PropTypes.bool, @@ -73,7 +69,7 @@ class Item extends React.PureComponent { handleClick = (e) => { const { index, onClick } = this.props; - if (this.context.router && e.button === 0) { + if (e.button === 0) { e.preventDefault(); onClick(index); } diff --git a/app/javascript/flavours/glitch/components/modal_root.js b/app/javascript/flavours/glitch/components/modal_root.js new file mode 100644 index 00000000000..789e117c705 --- /dev/null +++ b/app/javascript/flavours/glitch/components/modal_root.js @@ -0,0 +1,84 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class ModalRoot extends React.PureComponent { + + static propTypes = { + children: PropTypes.node, + onClose: PropTypes.func.isRequired, + }; + + state = { + revealed: !!this.props.children, + }; + + activeElement = this.state.revealed ? document.activeElement : null; + + handleKeyUp = (e) => { + if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) + && !!this.props.children && !this.props.props.noEsc) { + this.props.onClose(); + } + } + + componentDidMount () { + window.addEventListener('keyup', this.handleKeyUp, false); + } + + componentWillReceiveProps (nextProps) { + if (!!nextProps.children && !this.props.children) { + this.activeElement = document.activeElement; + + this.getSiblings().forEach(sibling => sibling.setAttribute('inert', true)); + } else if (!nextProps.children) { + this.setState({ revealed: false }); + } + } + + componentDidUpdate (prevProps) { + if (!this.props.children && !!prevProps.children) { + this.getSiblings().forEach(sibling => sibling.removeAttribute('inert')); + this.activeElement.focus(); + this.activeElement = null; + } + if (this.props.children) { + requestAnimationFrame(() => { + this.setState({ revealed: true }); + }); + } + } + + componentWillUnmount () { + window.removeEventListener('keyup', this.handleKeyUp); + } + + getSiblings = () => { + return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node); + } + + setRef = ref => { + this.node = ref; + } + + render () { + const { children, onClose } = this.props; + const { revealed } = this.state; + const visible = !!children; + + if (!visible) { + return ( +
+ ); + } + + return ( +
+
+
+
{children}
+
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/containers/media_galleries_container.js b/app/javascript/flavours/glitch/containers/media_galleries_container.js new file mode 100644 index 00000000000..a694578821e --- /dev/null +++ b/app/javascript/flavours/glitch/containers/media_galleries_container.js @@ -0,0 +1,68 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import PropTypes from 'prop-types'; +import { IntlProvider, addLocaleData } from 'react-intl'; +import { getLocale } from 'mastodon/locales'; +import MediaGallery from 'flavours/glitch/components/media_gallery'; +import ModalRoot from 'flavours/glitch/components/modal_root'; +import MediaModal from 'flavours/glitch/features/ui/components/media_modal'; +import { fromJS } from 'immutable'; + +const { localeData, messages } = getLocale(); +addLocaleData(localeData); + +export default class MediaGalleriesContainer extends React.PureComponent { + + static propTypes = { + locale: PropTypes.string.isRequired, + galleries: PropTypes.object.isRequired, + }; + + state = { + media: null, + index: null, + }; + + handleOpenMedia = (media, index) => { + document.body.classList.add('media-gallery-standalone__body'); + this.setState({ media, index }); + } + + handleCloseMedia = () => { + document.body.classList.remove('media-gallery-standalone__body'); + this.setState({ media: null, index: null }); + } + + render () { + const { locale, galleries } = this.props; + + return ( + + + {[].map.call(galleries, gallery => { + const { media, ...props } = JSON.parse(gallery.getAttribute('data-props')); + + return ReactDOM.createPortal( + , + gallery + ); + })} + + {this.state.media === null || this.state.index === null ? null : ( + + )} + + + + ); + } + +} diff --git a/app/javascript/flavours/glitch/containers/media_gallery_container.js b/app/javascript/flavours/glitch/containers/media_gallery_container.js deleted file mode 100644 index 54bfbf4535a..00000000000 --- a/app/javascript/flavours/glitch/containers/media_gallery_container.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import { getLocale } from 'mastodon/locales'; -import MediaGallery from 'flavours/glitch/components/media_gallery'; -import { fromJS } from 'immutable'; - -const { localeData, messages } = getLocale(); -addLocaleData(localeData); - -export default class MediaGalleryContainer extends React.PureComponent { - - static propTypes = { - locale: PropTypes.string.isRequired, - media: PropTypes.array.isRequired, - }; - - handleOpenMedia = () => {} - - render () { - const { locale, media, ...props } = this.props; - - return ( - - - - ); - } - -} diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index e12ee1761d7..320c039a4df 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import Base from '../../../components/modal_root'; import BundleContainer from '../containers/bundle_container'; import BundleModalError from './bundle_modal_error'; import ModalLoading from './modal_loading'; @@ -43,56 +44,6 @@ export default class ModalRoot extends React.PureComponent { onClose: PropTypes.func.isRequired, }; - state = { - revealed: false, - }; - - handleKeyUp = (e) => { - if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) - && !!this.props.type && !this.props.props.noEsc) { - this.props.onClose(); - } - } - - componentDidMount () { - window.addEventListener('keyup', this.handleKeyUp, false); - } - - componentWillReceiveProps (nextProps) { - if (!!nextProps.type && !this.props.type) { - this.activeElement = document.activeElement; - - this.getSiblings().forEach(sibling => sibling.setAttribute('inert', true)); - } else if (!nextProps.type) { - this.setState({ revealed: false }); - } - } - - componentDidUpdate (prevProps) { - if (!this.props.type && !!prevProps.type) { - this.getSiblings().forEach(sibling => sibling.removeAttribute('inert')); - this.activeElement.focus(); - this.activeElement = null; - } - if (this.props.type) { - requestAnimationFrame(() => { - this.setState({ revealed: true }); - }); - } - } - - componentWillUnmount () { - window.removeEventListener('keyup', this.handleKeyUp); - } - - getSiblings = () => { - return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node); - } - - setRef = ref => { - this.node = ref; - } - renderLoading = modalId => () => { return ['MEDIA', 'VIDEO', 'BOOST', 'FAVOURITE', 'DOODLE', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? : null; } @@ -105,30 +56,16 @@ export default class ModalRoot extends React.PureComponent { render () { const { type, props, onClose } = this.props; - const { revealed } = this.state; const visible = !!type; - if (!visible) { - return ( -
- ); - } - return ( -
-
-
-
- { - visible ? - ( - {(SpecificComponent) => } - ) : - null - } -
-
-
+ + {visible && ( + + {(SpecificComponent) => } + + )} + ); } diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index 9ea82b53aa2..ed685b6b767 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -7,7 +7,6 @@ function main() { const { getLocale } = require('locales'); const { localeData } = getLocale(); const VideoContainer = require('flavours/glitch/containers/video_container').default; - const MediaGalleryContainer = require('flavours/glitch/containers/media_gallery_container').default; const CardContainer = require('flavours/glitch/containers/card_container').default; const React = require('react'); const ReactDOM = require('react-dom'); @@ -58,15 +57,20 @@ function main() { ReactDOM.render(, content); }); - [].forEach.call(document.querySelectorAll('[data-component="MediaGallery"]'), (content) => { - const props = JSON.parse(content.getAttribute('data-props')); - ReactDOM.render(, content); - }); - [].forEach.call(document.querySelectorAll('[data-component="Card"]'), (content) => { const props = JSON.parse(content.getAttribute('data-props')); ReactDOM.render(, content); }); + + const mediaGalleries = document.querySelectorAll('[data-component="MediaGallery"]'); + + if (mediaGalleries.length > 0) { + const MediaGalleriesContainer = require('flavours/glitch/containers/media_galleries_container').default; + const content = document.createElement('div'); + + ReactDOM.render(, content); + document.body.appendChild(content); + } }); } diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss index 4f0d6e1bc20..2eb80aba83b 100644 --- a/app/javascript/flavours/glitch/styles/components/modal.scss +++ b/app/javascript/flavours/glitch/styles/components/modal.scss @@ -3,13 +3,14 @@ } .modal-root { + position: relative; transition: opacity 0.3s linear; will-change: opacity; z-index: 9999; } .modal-root__overlay { - position: absolute; + position: fixed; top: 0; left: 0; right: 0; @@ -18,7 +19,7 @@ } .modal-root__container { - position: absolute; + position: fixed; top: 0; left: 0; width: 100%; diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index 6fa1fa38f51..e761f58eb28 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -60,6 +60,10 @@ } } +.media-gallery-standalone__body { + overflow: hidden; +} + .account-header { width: 400px; margin: 0 auto;