diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2017-09-28 15:31:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-28 15:31:31 +0200 |
commit | 4ec1771165ab8dd40e52804fd087eacfab25290b (patch) | |
tree | e356a5477ee1790367a9b8981fdf5f6419540f88 /app/javascript/mastodon/features/compose/components/upload.js | |
parent | 3d9b8847d21d886886baae483304288139669795 (diff) | |
download | mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar.gz mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.tar.bz2 mastodon-4ec1771165ab8dd40e52804fd087eacfab25290b.zip |
Add ability to specify alternative text for media attachments (#5123)
* Fix #117 - Add ability to specify alternative text for media attachments
- POST /api/v1/media accepts `description` straight away
- PUT /api/v1/media/:id to update `description` (only for unattached ones)
- Serialized as `name` of Document object in ActivityPub
- Uploads form adjusted for better performance and description input
* Add tests
* Change undo button blend mode to difference
Diffstat (limited to 'app/javascript/mastodon/features/compose/components/upload.js')
-rw-r--r-- | app/javascript/mastodon/features/compose/components/upload.js | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js new file mode 100644 index 000000000..c2bf3b72e --- /dev/null +++ b/app/javascript/mastodon/features/compose/components/upload.js @@ -0,0 +1,96 @@ +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import PropTypes from 'prop-types'; +import IconButton from '../../../components/icon_button'; +import Motion from 'react-motion/lib/Motion'; +import spring from 'react-motion/lib/spring'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl } from 'react-intl'; +import classNames from 'classnames'; + +const messages = defineMessages({ + undo: { id: 'upload_form.undo', defaultMessage: 'Undo' }, + description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' }, +}); + +@injectIntl +export default class Upload extends ImmutablePureComponent { + + static propTypes = { + media: ImmutablePropTypes.map.isRequired, + intl: PropTypes.object.isRequired, + onUndo: PropTypes.func.isRequired, + onDescriptionChange: PropTypes.func.isRequired, + }; + + state = { + hovered: false, + focused: false, + dirtyDescription: null, + }; + + handleUndoClick = () => { + this.props.onUndo(this.props.media.get('id')); + } + + handleInputChange = e => { + this.setState({ dirtyDescription: e.target.value }); + } + + handleMouseEnter = () => { + this.setState({ hovered: true }); + } + + handleMouseLeave = () => { + this.setState({ hovered: false }); + } + + handleInputFocus = () => { + this.setState({ focused: true }); + } + + handleInputBlur = () => { + const { dirtyDescription } = this.state; + + this.setState({ focused: false, dirtyDescription: null }); + + if (dirtyDescription !== null) { + this.props.onDescriptionChange(this.props.media.get('id'), dirtyDescription); + } + } + + render () { + const { intl, media } = this.props; + const active = this.state.hovered || this.state.focused; + const description = this.state.dirtyDescription || media.get('description') || ''; + + return ( + <div className='compose-form__upload' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> + <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}> + {({ scale }) => ( + <div className='compose-form__upload-thumbnail' style={{ transform: `translateZ(0) scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})` }}> + <IconButton icon='times' title={intl.formatMessage(messages.undo)} size={36} onClick={this.handleUndoClick} /> + + <div className={classNames('compose-form__upload-description', { active })}> + <label> + <span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span> + + <input + placeholder={intl.formatMessage(messages.description)} + type='text' + value={description} + maxLength={140} + onFocus={this.handleInputFocus} + onChange={this.handleInputChange} + onBlur={this.handleInputBlur} + /> + </label> + </div> + </div> + )} + </Motion> + </div> + ); + } + +} |