diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2020-11-27 03:24:11 +0100 |
---|---|---|
committer | Claire <claire.github-309c@sitedethib.com> | 2021-05-07 22:47:09 +0200 |
commit | 50b100df00dc03d554acc9f3ca6f5845edcadbd2 (patch) | |
tree | 1012485be58ecacf762865f8ea21595daafc4e69 /app/javascript/flavours/glitch/features/ui | |
parent | d30dd5b1dbbc8e72cd7aefe5ee39684e068b7118 (diff) |
Change media modals look in web UI
Port 1e89e2ed988d2103ecd46e06476d863cb40c57c7 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
Diffstat (limited to 'app/javascript/flavours/glitch/features/ui')
3 files changed, 158 insertions, 49 deletions
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 e37df7208..7b07c557f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -4,12 +4,13 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import Video from 'flavours/glitch/features/video'; import classNames from 'classnames'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, injectIntl } from 'react-intl'; import IconButton from 'flavours/glitch/components/icon_button'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ImageLoader from './image_loader'; import Icon from 'flavours/glitch/components/icon'; import GIFV from 'flavours/glitch/components/gifv'; +import Footer from 'flavours/glitch/features/picture_in_picture/components/footer'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -17,6 +18,111 @@ const messages = defineMessages({ next: { id: 'lightbox.next', defaultMessage: 'Next' }, }); +const digitCharacters = [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '#', + '$', + '%', + '*', + '+', + ',', + '-', + '.', + ':', + ';', + '=', + '?', + '@', + '[', + ']', + '^', + '_', + '{', + '|', + '}', + '~', +]; + +const decode83 = (str) => { + let value = 0; + let c, digit; + + for (let i = 0; i < str.length; i++) { + c = str[i]; + digit = digitCharacters.indexOf(c); + value = value * 83 + digit; + } + + return value; +}; + +const decodeRGB = int => ({ + r: Math.max(0, (int >> 16)), + g: Math.max(0, (int >> 8) & 255), + b: Math.max(0, (int & 255)), +}); + export default @injectIntl class MediaModal extends ImmutablePureComponent { @@ -26,10 +132,11 @@ class MediaModal extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.list.isRequired, - status: ImmutablePropTypes.map, + statusId: PropTypes.string, index: PropTypes.number.isRequired, onClose: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, + onChangeBackgroundColor: PropTypes.func.isRequired, }; state = { @@ -64,6 +171,7 @@ class MediaModal extends ImmutablePureComponent { handleChangeIndex = (e) => { const index = Number(e.currentTarget.getAttribute('data-index')); + this.setState({ index: index % this.props.media.size, zoomButtonHidden: true, @@ -87,10 +195,12 @@ class MediaModal extends ImmutablePureComponent { componentDidMount () { window.addEventListener('keydown', this.handleKeyDown, false); + this._sendBackgroundColor(); } componentWillUnmount () { window.removeEventListener('keydown', this.handleKeyDown); + this.props.onChangeBackgroundColor(null); } getIndex () { @@ -106,30 +216,35 @@ class MediaModal extends ImmutablePureComponent { handleStatusClick = e => { if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { e.preventDefault(); - this.context.router.history.push(`/statuses/${this.props.status.get('id')}`); + this.context.router.history.push(`/statuses/${this.props.statusId}`); } + + this._sendBackgroundColor(); + } + + componentDidUpdate (prevProps, prevState) { + if (prevState.index !== this.state.index) { + this._sendBackgroundColor(); + } + } + + _sendBackgroundColor () { + const { media, onChangeBackgroundColor } = this.props; + const index = this.getIndex(); + const backgroundColor = decodeRGB(decode83(media.getIn([index, 'blurhash']).slice(2, 6))); + + onChangeBackgroundColor(backgroundColor); } render () { - const { media, status, intl, onClose } = this.props; + const { media, statusId, intl, onClose } = this.props; const { navigationHidden } = this.state; const index = this.getIndex(); - let pagination = []; const leftNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>; const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>; - if (media.size > 1) { - pagination = media.map((item, i) => { - const classes = ['media-modal__button']; - if (i === index) { - classes.push('media-modal__button--active'); - } - return (<li className='media-modal__page-dot' key={i}><button tabIndex='0' className={classes.join(' ')} onClick={this.handleChangeIndex} data-index={i}>{i + 1}</button></li>); - }); - } - const content = media.map((image) => { const width = image.getIn(['meta', 'original', 'width']) || null; const height = image.getIn(['meta', 'original', 'height']) || null; @@ -197,13 +312,19 @@ class MediaModal extends ImmutablePureComponent { 'media-modal__navigation--hidden': navigationHidden, }); + let pagination; + + if (media.size > 1) { + pagination = media.map((item, i) => ( + <button key={i} className={classNames('media-modal__page-dot', { active: i === index })} data-index={i} onClick={this.handleChangeIndex}> + {i + 1} + </button> + )); + } + return ( <div className='modal-root__modal media-modal'> - <div - className='media-modal__closer' - role='presentation' - onClick={onClose} - > + <div className='media-modal__closer' role='presentation' onClick={onClose} > <ReactSwipeableViews style={swipeableViewsStyle} containerStyle={containerStyle} @@ -221,15 +342,10 @@ class MediaModal extends ImmutablePureComponent { {leftNav} {rightNav} - {status && ( - <div className={classNames('media-modal__meta', { 'media-modal__meta--shifted': media.size > 1 })}> - <a href={status.get('url')} onClick={this.handleStatusClick}><Icon id='comments' /> <FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> - </div> - )} - - <ul className='media-modal__pagination'> - {pagination} - </ul> + <div className='media-modal__overlay'> + {pagination && <ul className='media-modal__pagination'>{pagination}</ul>} + {statusId && <Footer statusId={statusId} withOpenButton onClose={onClose} />} + </div> </div> </div> ); 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 488daf0cc..0fd70de34 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -55,6 +55,10 @@ export default class ModalRoot extends React.PureComponent { onClose: PropTypes.func.isRequired, }; + state = { + backgroundColor: null, + }; + getSnapshotBeforeUpdate () { return { visible: !!this.props.type }; } @@ -69,6 +73,10 @@ export default class ModalRoot extends React.PureComponent { } } + setBackgroundColor = color => { + this.setState({ backgroundColor: color }); + } + renderLoading = modalId => () => { return ['MEDIA', 'VIDEO', 'BOOST', 'FAVOURITE', 'DOODLE', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null; } @@ -81,13 +89,14 @@ export default class ModalRoot extends React.PureComponent { render () { const { type, props, onClose } = this.props; + const { backgroundColor } = this.state; const visible = !!type; return ( - <Base onClose={onClose} noEsc={props ? props.noEsc : false}> + <Base backgroundColor={backgroundColor} onClose={onClose} noEsc={props ? props.noEsc : false}> {visible && ( <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}> - {(SpecificComponent) => <SpecificComponent {...props} onClose={onClose} />} + {(SpecificComponent) => <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={onClose} />} </BundleContainer> )} </Base> 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 b0a4f3f03..62273f252 100644 --- a/app/javascript/flavours/glitch/features/ui/components/video_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js @@ -3,9 +3,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import Video from 'flavours/glitch/features/video'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { FormattedMessage } from 'react-intl'; -import classNames from 'classnames'; -import Icon from 'flavours/glitch/components/icon'; export default class VideoModal extends ImmutablePureComponent { @@ -15,7 +12,7 @@ export default class VideoModal extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.map.isRequired, - status: ImmutablePropTypes.map, + statusId: PropTypes.string, options: PropTypes.shape({ startTime: PropTypes.number, autoPlay: PropTypes.bool, @@ -24,15 +21,8 @@ export default class VideoModal extends ImmutablePureComponent { onClose: PropTypes.func.isRequired, }; - handleStatusClick = e => { - if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { - e.preventDefault(); - this.context.router.history.push(`/statuses/${this.props.status.get('id')}`); - } - } - render () { - const { media, status, onClose } = this.props; + const { media, onClose } = this.props; const options = this.props.options || {}; return ( @@ -51,12 +41,6 @@ export default class VideoModal extends ImmutablePureComponent { alt={media.get('description')} /> </div> - - {status && ( - <div className={classNames('media-modal__meta')}> - <a href={status.get('url')} onClick={this.handleStatusClick}><Icon id='comments' /> <FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> - </div> - )} </div> ); } |