import { useCallback, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; import { useHistory } from 'react-router-dom'; import type { List as ImmutableList, RecordOf } from 'immutable'; import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react'; import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react'; import { toggleStatusSpoilers } from 'mastodon/actions/statuses'; import { Avatar } from 'mastodon/components/avatar'; import { ContentWarning } from 'mastodon/components/content_warning'; import { DisplayName } from 'mastodon/components/display_name'; import { Icon } from 'mastodon/components/icon'; import type { Status } from 'mastodon/models/status'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; import { EmbeddedStatusContent } from './embedded_status_content'; export type Mention = RecordOf<{ url: string; acct: string }>; export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ statusId, }) => { const history = useHistory(); const clickCoordinatesRef = useRef<[number, number] | null>(); const dispatch = useAppDispatch(); const status = useAppSelector( (state) => state.statuses.get(statusId) as Status | undefined, ); const account = useAppSelector((state) => state.accounts.get(status?.get('account') as string), ); const handleMouseDown = useCallback>( ({ clientX, clientY }) => { clickCoordinatesRef.current = [clientX, clientY]; }, [clickCoordinatesRef], ); const handleMouseUp = useCallback>( ({ clientX, clientY, target, button }) => { const [startX, startY] = clickCoordinatesRef.current ?? [0, 0]; const [deltaX, deltaY] = [ Math.abs(clientX - startX), Math.abs(clientY - startY), ]; let element: HTMLDivElement | null = target as HTMLDivElement; while (element) { if ( element.localName === 'button' || element.localName === 'a' || element.localName === 'label' ) { return; } element = element.parentNode as HTMLDivElement | null; } if (deltaX + deltaY < 5 && button === 0 && account) { history.push(`/@${account.acct}/${statusId}`); } clickCoordinatesRef.current = null; }, [clickCoordinatesRef, statusId, account, history], ); const handleMouseEnter = useCallback>( ({ currentTarget }) => { const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (const emoji of emojis) { const newSrc = emoji.getAttribute('data-original'); if (newSrc) emoji.src = newSrc; } }, [], ); const handleMouseLeave = useCallback>( ({ currentTarget }) => { const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (const emoji of emojis) { const newSrc = emoji.getAttribute('data-static'); if (newSrc) emoji.src = newSrc; } }, [], ); const handleContentWarningClick = useCallback(() => { dispatch(toggleStatusSpoilers(statusId)); }, [dispatch, statusId]); if (!status) { return null; } // Assign status attributes to variables with a forced type, as status is not yet properly typed const contentHtml = status.get('contentHtml') as string; const contentWarning = status.get('spoilerHtml') as string; const poll = status.get('poll'); const language = status.get('language') as string; const mentions = status.get('mentions') as ImmutableList; const expanded = !status.get('hidden') || !contentWarning; const mediaAttachmentsSize = ( status.get('media_attachments') as ImmutableList ).size; return (
{contentWarning && ( )} {(!contentWarning || expanded) && ( )} {expanded && (poll || mediaAttachmentsSize > 0) && (
{!!poll && ( <> )} {mediaAttachmentsSize > 0 && ( <> )}
)}
); };