pl-fe: allow accessing 'load more' button with hotkeys

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2025-10-31 11:02:41 +01:00
parent 83d2bc1073
commit e1986fb670
11 changed files with 25 additions and 14 deletions

View File

@ -189,7 +189,7 @@ const NotificationsColumn = () => {
const handleMoveDown = (id: string) => {
const elementIndex = displayedNotifications.findIndex(item => item !== null && item.group_key === id) + 1;
selectChild(elementIndex, node);
selectChild(elementIndex, node, undefined, displayedNotifications.length);
};
const handleDequeueNotifications = useCallback(() => {

View File

@ -54,7 +54,7 @@ const SearchColumn: React.FC<ISearchColumn> = ({ type, query, accountId, multiCo
if (!resultsIds) return;
const elementIndex = getCurrentIndex(id) + 1;
selectChild(elementIndex, node, document.getElementById('search-results') || undefined);
selectChild(elementIndex, node, document.getElementById('search-results') || undefined, resultsIds.length);
};
const handleLoadMore = () => activeQuery.fetchNextPage({ cancelRefetch: false });

View File

@ -1,8 +1,7 @@
import { clsx } from 'clsx';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import Button from 'pl-fe/components/ui/button';
interface ILoadMore {
onClick: React.MouseEventHandler;
disabled?: boolean;
@ -16,9 +15,9 @@ const LoadMore: React.FC<ILoadMore> = ({ onClick, disabled, visible = true, clas
}
return (
<Button className={className} theme='primary' block disabled={disabled || !visible} onClick={onClick}>
<button className={clsx('⁂-load-more', className)} disabled={disabled || !visible} onClick={onClick}>
<FormattedMessage id='status.load_more' defaultMessage='Load more' />
</Button>
</button>
);
};

View File

@ -71,7 +71,7 @@ const StatusList: React.FC<IStatusList> = ({
const handleMoveDown = (id: string, featured: boolean = false) => {
const elementIndex = getCurrentStatusIndex(id, featured) + 1;
selectChild(elementIndex, node, document.getElementById('status-list') || undefined);
selectChild(elementIndex, node, document.getElementById('status-list') || undefined, scrollableContent.length);
};
const handleLoadOlder = useCallback(debounce(() => {

View File

@ -29,7 +29,7 @@ const ConversationsList: React.FC = () => {
const handleMoveDown = (id: string) => {
const elementIndex = getCurrentIndex(id) + 1;
selectChild(elementIndex, ref, document.getElementById('direct-list') || undefined);
selectChild(elementIndex, ref, document.getElementById('direct-list') || undefined, conversations.length);
};
const handleLoadOlder = debounce(() => {

View File

@ -254,15 +254,15 @@ const Thread = ({
const handleMoveDown = (id: string) => {
const modalOffset = isModal ? 1 : 0;
if (id === status.id) {
selectChild(statusIndex + 1 + modalOffset, scroller, node.current || undefined);
selectChild(statusIndex + 1 + modalOffset, scroller, node.current || undefined, thread.length + modalOffset);
} else {
let index = thread.indexOf(id);
if (index === -1) {
index = thread.indexOf(id);
selectChild(index + modalOffset, scroller, node.current || undefined);
selectChild(index + modalOffset, scroller, node.current || undefined, thread.length + modalOffset);
} else {
selectChild(index + 1 + modalOffset, scroller, node.current || undefined);
selectChild(index + 1 + modalOffset, scroller, node.current || undefined, thread.length + modalOffset);
}
}
};

View File

@ -3,7 +3,6 @@ import React, { useRef } from 'react';
import { useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import 'pl-fe/styles/new/timelines.scss';
import { uploadCompose } from 'pl-fe/actions/compose';
import Avatar from 'pl-fe/components/ui/avatar';
import Layout from 'pl-fe/components/ui/layout';

View File

@ -66,7 +66,7 @@ const EventDiscussionPage: React.FC<IEventDiscussion> = ({ params: { statusId: s
const handleMoveDown = (id: string) => {
const index = descendantsIds.indexOf(id);
selectChild(index + 1, scroller, node.current || undefined);
selectChild(index + 1, scroller, node.current || undefined, descendantsIds.length);
};
const renderTombstone = (id: string) => (

View File

@ -2,3 +2,4 @@
@use 'layout';
@use 'accounts';
@use 'statuses';
@use 'timelines';

View File

@ -23,4 +23,8 @@
&__form {
@apply w-full translate-y-0.5;
}
}
.-load-more {
@include mixins.button($theme: primary, $block: true);
}

View File

@ -1,7 +1,15 @@
import type React from 'react';
import type { VirtuosoHandle } from 'react-virtuoso';
const selectChild = (index: number, handle: React.RefObject<VirtuosoHandle>, node: ParentNode = document) => {
const selectChild = (index: number, handle: React.RefObject<VirtuosoHandle>, node: ParentNode = document, count?: number) => {
if (count !== undefined && index === count) {
const loadMoreButton = node.querySelector<HTMLButtonElement>('.⁂-load-more');
if (loadMoreButton) {
loadMoreButton.focus({ preventScroll: false });
return;
}
}
const selector = `[data-index="${index}"] .focusable`;
const element = node.querySelector<HTMLDivElement>(selector);