From 41ee08cd14626f10862bb1ac7c70faff0ebed269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 28 Jul 2023 23:23:04 +0200 Subject: [PATCH] Lexical: Add media preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/upload.tsx | 29 +++++++------ .../compose/editor/nodes/image-component.tsx | 42 +++++++++++++++---- app/styles/components/compose-form.scss | 2 +- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/app/soapbox/components/upload.tsx b/app/soapbox/components/upload.tsx index a7477585f..24a83d860 100644 --- a/app/soapbox/components/upload.tsx +++ b/app/soapbox/components/upload.tsx @@ -1,13 +1,13 @@ import clsx from 'clsx'; import { List as ImmutableList } from 'immutable'; import React, { useState } from 'react'; -import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, useIntl } from 'react-intl'; import { spring } from 'react-motion'; import { openModal } from 'soapbox/actions/modals'; import Blurhash from 'soapbox/components/blurhash'; import Icon from 'soapbox/components/icon'; -import IconButton from 'soapbox/components/icon-button'; +import { IconButton } from 'soapbox/components/ui'; import Motion from 'soapbox/features/ui/util/optional-motion'; import { useAppDispatch } from 'soapbox/hooks'; import { Attachment } from 'soapbox/types/entities'; @@ -57,6 +57,7 @@ export const MIMETYPE_ICONS: Record = { const messages = defineMessages({ description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' }, delete: { id: 'upload_form.undo', defaultMessage: 'Delete' }, + preview: { id: 'upload_form.preview', defaultMessage: 'Preview' }, }); interface IUpload { @@ -159,20 +160,24 @@ const Upload: React.FC = ({ backgroundPosition: typeof x === 'number' && typeof y === 'number' ? `${x}% ${y}%` : undefined }} >
- {onDelete && ( - } - /> - )} - - {/* Only display the "Preview" button for a valid attachment with a URL */} {(withPreview && mediaType !== 'unknown' && Boolean(media.url)) && ( } + theme='dark' + className='hover:scale-105 hover:bg-gray-900' + iconClassName='h-5 w-5' + title={intl.formatMessage(messages.preview)} + /> + )} + {onDelete && ( + )}
diff --git a/app/soapbox/features/compose/editor/nodes/image-component.tsx b/app/soapbox/features/compose/editor/nodes/image-component.tsx index ed686af4b..9d45c6adf 100644 --- a/app/soapbox/features/compose/editor/nodes/image-component.tsx +++ b/app/soapbox/features/compose/editor/nodes/image-component.tsx @@ -11,6 +11,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection'; import { mergeRegister } from '@lexical/utils'; import clsx from 'clsx'; +import { List as ImmutableList } from 'immutable'; import { $getNodeByKey, $getSelection, @@ -28,7 +29,10 @@ import { import * as React from 'react'; import { Suspense, useCallback, useEffect, useRef, useState } from 'react'; -import { IconButton } from 'soapbox/components/ui'; +import { openModal } from 'soapbox/actions/modals'; +import { HStack, IconButton } from 'soapbox/components/ui'; +import { useAppDispatch } from 'soapbox/hooks'; +import { normalizeAttachment } from 'soapbox/normalizers'; import { $isImageNode } from './image-node'; @@ -40,6 +44,7 @@ import type { RangeSelection, } from 'lexical'; + const imageCache = new Set(); const useSuspenseImage = (src: string) => { @@ -87,6 +92,8 @@ const ImageComponent = ({ nodeKey: NodeKey src: string }): JSX.Element => { + const dispatch = useAppDispatch(); + const imageRef = useRef(null); const buttonRef = useRef(null); const [isSelected, setSelected, clearSelection] = @@ -109,6 +116,16 @@ const ImageComponent = ({ [nodeKey], ); + const previewImage = () => { + const image = normalizeAttachment({ + type: 'image', + url: src, + altText, + }); + + dispatch(openModal('MEDIA', { media: ImmutableList.of(image), index: 0 })); + }; + const onDelete = useCallback( (payload: KeyboardEvent) => { if (isSelected && $isNodeSelection($getSelection())) { @@ -248,13 +265,22 @@ const ImageComponent = ({ <>
- + + + +