mirror of
https://github.com/cheeaun/phanpy.git
synced 2024-11-21 16:55:25 +03:00
Make search page keyboard-navigable
Still experimental
This commit is contained in:
parent
f0773dc6f3
commit
7d922550d0
1 changed files with 76 additions and 1 deletions
|
@ -24,6 +24,12 @@ const SHORT_LIMIT = 5;
|
|||
const LIMIT = 40;
|
||||
const emptySearchParams = new URLSearchParams();
|
||||
|
||||
const scrollIntoViewOptions = {
|
||||
block: 'nearest',
|
||||
inline: 'center',
|
||||
behavior: 'smooth',
|
||||
};
|
||||
|
||||
function Search({ columnMode, ...props }) {
|
||||
const params = columnMode ? {} : useParams();
|
||||
const { masto, instance, authenticated } = api({
|
||||
|
@ -186,10 +192,79 @@ function Search({ columnMode, ...props }) {
|
|||
},
|
||||
);
|
||||
|
||||
const itemsSelector = '.timeline > li > a, .hashtag-list > li > a';
|
||||
const jRef = useHotkeys('j', () => {
|
||||
const activeItem = document.activeElement.closest(itemsSelector);
|
||||
const activeItemRect = activeItem?.getBoundingClientRect();
|
||||
const allItems = Array.from(
|
||||
scrollableRef.current.querySelectorAll(itemsSelector),
|
||||
);
|
||||
if (
|
||||
activeItem &&
|
||||
activeItemRect.top < scrollableRef.current.clientHeight &&
|
||||
activeItemRect.bottom > 0
|
||||
) {
|
||||
const activeItemIndex = allItems.indexOf(activeItem);
|
||||
let nextItem = allItems[activeItemIndex + 1];
|
||||
if (nextItem) {
|
||||
nextItem.focus();
|
||||
nextItem.scrollIntoView(scrollIntoViewOptions);
|
||||
}
|
||||
} else {
|
||||
const topmostItem = allItems.find((item) => {
|
||||
const itemRect = item.getBoundingClientRect();
|
||||
return itemRect.top >= 44 && itemRect.left >= 0;
|
||||
});
|
||||
if (topmostItem) {
|
||||
topmostItem.focus();
|
||||
topmostItem.scrollIntoView(scrollIntoViewOptions);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const kRef = useHotkeys('k', () => {
|
||||
// focus on previous status after active item
|
||||
const activeItem = document.activeElement.closest(itemsSelector);
|
||||
const activeItemRect = activeItem?.getBoundingClientRect();
|
||||
const allItems = Array.from(
|
||||
scrollableRef.current.querySelectorAll(itemsSelector),
|
||||
);
|
||||
if (
|
||||
activeItem &&
|
||||
activeItemRect.top < scrollableRef.current.clientHeight &&
|
||||
activeItemRect.bottom > 0
|
||||
) {
|
||||
const activeItemIndex = allItems.indexOf(activeItem);
|
||||
let prevItem = allItems[activeItemIndex - 1];
|
||||
if (prevItem) {
|
||||
prevItem.focus();
|
||||
prevItem.scrollIntoView(scrollIntoViewOptions);
|
||||
}
|
||||
} else {
|
||||
const topmostItem = allItems.find((item) => {
|
||||
const itemRect = item.getBoundingClientRect();
|
||||
return itemRect.top >= 44 && itemRect.left >= 0;
|
||||
});
|
||||
if (topmostItem) {
|
||||
topmostItem.focus();
|
||||
topmostItem.scrollIntoView(scrollIntoViewOptions);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const [filterBarParent] = useAutoAnimate();
|
||||
|
||||
return (
|
||||
<div id="search-page" class="deck-container" ref={scrollableRef}>
|
||||
<div
|
||||
id="search-page"
|
||||
class="deck-container"
|
||||
tabIndex="-1"
|
||||
ref={(node) => {
|
||||
scrollableRef.current = node;
|
||||
jRef(node);
|
||||
kRef(node);
|
||||
}}
|
||||
>
|
||||
<div class="timeline-deck deck">
|
||||
<header class={uiState === 'loading' ? 'loading' : ''}>
|
||||
<div class="header-grid">
|
||||
|
|
Loading…
Reference in a new issue