import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import spring from 'react-motion/lib/spring'; import { withRouter } from 'react-router-dom'; import Blurhash from 'soapbox/components/blurhash'; import Icon from 'soapbox/components/icon'; import IconButton from 'soapbox/components/icon_button'; import Motion from '../../ui/util/optional_motion'; const bookIcon = require('@tabler/icons/icons/book.svg'); const fileAnalyticsIcon = require('@tabler/icons/icons/file-analytics.svg'); const fileCodeIcon = require('@tabler/icons/icons/file-code.svg'); const fileTextIcon = require('@tabler/icons/icons/file-text.svg'); const fileZipIcon = require('@tabler/icons/icons/file-zip.svg'); const presentationIcon = require('@tabler/icons/icons/presentation.svg'); export const MIMETYPE_ICONS = { 'application/x-freearc': fileZipIcon, 'application/x-bzip': fileZipIcon, 'application/x-bzip2': fileZipIcon, 'application/gzip': fileZipIcon, 'application/vnd.rar': fileZipIcon, 'application/x-tar': fileZipIcon, 'application/zip': fileZipIcon, 'application/x-7z-compressed': fileZipIcon, 'application/x-csh': fileCodeIcon, 'application/html': fileCodeIcon, 'text/javascript': fileCodeIcon, 'application/json': fileCodeIcon, 'application/ld+json': fileCodeIcon, 'application/x-httpd-php': fileCodeIcon, 'application/x-sh': fileCodeIcon, 'application/xhtml+xml': fileCodeIcon, 'application/xml': fileCodeIcon, 'application/epub+zip': bookIcon, 'application/vnd.oasis.opendocument.spreadsheet': fileAnalyticsIcon, 'application/vnd.ms-excel': fileAnalyticsIcon, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': fileAnalyticsIcon, 'application/pdf': fileTextIcon, 'application/vnd.oasis.opendocument.presentation': presentationIcon, 'application/vnd.ms-powerpoint': presentationIcon, 'application/vnd.openxmlformats-officedocument.presentationml.presentation': presentationIcon, 'text/plain': fileTextIcon, 'application/rtf': fileTextIcon, 'application/msword': fileTextIcon, 'application/x-abiword': fileTextIcon, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': fileTextIcon, 'application/vnd.oasis.opendocument.text': fileTextIcon, }; const messages = defineMessages({ description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' }, delete: { id: 'upload_form.undo', defaultMessage: 'Delete' }, }); export default @injectIntl @withRouter class Upload extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.map.isRequired, intl: PropTypes.object.isRequired, onUndo: PropTypes.func.isRequired, onDescriptionChange: PropTypes.func.isRequired, onOpenFocalPoint: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, history: PropTypes.object.isRequired, }; state = { hovered: false, focused: false, dirtyDescription: null, }; handleKeyDown = (e) => { if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { this.handleSubmit(); } } handleSubmit = () => { this.handleInputBlur(); this.props.onSubmit(this.props.history); } handleUndoClick = e => { e.stopPropagation(); this.props.onUndo(this.props.media.get('id')); } handleFocalPointClick = e => { e.stopPropagation(); this.props.onOpenFocalPoint(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 }); } handleClick = () => { 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); } } handleOpenModal = () => { this.props.onOpenModal(this.props.media); } render() { const { intl, media, descriptionLimit } = this.props; const active = this.state.hovered || this.state.focused; const description = this.state.dirtyDescription || (this.state.dirtyDescription !== '' && media.get('description')) || ''; const focusX = media.getIn(['meta', 'focus', 'x']); const focusY = media.getIn(['meta', 'focus', 'y']); const x = ((focusX / 2) + .5) * 100; const y = ((focusY / -2) + .5) * 100; const mediaType = media.get('type'); const uploadIcon = mediaType === 'unknown' && ( ); return (
{({ scale }) => (
} /> {/* Only display the "Preview" button for a valid attachment with a URL */} {(mediaType !== 'unknown' && Boolean(media.get('url'))) && ( } /> )}