Change media reordering design in the compose form in web UI (#32093)
This commit is contained in:
parent
cdd7526531
commit
11a12e56b3
9 changed files with 423 additions and 154 deletions
130
app/javascript/mastodon/features/compose/components/upload.tsx
Normal file
130
app/javascript/mastodon/features/compose/components/upload.tsx
Normal file
|
@ -0,0 +1,130 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
|
||||
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 type { MediaAttachment } from 'mastodon/models/media_attachment';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
export const Upload: React.FC<{
|
||||
id: string;
|
||||
dragging?: boolean;
|
||||
overlay?: boolean;
|
||||
tall?: boolean;
|
||||
wide?: boolean;
|
||||
}> = ({ id, dragging, overlay, tall, wide }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const media = useAppSelector(
|
||||
(state) =>
|
||||
state.compose // eslint-disable-line @typescript-eslint/no-unsafe-call
|
||||
.get('media_attachments') // eslint-disable-line @typescript-eslint/no-unsafe-member-access
|
||||
.find((item: MediaAttachment) => item.get('id') === id) as // eslint-disable-line @typescript-eslint/no-unsafe-member-access
|
||||
| MediaAttachment
|
||||
| undefined,
|
||||
);
|
||||
const sensitive = useAppSelector(
|
||||
(state) => state.compose.get('spoiler') as boolean, // eslint-disable-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
);
|
||||
|
||||
const handleUndoClick = useCallback(() => {
|
||||
dispatch(undoUploadCompose(id));
|
||||
}, [dispatch, id]);
|
||||
|
||||
const handleFocalPointClick = useCallback(() => {
|
||||
dispatch(initMediaEditModal(id));
|
||||
}, [dispatch, id]);
|
||||
|
||||
const { attributes, listeners, setNodeRef, transform, transition } =
|
||||
useSortable({ id });
|
||||
|
||||
if (!media) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const focusX = media.getIn(['meta', 'focus', 'x']) as number;
|
||||
const focusY = media.getIn(['meta', 'focus', 'y']) as number;
|
||||
const x = (focusX / 2 + 0.5) * 100;
|
||||
const y = (focusY / -2 + 0.5) * 100;
|
||||
const missingDescription =
|
||||
((media.get('description') as string | undefined) ?? '').length === 0;
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('compose-form__upload media-gallery__item', {
|
||||
dragging,
|
||||
overlay,
|
||||
'media-gallery__item--tall': tall,
|
||||
'media-gallery__item--wide': wide,
|
||||
})}
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
>
|
||||
<div
|
||||
className='compose-form__upload__thumbnail'
|
||||
style={{
|
||||
backgroundImage: !sensitive
|
||||
? `url(${media.get('preview_url') as string})`
|
||||
: undefined,
|
||||
backgroundPosition: `${x}% ${y}%`,
|
||||
}}
|
||||
>
|
||||
{sensitive && (
|
||||
<Blurhash
|
||||
hash={media.get('blurhash') as string}
|
||||
className='compose-form__upload__preview'
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='compose-form__upload__actions'>
|
||||
<button
|
||||
type='button'
|
||||
className='icon-button compose-form__upload__delete'
|
||||
onClick={handleUndoClick}
|
||||
>
|
||||
<Icon id='close' icon={CloseIcon} />
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
className='icon-button'
|
||||
onClick={handleFocalPointClick}
|
||||
>
|
||||
<Icon id='edit' 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 id='warning' icon={WarningIcon} />} ALT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue