82 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import PropTypes from 'prop-types';
 | |
| import { useCallback } from 'react';
 | |
| 
 | |
| import { FormattedMessage } from 'react-intl';
 | |
| 
 | |
| import classNames from 'classnames';
 | |
| 
 | |
| import { useDispatch, useSelector } from 'react-redux';
 | |
| 
 | |
| import spring from 'react-motion/lib/spring';
 | |
| 
 | |
| import CloseIcon from '@/material-icons/400-20px/close.svg?react';
 | |
| import EditIcon from '@/material-icons/400-24px/edit.svg?react';
 | |
| import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
 | |
| import { undoUploadCompose, initMediaEditModal } from 'mastodon/actions/compose';
 | |
| import { Blurhash } from 'mastodon/components/blurhash';
 | |
| import { Icon }  from 'mastodon/components/icon';
 | |
| import Motion from 'mastodon/features/ui/util/optional_motion';
 | |
| 
 | |
| export const Upload = ({ id, onDragStart, onDragEnter, onDragEnd }) => {
 | |
|   const dispatch = useDispatch();
 | |
|   const media = useSelector(state => state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id));
 | |
|   const sensitive = useSelector(state => state.getIn(['compose', 'spoiler']));
 | |
| 
 | |
|   const handleUndoClick = useCallback(() => {
 | |
|     dispatch(undoUploadCompose(id));
 | |
|   }, [dispatch, id]);
 | |
| 
 | |
|   const handleFocalPointClick = useCallback(() => {
 | |
|     dispatch(initMediaEditModal(id));
 | |
|   }, [dispatch, id]);
 | |
| 
 | |
|   const handleDragStart = useCallback(() => {
 | |
|     onDragStart(id);
 | |
|   }, [onDragStart, id]);
 | |
| 
 | |
|   const handleDragEnter = useCallback(() => {
 | |
|     onDragEnter(id);
 | |
|   }, [onDragEnter, id]);
 | |
| 
 | |
|   if (!media) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   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 missingDescription = (media.get('description') || '').length === 0;
 | |
| 
 | |
|   return (
 | |
|     <div className='compose-form__upload' draggable onDragStart={handleDragStart} onDragEnter={handleDragEnter} onDragEnd={onDragEnd}>
 | |
|       <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
 | |
|         {({ scale }) => (
 | |
|           <div className='compose-form__upload__thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: !sensitive ? `url(${media.get('preview_url')})` : null, backgroundPosition: `${x}% ${y}%` }}>
 | |
|             {sensitive && <Blurhash
 | |
|               hash={media.get('blurhash')}
 | |
|               className='compose-form__upload__preview'
 | |
|             />}
 | |
| 
 | |
|             <div className='compose-form__upload__actions'>
 | |
|               <button type='button' className='icon-button compose-form__upload__delete' onClick={handleUndoClick}><Icon icon={CloseIcon} /></button>
 | |
|               <button type='button' className='icon-button' onClick={handleFocalPointClick}><Icon icon={EditIcon} /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
 | |
|             </div>
 | |
| 
 | |
|             <div className='compose-form__upload__warning'>
 | |
|               <button type='button' className={classNames('icon-button', { active: missingDescription })} onClick={handleFocalPointClick}>{missingDescription && <Icon icon={WarningIcon} />} ALT</button>
 | |
|             </div>
 | |
|           </div>
 | |
|         )}
 | |
|       </Motion>
 | |
|     </div>
 | |
|   );
 | |
| };
 | |
| 
 | |
| Upload.propTypes = {
 | |
|   id: PropTypes.string,
 | |
|   onDragEnter: PropTypes.func,
 | |
|   onDragStart: PropTypes.func,
 | |
|   onDragEnd: PropTypes.func,
 | |
| };
 |