diff options
Diffstat (limited to 'app/javascript/flavours/glitch/components')
8 files changed, 138 insertions, 90 deletions
diff --git a/app/javascript/flavours/glitch/components/column_back_button.js b/app/javascript/flavours/glitch/components/column_back_button.js index 8326cbb79..05688f867 100644 --- a/app/javascript/flavours/glitch/components/column_back_button.js +++ b/app/javascript/flavours/glitch/components/column_back_button.js @@ -41,7 +41,19 @@ export default class ColumnBackButton extends React.PureComponent { if (multiColumn) { return component; } else { - return createPortal(component, document.getElementById('tabs-bar__portal')); + // The portal container and the component may be rendered to the DOM in + // the same React render pass, so the container might not be available at + // the time `render()` is called. + const container = document.getElementById('tabs-bar__portal'); + if (container === null) { + // The container wasn't available, force a re-render so that the + // component can eventually be inserted in the container and not scroll + // with the rest of the area. + this.forceUpdate(); + return component; + } else { + return createPortal(component, container); + } } } diff --git a/app/javascript/flavours/glitch/components/column_header.js b/app/javascript/flavours/glitch/components/column_header.js index 43c9f1144..dd1162429 100644 --- a/app/javascript/flavours/glitch/components/column_header.js +++ b/app/javascript/flavours/glitch/components/column_header.js @@ -235,7 +235,19 @@ class ColumnHeader extends React.PureComponent { if (multiColumn || placeholder) { return component; } else { - return createPortal(component, document.getElementById('tabs-bar__portal')); + // The portal container and the component may be rendered to the DOM in + // the same React render pass, so the container might not be available at + // the time `render()` is called. + const container = document.getElementById('tabs-bar__portal'); + if (container === null) { + // The container wasn't available, force a re-render so that the + // component can eventually be inserted in the container and not scroll + // with the rest of the area. + this.forceUpdate(); + return component; + } else { + return createPortal(component, container); + } } } diff --git a/app/javascript/flavours/glitch/components/extended_video_player.js b/app/javascript/flavours/glitch/components/extended_video_player.js deleted file mode 100644 index 009c0d559..000000000 --- a/app/javascript/flavours/glitch/components/extended_video_player.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class ExtendedVideoPlayer extends React.PureComponent { - - static propTypes = { - src: PropTypes.string.isRequired, - alt: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number, - time: PropTypes.number, - controls: PropTypes.bool.isRequired, - muted: PropTypes.bool.isRequired, - onClick: PropTypes.func, - }; - - handleLoadedData = () => { - if (this.props.time) { - this.video.currentTime = this.props.time; - } - } - - componentDidMount () { - this.video.addEventListener('loadeddata', this.handleLoadedData); - } - - componentWillUnmount () { - this.video.removeEventListener('loadeddata', this.handleLoadedData); - } - - setRef = (c) => { - this.video = c; - } - - handleClick = e => { - e.stopPropagation(); - const handler = this.props.onClick; - if (handler) handler(); - } - - render () { - const { src, muted, controls, alt } = this.props; - - return ( - <div className='extended-video-player'> - <video - ref={this.setRef} - src={src} - autoPlay - role='button' - tabIndex='0' - aria-label={alt} - title={alt} - muted={muted} - controls={controls} - loop={!controls} - onClick={this.handleClick} - /> - </div> - ); - } - -} diff --git a/app/javascript/flavours/glitch/components/gifv.js b/app/javascript/flavours/glitch/components/gifv.js new file mode 100644 index 000000000..83cfae49c --- /dev/null +++ b/app/javascript/flavours/glitch/components/gifv.js @@ -0,0 +1,75 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class GIFV extends React.PureComponent { + + static propTypes = { + src: PropTypes.string.isRequired, + alt: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + onClick: PropTypes.func, + }; + + state = { + loading: true, + }; + + handleLoadedData = () => { + this.setState({ loading: false }); + } + + componentWillReceiveProps (nextProps) { + if (nextProps.src !== this.props.src) { + this.setState({ loading: true }); + } + } + + handleClick = e => { + const { onClick } = this.props; + + if (onClick) { + e.stopPropagation(); + onClick(); + } + } + + render () { + const { src, width, height, alt } = this.props; + const { loading } = this.state; + + return ( + <div className='gifv' style={{ position: 'relative' }}> + {loading && ( + <canvas + width={width} + height={height} + role='button' + tabIndex='0' + aria-label={alt} + title={alt} + onClick={this.handleClick} + /> + )} + + <video + src={src} + width={width} + height={height} + role='button' + tabIndex='0' + aria-label={alt} + title={alt} + muted + loop + autoPlay + playsInline + onClick={this.handleClick} + onLoadedData={this.handleLoadedData} + style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }} + /> + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/components/missing_indicator.js b/app/javascript/flavours/glitch/components/missing_indicator.js index 70d8c3b98..ee5bf7c1e 100644 --- a/app/javascript/flavours/glitch/components/missing_indicator.js +++ b/app/javascript/flavours/glitch/components/missing_indicator.js @@ -1,17 +1,24 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; +import illustration from 'flavours/glitch/images/elephant_ui_disappointed.svg'; +import classNames from 'classnames'; -const MissingIndicator = () => ( - <div className='regeneration-indicator missing-indicator'> - <div> - <div className='regeneration-indicator__figure' /> +const MissingIndicator = ({ fullPage }) => ( + <div className={classNames('regeneration-indicator', { 'regeneration-indicator--without-header': fullPage })}> + <div className='regeneration-indicator__figure'> + <img src={illustration} alt='' /> + </div> - <div className='regeneration-indicator__label'> - <FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' /> - <FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' /> - </div> + <div className='regeneration-indicator__label'> + <FormattedMessage id='missing_indicator.label' tagName='strong' defaultMessage='Not found' /> + <FormattedMessage id='missing_indicator.sublabel' defaultMessage='This resource could not be found' /> </div> </div> ); +MissingIndicator.propTypes = { + fullPage: PropTypes.bool, +}; + export default MissingIndicator; diff --git a/app/javascript/flavours/glitch/components/regeneration_indicator.js b/app/javascript/flavours/glitch/components/regeneration_indicator.js new file mode 100644 index 000000000..f4e0a79ef --- /dev/null +++ b/app/javascript/flavours/glitch/components/regeneration_indicator.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import illustration from 'flavours/glitch/images/elephant_ui_working.svg'; + +const MissingIndicator = () => ( + <div className='regeneration-indicator'> + <div className='regeneration-indicator__figure'> + <img src={illustration} alt='' /> + </div> + + <div className='regeneration-indicator__label'> + <FormattedMessage id='regeneration_indicator.label' tagName='strong' defaultMessage='Loading…' /> + <FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' /> + </div> + </div> +); + +export default MissingIndicator; diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index 209350440..da8b787ba 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -315,7 +315,7 @@ export default class StatusContent extends React.PureComponent { <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }} > - <span dangerouslySetInnerHTML={spoilerContent} lang={status.get('language')} /> + <span dangerouslySetInnerHTML={spoilerContent} /> {' '} <button tabIndex='0' className='status__content__spoiler-link' onClick={this.handleSpoilerClick}> {toggleText} @@ -332,7 +332,6 @@ export default class StatusContent extends React.PureComponent { tabIndex={!hidden ? 0 : null} dangerouslySetInnerHTML={content} className='status__content__text' - lang={status.get('language')} /> {media} </div> @@ -353,7 +352,6 @@ export default class StatusContent extends React.PureComponent { ref={this.setContentsRef} key={`contents-${tagLinks}-${rewriteMentions}`} dangerouslySetInnerHTML={content} - lang={status.get('language')} className='status__content__text' tabIndex='0' /> @@ -368,7 +366,7 @@ export default class StatusContent extends React.PureComponent { tabIndex='0' ref={this.setRef} > - <div ref={this.setContentsRef} key={`contents-${tagLinks}`} className='status__content__text' dangerouslySetInnerHTML={content} lang={status.get('language')} tabIndex='0' /> + <div ref={this.setContentsRef} key={`contents-${tagLinks}`} className='status__content__text' dangerouslySetInnerHTML={content} tabIndex='0' /> {media} </div> ); diff --git a/app/javascript/flavours/glitch/components/status_list.js b/app/javascript/flavours/glitch/components/status_list.js index c1f51b307..a399ff567 100644 --- a/app/javascript/flavours/glitch/components/status_list.js +++ b/app/javascript/flavours/glitch/components/status_list.js @@ -6,7 +6,7 @@ import StatusContainer from 'flavours/glitch/containers/status_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import LoadGap from './load_gap'; import ScrollableList from './scrollable_list'; -import { FormattedMessage } from 'react-intl'; +import RegenerationIndicator from 'flavours/glitch/components/regeneration_indicator'; export default class StatusList extends ImmutablePureComponent { @@ -81,18 +81,7 @@ export default class StatusList extends ImmutablePureComponent { const { isLoading, isPartial } = other; if (isPartial) { - return ( - <div className='regeneration-indicator'> - <div> - <div className='regeneration-indicator__figure' /> - - <div className='regeneration-indicator__label'> - <FormattedMessage id='regeneration_indicator.label' tagName='strong' defaultMessage='Loading…' /> - <FormattedMessage id='regeneration_indicator.sublabel' defaultMessage='Your home feed is being prepared!' /> - </div> - </div> - </div> - ); + return <RegenerationIndicator />; } let scrollableContent = (isLoading || statusIds.size > 0) ? ( |