From a8330be93ee825948a17c810af33e28bfa2c56c8 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 23 Jul 2024 14:11:08 +0200 Subject: [PATCH] Widen the clickable area for statuses in grouped notifications (#31111) --- .../components/embedded_status.tsx | 80 +++++++++++++++++-- .../components/embedded_status_content.tsx | 76 +----------------- .../styles/mastodon/components.scss | 3 +- 3 files changed, 77 insertions(+), 82 deletions(-) diff --git a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx index 0881e24e3f..baec016117 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useCallback, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; @@ -22,6 +22,7 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ statusId, }) => { const history = useHistory(); + const clickCoordinatesRef = useRef<[number, number] | null>(); const status = useAppSelector( (state) => state.statuses.get(statusId) as Status | undefined, @@ -31,11 +32,69 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ state.accounts.get(status?.get('account') as string), ); - const handleClick = useCallback(() => { - if (!account) return; + const handleMouseDown = useCallback>( + ({ clientX, clientY }) => { + clickCoordinatesRef.current = [clientX, clientY]; + }, + [clickCoordinatesRef], + ); - history.push(`/@${account.acct}/${statusId}`); - }, [statusId, account, history]); + 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; + } + }, + [], + ); if (!status) { return null; @@ -51,7 +110,15 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ ).size; return ( -
+
@@ -62,7 +129,6 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ content={contentHtml} language={language} mentions={mentions} - onClick={handleClick} /> {(poll || mediaAttachmentsSize > 0) && ( diff --git a/app/javascript/mastodon/features/notifications_v2/components/embedded_status_content.tsx b/app/javascript/mastodon/features/notifications_v2/components/embedded_status_content.tsx index 310a685711..1a38be536b 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/embedded_status_content.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/embedded_status_content.tsx @@ -1,4 +1,4 @@ -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; @@ -34,76 +34,10 @@ export const EmbeddedStatusContent: React.FC<{ content: string; mentions: List; language: string; - onClick?: () => void; className?: string; -}> = ({ content, mentions, language, onClick, className }) => { - const clickCoordinatesRef = useRef<[number, number] | null>(); +}> = ({ content, mentions, language, className }) => { const history = useHistory(); - 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 && onClick) { - onClick(); - } - - clickCoordinatesRef.current = null; - }, - [clickCoordinatesRef, onClick], - ); - - 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 handleContentRef = useCallback( (node: HTMLDivElement | null) => { if (!node) { @@ -150,16 +84,10 @@ export const EmbeddedStatusContent: React.FC<{ return (
); }; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index adcbad202d..18a775fb2f 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -10457,6 +10457,8 @@ noscript { } &__embedded-status { + cursor: pointer; + &__account { display: flex; align-items: center; @@ -10478,7 +10480,6 @@ noscript { font-size: 15px; line-height: 22px; color: $dark-text-color; - cursor: pointer; -webkit-line-clamp: 4; -webkit-box-orient: vertical; max-height: 4 * 22px;