Merge branch 'search-results-hotkeys' into 'develop'
Allow up/down hotkey navigation in posts search results See merge request soapbox-pub/soapbox-fe!1588
This commit is contained in:
commit
a652aa75a2
2 changed files with 52 additions and 4 deletions
|
@ -86,7 +86,7 @@ const StatusList: React.FC<IStatusList> = ({
|
|||
index,
|
||||
behavior: 'smooth',
|
||||
done: () => {
|
||||
const element: HTMLElement | null = document.querySelector(`#status-list [data-index="${index}"] .focusable`);
|
||||
const element = document.querySelector<HTMLDivElement>(`#status-list [data-index="${index}"] .focusable`);
|
||||
element?.focus();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { expandSearch, setFilter } from 'soapbox/actions/search';
|
||||
|
@ -14,6 +14,8 @@ import PlaceholderHashtag from 'soapbox/features/placeholder/components/placehol
|
|||
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||
import type { SearchFilter } from 'soapbox/reducers/search';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -23,6 +25,8 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const SearchResults = () => {
|
||||
const node = useRef<VirtuosoHandle>(null);
|
||||
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
@ -60,6 +64,35 @@ const SearchResults = () => {
|
|||
return <Tabs items={items} activeItem={selectedFilter} />;
|
||||
};
|
||||
|
||||
const getCurrentIndex = (id: string): number => {
|
||||
return resultsIds?.keySeq().findIndex(key => key === id);
|
||||
};
|
||||
|
||||
const handleMoveUp = (id: string) => {
|
||||
if (!resultsIds) return;
|
||||
|
||||
const elementIndex = getCurrentIndex(id) - 1;
|
||||
selectChild(elementIndex);
|
||||
};
|
||||
|
||||
const handleMoveDown = (id: string) => {
|
||||
if (!resultsIds) return;
|
||||
|
||||
const elementIndex = getCurrentIndex(id) + 1;
|
||||
selectChild(elementIndex);
|
||||
};
|
||||
|
||||
const selectChild = (index: number) => {
|
||||
node.current?.scrollIntoView({
|
||||
index,
|
||||
behavior: 'smooth',
|
||||
done: () => {
|
||||
const element = document.querySelector<HTMLDivElement>(`#search-results [data-index="${index}"] .focusable`);
|
||||
element?.focus();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchTrendingStatuses());
|
||||
}, []);
|
||||
|
@ -69,6 +102,7 @@ const SearchResults = () => {
|
|||
let loaded;
|
||||
let noResultsMessage;
|
||||
let placeholderComponent = PlaceholderStatus as React.ComponentType;
|
||||
let resultsIds: ImmutableOrderedSet<string>;
|
||||
|
||||
if (selectedFilter === 'accounts') {
|
||||
hasMore = results.accountsHasMore;
|
||||
|
@ -99,13 +133,25 @@ const SearchResults = () => {
|
|||
if (results.statuses && results.statuses.size > 0) {
|
||||
searchResults = results.statuses.map((statusId: string) => (
|
||||
// @ts-ignore
|
||||
<StatusContainer key={statusId} id={statusId} />
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
/>
|
||||
));
|
||||
resultsIds = results.statuses;
|
||||
} else if (!submitted && trendingStatuses && !trendingStatuses.isEmpty()) {
|
||||
searchResults = trendingStatuses.map((statusId: string) => (
|
||||
// @ts-ignore
|
||||
<StatusContainer key={statusId} id={statusId} />
|
||||
<StatusContainer
|
||||
key={statusId}
|
||||
id={statusId}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
/>
|
||||
));
|
||||
resultsIds = trendingStatuses;
|
||||
} else if (loaded) {
|
||||
noResultsMessage = (
|
||||
<div className='empty-column-indicator'>
|
||||
|
@ -147,6 +193,8 @@ const SearchResults = () => {
|
|||
|
||||
{noResultsMessage || (
|
||||
<ScrollableList
|
||||
id='search-results'
|
||||
ref={node}
|
||||
key={selectedFilter}
|
||||
scrollKey={`${selectedFilter}:${value}`}
|
||||
isLoading={submitted && !loaded}
|
||||
|
|
Loading…
Reference in a new issue