diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2019-08-14 04:07:32 +0200 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2019-08-19 21:56:25 +0200 |
commit | ab019800f8862a84eab679ea5848c3df0531ddc9 (patch) | |
tree | 85334d309f0353649614b0da9b7fb167b0427a15 /app/javascript/flavours/glitch/features/ui | |
parent | f8e7c69861e0ec3fac8d7f416c8bff7148824dc0 (diff) |
[Glitch] Add media editing modal
Port 23f7afa562c49b24e979505680463bc712b11d94 to glitch-soc Signed-off-by: Thibaut Girka <thib@sitedethib.com>
Diffstat (limited to 'app/javascript/flavours/glitch/features/ui')
-rw-r--r-- | app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js | 129 |
1 files changed, 105 insertions, 24 deletions
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js index 57c92cc66..de87ba83f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js @@ -1,11 +1,21 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import ImageLoader from './image_loader'; import classNames from 'classnames'; import { changeUploadCompose } from 'flavours/glitch/actions/compose'; import { getPointerPosition } from 'flavours/glitch/features/video'; +import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; +import IconButton from 'flavours/glitch/components/icon_button'; +import Button from 'flavours/glitch/components/button'; +import Video from 'flavours/glitch/features/video'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' }, + apply: { id: 'upload_modal.apply', defaultMessage: 'Apply' }, + placeholder: { id: 'upload_modal.description_placeholder', defaultMessage: 'A quick brown fox jumps over the lazy dog' }, +}); const mapStateToProps = (state, { id }) => ({ media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id), @@ -13,17 +23,20 @@ const mapStateToProps = (state, { id }) => ({ const mapDispatchToProps = (dispatch, { id }) => ({ - onSave: (x, y) => { - dispatch(changeUploadCompose(id, { focus: `${x.toFixed(2)},${y.toFixed(2)}` })); + onSave: (description, x, y) => { + dispatch(changeUploadCompose(id, { description, focus: `${x.toFixed(2)},${y.toFixed(2)}` })); }, }); -@connect(mapStateToProps, mapDispatchToProps) -export default class FocalPointModal extends ImmutablePureComponent { +export default @connect(mapStateToProps, mapDispatchToProps) +@injectIntl +class FocalPointModal extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.map.isRequired, + onClose: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, }; state = { @@ -32,6 +45,8 @@ export default class FocalPointModal extends ImmutablePureComponent { focusX: 0, focusY: 0, dragging: false, + description: '', + dirty: false, }; componentWillMount () { @@ -66,7 +81,6 @@ export default class FocalPointModal extends ImmutablePureComponent { document.removeEventListener('mouseup', this.handleMouseUp); this.setState({ dragging: false }); - this.props.onSave(this.state.focusX, this.state.focusY); } updatePosition = e => { @@ -74,46 +88,113 @@ export default class FocalPointModal extends ImmutablePureComponent { const focusX = (x - .5) * 2; const focusY = (y - .5) * -2; - this.setState({ x, y, focusX, focusY }); + this.setState({ x, y, focusX, focusY, dirty: true }); } updatePositionFromMedia = media => { - const focusX = media.getIn(['meta', 'focus', 'x']); - const focusY = media.getIn(['meta', 'focus', 'y']); + const focusX = media.getIn(['meta', 'focus', 'x']); + const focusY = media.getIn(['meta', 'focus', 'y']); + const description = media.get('description') || ''; if (focusX && focusY) { const x = (focusX / 2) + .5; const y = (focusY / -2) + .5; - this.setState({ x, y, focusX, focusY }); + this.setState({ + x, + y, + focusX, + focusY, + description, + dirty: false, + }); } else { - this.setState({ x: 0.5, y: 0.5, focusX: 0, focusY: 0 }); + this.setState({ + x: 0.5, + y: 0.5, + focusX: 0, + focusY: 0, + description, + dirty: false, + }); } } + handleChange = e => { + this.setState({ description: e.target.value, dirty: true }); + } + + handleSubmit = () => { + this.props.onSave(this.state.description, this.state.focusX, this.state.focusY); + this.props.onClose(); + } + setRef = c => { this.node = c; } render () { - const { media } = this.props; - const { x, y, dragging } = this.state; + const { media, intl, onClose } = this.props; + const { x, y, dragging, description, dirty } = this.state; const width = media.getIn(['meta', 'original', 'width']) || null; const height = media.getIn(['meta', 'original', 'height']) || null; + const focals = ['image', 'gifv'].includes(media.get('type')); + + const previewRatio = 16/9; + const previewWidth = 200; + const previewHeight = previewWidth / previewRatio; return ( - <div className='modal-root__modal video-modal focal-point-modal'> - <div className={classNames('focal-point', { dragging })} ref={this.setRef}> - <ImageLoader - previewSrc={media.get('preview_url')} - src={media.get('url')} - width={width} - height={height} - /> - - <div className='focal-point__reticle' style={{ top: `${y * 100}%`, left: `${x * 100}%` }} /> - <div className='focal-point__overlay' onMouseDown={this.handleMouseDown} /> + <div className='modal-root__modal report-modal' style={{ maxWidth: 960 }}> + <div className='report-modal__target'> + <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} /> + <FormattedMessage id='upload_modal.edit_media' defaultMessage='Edit media' /> + </div> + + <div className='report-modal__container'> + <div className='report-modal__comment'> + {focals && <p><FormattedMessage id='upload_modal.hint' defaultMessage='Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.' /></p>} + + <label className='setting-text-label' htmlFor='upload-modal__description'><FormattedMessage id='upload_form.description' defaultMessage='Describe for the visually impaired' /></label> + + <textarea + id='upload-modal__description' + className='setting-text light' + value={description} + onChange={this.handleChange} + autoFocus + /> + + <Button disabled={!dirty} text={intl.formatMessage(messages.apply)} onClick={this.handleSubmit} /> + </div> + + <div className='report-modal__statuses'> + {focals && ( + <div className={classNames('focal-point', { dragging })} ref={this.setRef}> + {media.get('type') === 'image' && <img src={media.get('url')} width={width} height={height} alt='' />} + {media.get('type') === 'gifv' && <video src={media.get('url')} width={width} height={height} loop muted autoPlay />} + + <div className='focal-point__preview'> + <strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong> + <div style={{ width: previewWidth, height: previewHeight, backgroundImage: `url(${media.get('preview_url')})`, backgroundSize: 'cover', backgroundPosition: `${x * 100}% ${y * 100}%` }} /> + </div> + + <div className='focal-point__reticle' style={{ top: `${y * 100}%`, left: `${x * 100}%` }} /> + <div className='focal-point__overlay' onMouseDown={this.handleMouseDown} /> + </div> + )} + + {['audio', 'video'].includes(media.get('type')) && ( + <Video + preview={media.get('preview_url')} + blurhash={media.get('blurhash')} + src={media.get('url')} + detailed + editable + /> + )} + </div> </div> </div> ); |