From 5c7492c5e47968fa56fcf130a3b13365c916e627 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 24 Jun 2026 09:45:02 +0200 Subject: [PATCH 01/12] Fix accounts not visible in collection editor in advanced web interface (#39586) --- .../features/collections/editor/accounts.tsx | 72 +++++++++---------- .../collections/editor/styles.module.scss | 2 +- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/app/javascript/mastodon/features/collections/editor/accounts.tsx b/app/javascript/mastodon/features/collections/editor/accounts.tsx index a27079164e..78acd6a720 100644 --- a/app/javascript/mastodon/features/collections/editor/accounts.tsx +++ b/app/javascript/mastodon/features/collections/editor/accounts.tsx @@ -24,7 +24,6 @@ import { import { Article, ItemList, - Scrollable, } from 'mastodon/components/scrollable_list/components'; import { useAccount } from 'mastodon/hooks/useAccount'; import { useSearchAccounts } from 'mastodon/hooks/useSearchAccounts'; @@ -417,43 +416,42 @@ export const CollectionAccounts: React.FC<{ )} - - - } - message={ - - } - /> - } - > - {editorItems.map(({ account_id, state }, index) => ( -
- -
- ))} -
-
+ } + message={ + + } + /> + } + > + {editorItems.map(({ account_id, state }, index) => ( +
+ +
+ ))} + {!isEditMode && hasItems && ( diff --git a/app/javascript/mastodon/features/collections/editor/styles.module.scss b/app/javascript/mastodon/features/collections/editor/styles.module.scss index d1111e7469..02d719699e 100644 --- a/app/javascript/mastodon/features/collections/editor/styles.module.scss +++ b/app/javascript/mastodon/features/collections/editor/styles.module.scss @@ -55,7 +55,7 @@ gap: 16px; } -.scrollableWrapper { +.accountList { margin-inline: -16px; } From a090a9f5158cfa2a6159cf1f08db454c61077f05 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 24 Jun 2026 10:54:58 +0200 Subject: [PATCH 02/12] Fix media modal navigation in RTL languages (#39587) --- .../features/ui/components/media_modal.tsx | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/app/javascript/mastodon/features/ui/components/media_modal.tsx b/app/javascript/mastodon/features/ui/components/media_modal.tsx index 2510137682..17e50f7b22 100644 --- a/app/javascript/mastodon/features/ui/components/media_modal.tsx +++ b/app/javascript/mastodon/features/ui/components/media_modal.tsx @@ -47,11 +47,9 @@ interface MediaModalProps { } const MIN_SWIPE_DISTANCE = 400; +const isLtrDir = getComputedStyle(document.body).direction !== 'rtl'; -export const MediaModal: FC = forwardRef< - HTMLDivElement, - MediaModalProps ->( +export const MediaModal = forwardRef( ( { media, @@ -64,15 +62,16 @@ export const MediaModal: FC = forwardRef< statusId, onChangeBackgroundColor, }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars -- _ref is required to keep the ref forwarding working _ref, ) => { const [index, setIndex] = useState(startIndex); const [zoomedIn, setZoomedIn] = useState(false); const currentMedia = media.get(index); + const sign = isLtrDir ? '-' : ''; + const [wrapperStyles, api] = useSpring(() => ({ - x: `-${index * 100}%`, + x: `${sign}${index * 100}%`, })); const handleChangeIndex = useCallback( @@ -85,10 +84,12 @@ export const MediaModal: FC = forwardRef< setIndex(newIndex); setZoomedIn(false); if (animate) { - void api.start({ x: `calc(-${newIndex * 100}% + 0px)` }); + void api.start({ + x: `calc(${sign}${newIndex * 100}% + 0px)`, + }); } }, - [api, media.size], + [api, media.size, sign], ); const handlePrevClick = useCallback(() => { handleChangeIndex(index - 1, true); @@ -99,11 +100,14 @@ export const MediaModal: FC = forwardRef< const handleKeyDown = useCallback( (event: KeyboardEvent) => { - if (event.key === 'ArrowLeft') { + const prevKey = isLtrDir ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = isLtrDir ? 'ArrowRight' : 'ArrowLeft'; + + if (event.key === prevKey) { handlePrevClick(); event.preventDefault(); event.stopPropagation(); - } else if (event.key === 'ArrowRight') { + } else if (event.key === nextKey) { handleNextClick(); event.preventDefault(); event.stopPropagation(); @@ -124,13 +128,14 @@ export const MediaModal: FC = forwardRef< active && Math.abs(mx) > Math.min(window.innerWidth / 4, MIN_SWIPE_DISTANCE) ) { - handleChangeIndex(index - xDir); + handleChangeIndex(isLtrDir ? index - xDir : index + xDir); cancel(); } // Set the x position via calc to ensure proper centering regardless of screen size. const x = active ? mx : 0; + const operator = isLtrDir ? '+' : '-'; void api.start({ - x: `calc(-${index * 100}% + ${x}px)`, + x: `calc(${sign}${index * 100}% ${operator} ${x}px)`, }); }, { pointer: { capture: false } }, @@ -161,14 +166,23 @@ export const MediaModal: FC = forwardRef< width: number; height: number; }>({ width: 0, height: 0 }); - const handleRef: RefCallback = useCallback((ele) => { - if (ele?.clientWidth && ele.clientHeight) { - setViewportDimensions({ - width: ele.clientWidth, - height: ele.clientHeight, - }); - } - }, []); + const handleRef: RefCallback = useCallback( + (ele) => { + if (typeof _ref === 'function') { + _ref(ele); + } else if (_ref) { + _ref.current = ele; + } + + if (ele?.clientWidth && ele.clientHeight) { + setViewportDimensions({ + width: ele.clientWidth, + height: ele.clientHeight, + }); + } + }, + [_ref], + ); const zoomable = currentMedia?.get('type') === 'image' && @@ -268,9 +282,8 @@ export const MediaModal: FC = forwardRef< const intl = useIntl(); - const leftNav = media.size > 1 && ( + const prevNav = media.size > 1 && ( ); - const rightNav = media.size > 1 && ( + const nextNav = media.size > 1 && ( ); - const rightNav = media.size > 1 && ( + const nextNav = media.size > 1 && (