From f20e68ffe36d916be7eb5d773417a88fea3204bc Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 22 Sep 2026 12:09:34 +0000 Subject: [PATCH] Status redesign: Make statuses clickable again (#40648) --- .../mastodon/components/status/hooks.ts | 12 +++++- .../mastodon/components/status/meta.tsx | 8 ++-- .../mastodon/components/status/status.tsx | 42 ++++++++++--------- .../components/status/styles.module.scss | 7 +++- .../mastodon/features/status/redesign.tsx | 10 ++++- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/app/javascript/mastodon/components/status/hooks.ts b/app/javascript/mastodon/components/status/hooks.ts index 1a90bc41738..badc7a8d7e0 100644 --- a/app/javascript/mastodon/components/status/hooks.ts +++ b/app/javascript/mastodon/components/status/hooks.ts @@ -140,6 +140,14 @@ export function useStatusHandlers({ const onOpenClick: React.MouseEventHandler = useCallback( (event) => { + const target = event.target; + if ( + !(target instanceof HTMLElement) || + target.closest('a, button') || + contextType === 'detailed' + ) { + return; + } event.preventDefault(); if (event.button === 0 && !(event.ctrlKey || event.metaKey)) { @@ -151,7 +159,7 @@ export function useStatusHandlers({ onOpenCallback(true); } }, - [onOpenCallback], + [contextType, onOpenCallback], ); const acct = status?.account.acct; @@ -202,7 +210,7 @@ export function useStatusHandlers({ onOpenClick, onFilterToggle, onMention, - onOpen: () => { + onOpenCallback: () => { onOpenCallback(); }, onOpenMedia, diff --git a/app/javascript/mastodon/components/status/meta.tsx b/app/javascript/mastodon/components/status/meta.tsx index e1cfe3d630a..3cd883a19c0 100644 --- a/app/javascript/mastodon/components/status/meta.tsx +++ b/app/javascript/mastodon/components/status/meta.tsx @@ -52,7 +52,7 @@ export const StatusMeta: React.FC<{ return (
-
    +
      -
+ -
    +
    • {applicationDisplay &&
    • {applicationDisplay}
    • }
    • {visibility}
    • -
+
); }; diff --git a/app/javascript/mastodon/components/status/status.tsx b/app/javascript/mastodon/components/status/status.tsx index 2664dd8f998..1b6e79db067 100644 --- a/app/javascript/mastodon/components/status/status.tsx +++ b/app/javascript/mastodon/components/status/status.tsx @@ -4,6 +4,7 @@ import classNames from 'classnames'; import type { Merge } from 'type-fest'; +import type { ExpandedStatusShape } from '@/mastodon/models/status'; import { selectExpandedStatus } from '@/mastodon/selectors/statuses'; import { createAppSelector, useAppSelector } from '@/mastodon/store'; @@ -15,9 +16,9 @@ import { StatusAttachments } from './attachments'; import { StatusContent } from './content'; import { StatusHashtagBar } from './hashtag_bar'; import { StatusRedesignHeader } from './header'; -import type { StatusHandlers } from './hooks'; import { StatusContext, + useStatusContext, useStatusHandlers, useTextForScreenReader, } from './hooks'; @@ -107,7 +108,8 @@ export const StatusRedesign: React.FC = ({ showDespiteFilter, onFilterToggle, onTranslate, - ...handlers + onOpenCallback, + onOpenClick, } = useStatusHandlers({ status, contextType, @@ -119,10 +121,8 @@ export const StatusRedesign: React.FC = ({ } const hotkeysProps = { - handlers: { - ...handlers, - onTranslate, - }, + status, + onOpen, muted, unfocusable, 'data-id': id, @@ -146,6 +146,7 @@ export const StatusRedesign: React.FC = ({ = ({ @@ -238,27 +239,28 @@ export const StatusRedesign: React.FC = ({ }; interface StatusHotkeysProps { + children: React.ReactNode; + status: ExpandedStatusShape; + onOpen?: () => void; muted?: boolean; unfocusable?: boolean; - children: React.ReactNode; - handlers: Omit< - StatusHandlers, - | 'isFiltered' - | 'showDespiteFilter' - | 'onOpenClick' - | 'onHeaderClick' - | 'onExpandedToggle' - | 'onFilterToggle' - >; } const StatusHotkeys = ({ + children, + status, + onOpen, muted, unfocusable, - children, - handlers, ...props }: StatusHotkeysProps & React.ComponentPropsWithoutRef<'article'>) => { + const { contextType } = useStatusContext(); + const handlers = useStatusHandlers({ + status, + contextType, + onOpen, + }); + if (muted) { return
{children}
; } @@ -273,7 +275,7 @@ const StatusHotkeys = ({ boost: handlers.onBoost, quote: handlers.onQuote, mention: handlers.onMention, - open: handlers.onOpen, + open: handlers.onOpenCallback, openProfile: handlers.onOpenProfile, toggleHidden: handlers.onToggleHidden, // TODO: This is handled in a child component, so needs to be fixed. diff --git a/app/javascript/mastodon/components/status/styles.module.scss b/app/javascript/mastodon/components/status/styles.module.scss index 23dbc183fd5..fc511617720 100644 --- a/app/javascript/mastodon/components/status/styles.module.scss +++ b/app/javascript/mastodon/components/status/styles.module.scss @@ -14,10 +14,12 @@ grid-auto-rows: auto; row-gap: var(--space-2); padding: var(--space-4); + cursor: pointer; } .variantPage { padding: var(--space-2) var(--space-4); + cursor: auto; } .variantThread { @@ -232,6 +234,8 @@ @include mixins.type-micro; display: flex; + gap: var(--space-4); + flex-wrap: wrap; justify-content: space-between; color: var(--color-text-secondary); padding-block-start: var(--space-2); @@ -240,8 +244,9 @@ margin-inline: calc(-1 * var(--space-4)); padding-inline: var(--space-4); - > ol { + > ul { display: flex; + flex-wrap: wrap; gap: var(--space-1); } diff --git a/app/javascript/mastodon/features/status/redesign.tsx b/app/javascript/mastodon/features/status/redesign.tsx index e5b1adf3691..5a4a61ff5dd 100644 --- a/app/javascript/mastodon/features/status/redesign.tsx +++ b/app/javascript/mastodon/features/status/redesign.tsx @@ -10,6 +10,7 @@ import { BookmarkSimpleIcon } from '@phosphor-icons/react'; import { Helmet } from '@unhead/react/helmet'; import { statusInteraction } from '@/mastodon/actions/interactions_typed'; +import { fetchStatus } from '@/mastodon/actions/statuses'; import { ToggleIconButton } from '@/mastodon/components/button/redesign'; import { Column } from '@/mastodon/components/column'; import { @@ -71,6 +72,7 @@ export const StatusPage: React.FC = () => { const { statusId } = useParams<{ acct: string; statusId: string }>(); const { multiColumn } = useColumnsContext(); const intl = useIntl(); + const dispatch = useAppDispatch(); const [fullscreen, setFullscreen] = useState(isFullscreen); useEffect(() => { @@ -84,7 +86,12 @@ export const StatusPage: React.FC = () => { }; }); - const status = useExpandedStatus(statusId, 'force'); + const status = useExpandedStatus(statusId); + useEffect(() => { + dispatch( + fetchStatus(statusId, { forceFetch: true, alsoFetchContext: true }), + ); + }, [dispatch, statusId]); const isLoading = useAppSelector( (state) => !!state.statuses.getIn([statusId, 'isLoading']), ); @@ -120,7 +127,6 @@ export const StatusPage: React.FC = () => { [], ); - const dispatch = useAppDispatch(); const handleBookmarkClick = useCallback(() => { dispatch( statusInteraction({