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 LIMIT = 40;
|
||||||
const emptySearchParams = new URLSearchParams();
|
const emptySearchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
const scrollIntoViewOptions = {
|
||||||
|
block: 'nearest',
|
||||||
|
inline: 'center',
|
||||||
|
behavior: 'smooth',
|
||||||
|
};
|
||||||
|
|
||||||
function Search({ columnMode, ...props }) {
|
function Search({ columnMode, ...props }) {
|
||||||
const params = columnMode ? {} : useParams();
|
const params = columnMode ? {} : useParams();
|
||||||
const { masto, instance, authenticated } = api({
|
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();
|
const [filterBarParent] = useAutoAnimate();
|
||||||
|
|
||||||
return (
|
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">
|
<div class="timeline-deck deck">
|
||||||
<header class={uiState === 'loading' ? 'loading' : ''}>
|
<header class={uiState === 'loading' ? 'loading' : ''}>
|
||||||
<div class="header-grid">
|
<div class="header-grid">
|
||||||
|
|
Loading…
Reference in a new issue