From e813eecacbf45d20460dd50d49df1e0d09209e5e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 30 May 2022 13:53:14 -0500 Subject: [PATCH] Upload: convert to TSX --- .../features/compose/components/upload.js | Bin 7816 -> 0 bytes .../features/compose/components/upload.tsx | 205 ++++++++++++++++++ 2 files changed, 205 insertions(+) delete mode 100644 app/soapbox/features/compose/components/upload.js create mode 100644 app/soapbox/features/compose/components/upload.tsx diff --git a/app/soapbox/features/compose/components/upload.js b/app/soapbox/features/compose/components/upload.js deleted file mode 100644 index a293509f918c2028d999dd8ace39a37774602112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7816 zcmbUmYj4}g@wA!bo zmye}LS-KMpOIptRy(1B)GSd)5OsQX4%oWTt8G~mI5<2jHJ`on^Hk0Y6OldItI=c)nlLN?vQP8^Ne3flqcayi;s(sFn&-0H3Ae6 z^0`R(4OfaSxH<)qeB*(>PIPn%Z)FxUt$A2JhOMiHFA%69rP53!ixxmEwUEg;60@;= z+CUfZAoTKs%r(z;$Y$oy4`qztm7!lpdA4L~S<+XMr8Bu6*D9&;tb}NITn94Q4=?a( z8}@as^&yPu%m6u(-54cHKBLhX|8gu9LZ(W?Ov-yB-2^iJzg%Q| z;Jq?|kc~+$RsJWqkyqnSC zaRT76G>t@H*o@cyJmZ{Yfp-C9;!=UrF5C>|Jqqag0jR}cLaQVkWh^^DXzlBRFo$`q z{eOHnB?YaoczBR!pq3>}6>=S8Ep;6A!BEVMzp)ilK_*h&2jcqXo5IYtZrRH!3ZESV zw)U4=r=g!ND zTSBl?TtERLyZ|pxBgw)k1?tFo?wt|=mPfjreh~B*gFfScz@V2LRzl@0iZ+1rAj38u zda$KP3VFme?`4r=9`@5F6obFTc3(B5QU-X{3}*1EnVn9|R0^Ms4uGb?G*_@^HY`q1 zG)0Xv!1%8wSKHkHVjc>1;ow#fqnM>5p+4A2B_#a-=R_S{Ks~pP$Yry>XPjfFzG1g11!B24Tei%{RZuhXkn)_z)&9 z%^-rtpX2w@J>O6_g2`k8=YNHtexk!bXAxq-@4o{d#auJ|G8~q8fI*ARz|ywH7+|cC zKexo0)NvmYUx%%Oe4V7ZrlGvTH_s@ju-7CdY3HmosbS`@q2Rc}q3Rwvp(2%jIAm&> zlK=>PBL0y-DaE)#ELPbRC&G+e_yiXDf>3j@SF>mW-{Dh>-QFGRz`J3Vo;iWsT>gVwEau9LxU9#vuN_?~%8 zAJ*R2(nAj3m&16Q9lSL;a!_&|13VwXGZ_7C2v6bs?97#H(?EWKG5Gr-jp($}a>W^V zw0xp1M5C-7o67sPgGGkRlluhQma*T!-~e0_X!#ipR&CcN-qJt+J3P?87{|_BONclA z`E#H_&tGJ0^LUmp5n=Me-4kmd%8~8eu!;yvm8LS)PsM*U7kfq$?;j~jVV6x zhDaQm(bDDM^0<{s(Dn>Pds3{oKf;q@v;FZ7ZQN4BH8_zXvpQjM(2&z9m3rK;p&bh- z%l>xQa-h zUrBH0&N#sHCm0Gqt#{>cC*LJ|+r^>NeHi63poLVP^`Z2H>E*aLMve;B z{?=IKP&e$FE@>7N-b#cV>*Ky!VjcsHf45ZisPw7pB*Nb&0e>UqAw*K9T`o4fWu67x z7LUD+&>c<)%f2qhhH;m0C!=x3Xhz;$dzTihsM34q$f0;Sw$o9?)`6{VS=*EU1K^Or A?*IS* diff --git a/app/soapbox/features/compose/components/upload.tsx b/app/soapbox/features/compose/components/upload.tsx new file mode 100644 index 0000000000..b60079dcab --- /dev/null +++ b/app/soapbox/features/compose/components/upload.tsx @@ -0,0 +1,205 @@ +import classNames from 'classnames'; +import React, { useState } from 'react'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; +import { spring } from 'react-motion'; +import { useHistory } 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'; + +import type { Map as ImmutableMap } from 'immutable'; + +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 defaultIcon = require('@tabler/icons/icons/paperclip.svg'); +const presentationIcon = require('@tabler/icons/icons/presentation.svg'); + +export const MIMETYPE_ICONS: Record = { + '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' }, +}); + +interface IUpload { + media: ImmutableMap, + descriptionLimit: number, + onUndo: (attachmentId: string) => void, + onDescriptionChange: (attachmentId: string, description: string) => void, + onOpenFocalPoint: (attachmentId: string) => void, + onOpenModal: (attachments: ImmutableMap) => void, + onSubmit: (history: ReturnType) => void, +} + +const Upload: React.FC = (props) => { + const intl = useIntl(); + const history = useHistory(); + + const [hovered, setHovered] = useState(false); + const [focused, setFocused] = useState(false); + const [dirtyDescription, setDirtyDescription] = useState(null); + + const handleKeyDown: React.KeyboardEventHandler = (e) => { + if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { + handleSubmit(); + } + }; + + const handleSubmit = () => { + handleInputBlur(); + props.onSubmit(history); + }; + + const handleUndoClick: React.MouseEventHandler = e => { + e.stopPropagation(); + props.onUndo(props.media.get('id')); + }; + + const handleInputChange: React.ChangeEventHandler = e => { + setDirtyDescription(e.target.value); + }; + + const handleMouseEnter = () => { + setHovered(true); + }; + + const handleMouseLeave = () => { + setHovered(false); + }; + + const handleInputFocus = () => { + setFocused(true); + }; + + const handleClick = () => { + setFocused(true); + }; + + const handleInputBlur = () => { + setFocused(false); + setDirtyDescription(null); + + if (dirtyDescription !== null) { + props.onDescriptionChange(props.media.get('id'), dirtyDescription); + } + }; + + const handleOpenModal = () => { + props.onOpenModal(props.media); + }; + + const active = hovered || focused; + const description = dirtyDescription || (dirtyDescription !== '' && props.media.get('description')) || ''; + const focusX = props.media.getIn(['meta', 'focus', 'x']) as number | undefined; + const focusY = props.media.getIn(['meta', 'focus', 'y']) as number | undefined; + const x = focusX ? ((focusX / 2) + .5) * 100 : 0; + const y = focusY ? ((focusY / -2) + .5) * 100 : 0; + const mediaType = props.media.get('type'); + const mimeType = props.media.getIn(['pleroma', 'mime_type']) as string | undefined; + + const uploadIcon = mediaType === 'unknown' && ( + + ); + + return ( +
+ + + {({ scale }) => ( +
+
+ } + /> + + {/* Only display the "Preview" button for a valid attachment with a URL */} + {(mediaType !== 'unknown' && Boolean(props.media.get('url'))) && ( + } + /> + )} +
+ +
+