It's time for keyboard-layout-dependant shortcuts

Let's hope this works!
pull/1124/head
Lim Chee Aun 2025-04-19 09:00:01 +08:00
rodzic 4719e2c6a4
commit e87f7777c6
12 zmienionych plików z 722 dodań i 607 usunięć

Wyświetl plik

@ -144,13 +144,22 @@ export default memo(function BackgroundService({ isLoggedIn }) {
});
// Global keyboard shortcuts "service"
useHotkeys('shift+alt+k', () => {
const currentCloakMode = states.settings.cloakMode;
states.settings.cloakMode = !currentCloakMode;
showToast({
text: currentCloakMode ? t`Cloak mode disabled` : t`Cloak mode enabled`,
});
});
useHotkeys(
'shift+alt+k',
(e) => {
// Need modifers check due to useKey: true
if (!e.shiftKey || !e.altKey) return;
const currentCloakMode = states.settings.cloakMode;
states.settings.cloakMode = !currentCloakMode;
showToast({
text: currentCloakMode ? t`Cloak mode disabled` : t`Cloak mode enabled`,
});
},
{
useKey: true,
},
);
return null;
});

Wyświetl plik

@ -68,31 +68,38 @@ function Columns() {
}
});
useHotkeys(['[', ']'], (e, handler) => {
const key = handler.keys[0];
const currentFocusedColumn = document.activeElement.closest('#columns > *');
useHotkeys(
['[', ']'],
(e, handler) => {
const key = handler.keys[0];
const currentFocusedColumn =
document.activeElement.closest('#columns > *');
const rtl = isRTL();
const prevColKey = rtl ? ']' : '[';
const nextColKey = rtl ? '[' : ']';
let $column;
const rtl = isRTL();
const prevColKey = rtl ? ']' : '[';
const nextColKey = rtl ? '[' : ']';
let $column;
if (key === prevColKey) {
// If [, focus on left of focused column, else first column
$column = currentFocusedColumn
? currentFocusedColumn.previousElementSibling
: document.querySelectorAll('#columns > *')[0];
} else if (key === nextColKey) {
// If ], focus on right of focused column, else 2nd column
$column = currentFocusedColumn
? currentFocusedColumn.nextElementSibling
: document.querySelectorAll('#columns > *')[1];
}
if ($column) {
$column.focus();
$column.scrollIntoView(scrollIntoViewOptions);
}
});
if (key === prevColKey) {
// If [, focus on left of focused column, else first column
$column = currentFocusedColumn
? currentFocusedColumn.previousElementSibling
: document.querySelectorAll('#columns > *')[0];
} else if (key === nextColKey) {
// If ], focus on right of focused column, else 2nd column
$column = currentFocusedColumn
? currentFocusedColumn.nextElementSibling
: document.querySelectorAll('#columns > *')[1];
}
if ($column) {
$column.focus();
$column.scrollIntoView(scrollIntoViewOptions);
}
},
{
useKey: true,
},
);
return (
<div

Wyświetl plik

@ -70,12 +70,19 @@ export default function ComposeButton() {
}
}
useHotkeys('c, shift+c', handleButton, {
ignoreEventWhen: (e) => {
const hasModal = !!document.querySelector('#modal-container > *');
return hasModal;
useHotkeys(
'c, shift+c',
handleButton,
{
ignoreEventWhen: (e) => {
const hasModal = !!document.querySelector('#modal-container > *');
return hasModal;
},
},
});
{
useKey: true,
},
);
// Setup longpress handler to open context menu
const bindLongPress = useLongPress(

Wyświetl plik

@ -19,12 +19,13 @@ export default memo(function KeyboardShortcutsHelp() {
}
useHotkeys(
'?, shift+?, shift+slash',
(e) => {
'?',
() => {
console.log('help');
states.showKeyboardShortcutsHelp = true;
},
{
useKey: true,
ignoreEventWhen: (e) => {
const isCatchUpPage = /\/catchup/i.test(location.hash);
return isCatchUpPage;

Wyświetl plik

@ -20,6 +20,7 @@ export default memo(function SearchCommand({ onClose = () => {} }) {
}, 0);
},
{
useKey: true,
preventDefault: true,
ignoreEventWhen: (e) => {
const isSearchPage = /\/search/.test(location.hash);

Wyświetl plik

@ -1482,16 +1482,22 @@ function Status({
const hotkeysEnabled = !readOnly && !previewMode && !quoted;
const rRef = useHotkeys('r, shift+r', replyStatus, {
enabled: hotkeysEnabled,
useKey: true,
});
const fRef = useHotkeys('f, l', favouriteStatusNotify, {
enabled: hotkeysEnabled,
useKey: true,
});
const dRef = useHotkeys('d', bookmarkStatusNotify, {
enabled: hotkeysEnabled,
useKey: true,
});
const bRef = useHotkeys(
'shift+b',
() => {
(e) => {
// Need shiftKey check due to useKey: true
if (!e.shiftKey) return;
(async () => {
try {
const done = await confirmBoostStatus();
@ -1507,30 +1513,37 @@ function Status({
},
{
enabled: hotkeysEnabled && canBoost,
useKey: true,
},
);
const xRef = useHotkeys('x', (e) => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
if (activeStatus) {
const spoilerButton = activeStatus.querySelector(
'.spoiler-button:not(.spoiling)',
const xRef = useHotkeys(
'x',
(e) => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
if (spoilerButton) {
e.stopPropagation();
spoilerButton.click();
} else {
const spoilerMediaButton = activeStatus.querySelector(
'.spoiler-media-button:not(.spoiling)',
if (activeStatus) {
const spoilerButton = activeStatus.querySelector(
'.spoiler-button:not(.spoiling)',
);
if (spoilerMediaButton) {
if (spoilerButton) {
e.stopPropagation();
spoilerMediaButton.click();
spoilerButton.click();
} else {
const spoilerMediaButton = activeStatus.querySelector(
'.spoiler-media-button:not(.spoiling)',
);
if (spoilerMediaButton) {
e.stopPropagation();
spoilerMediaButton.click();
}
}
}
}
});
},
{
useKey: true,
},
);
const displayedMediaAttachments = mediaAttachments.slice(
0,

Wyświetl plik

@ -143,91 +143,115 @@ function Timeline({
const itemsSelector = '.timeline-item, .timeline-item-alt';
const jRef = useHotkeys('j, shift+j', (_, handler) => {
// focus on next status after active item
const activeItem = document.activeElement.closest(itemsSelector);
const activeItemRect = activeItem?.getBoundingClientRect();
const allItems = Array.from(
scrollableRef.current.querySelectorAll(itemsSelector),
).filter((item) => !!item.offsetHeight);
if (
activeItem &&
activeItemRect.top < scrollableRef.current.clientHeight &&
activeItemRect.bottom > 0
) {
const activeItemIndex = allItems.indexOf(activeItem);
let nextItem = allItems[activeItemIndex + 1];
if (handler.shift) {
// get next status that's not .timeline-item-alt
nextItem = allItems.find(
(item, index) =>
index > activeItemIndex &&
!item.classList.contains('timeline-item-alt'),
);
}
if (nextItem) {
nextItem.focus();
nextItem.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
const jRef = useHotkeys(
'j, shift+j',
(e, handler) => {
// Fix bug: shift+j is fired even when j is pressed due to useKey: true
if (e.shiftKey !== handler.shift) return;
const kRef = useHotkeys('k, shift+k', (_, handler) => {
// 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),
).filter((item) => !!item.offsetHeight);
if (
activeItem &&
activeItemRect.top < scrollableRef.current.clientHeight &&
activeItemRect.bottom > 0
) {
const activeItemIndex = allItems.indexOf(activeItem);
let prevItem = allItems[activeItemIndex - 1];
if (handler.shift) {
// get prev status that's not .timeline-item-alt
prevItem = allItems.findLast(
(item, index) =>
index < activeItemIndex &&
!item.classList.contains('timeline-item-alt'),
);
// focus on next status after active item
const activeItem = document.activeElement.closest(itemsSelector);
const activeItemRect = activeItem?.getBoundingClientRect();
const allItems = Array.from(
scrollableRef.current.querySelectorAll(itemsSelector),
).filter((item) => !!item.offsetHeight);
if (
activeItem &&
activeItemRect.top < scrollableRef.current.clientHeight &&
activeItemRect.bottom > 0
) {
const activeItemIndex = allItems.indexOf(activeItem);
let nextItem = allItems[activeItemIndex + 1];
if (handler.shift) {
// get next status that's not .timeline-item-alt
nextItem = allItems.find(
(item, index) =>
index > activeItemIndex &&
!item.classList.contains('timeline-item-alt'),
);
}
if (nextItem) {
nextItem.focus();
nextItem.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
if (prevItem) {
prevItem.focus();
prevItem.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
const oRef = useHotkeys(['enter', 'o'], () => {
// open active status
const activeItem = document.activeElement;
if (activeItem?.matches(itemsSelector)) {
activeItem.click();
}
});
const kRef = useHotkeys(
'k, shift+k',
(e, handler) => {
// Fix bug: shift+k is fired even when k is pressed due to useKey: true
if (e.shiftKey !== handler.shift) return;
// 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),
).filter((item) => !!item.offsetHeight);
if (
activeItem &&
activeItemRect.top < scrollableRef.current.clientHeight &&
activeItemRect.bottom > 0
) {
const activeItemIndex = allItems.indexOf(activeItem);
let prevItem = allItems[activeItemIndex - 1];
if (handler.shift) {
// get prev status that's not .timeline-item-alt
prevItem = allItems.findLast(
(item, index) =>
index < activeItemIndex &&
!item.classList.contains('timeline-item-alt'),
);
}
if (prevItem) {
prevItem.focus();
prevItem.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
},
{
useKey: true,
},
);
const oRef = useHotkeys(
['enter', 'o'],
() => {
// open active status
const activeItem = document.activeElement;
if (activeItem?.matches(itemsSelector)) {
activeItem.click();
}
},
{
useKey: true,
},
);
const showNewPostsIndicator =
items.length > 0 && uiState !== 'loading' && showNew;

562
src/locales/en.po wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -716,6 +716,7 @@ function Catchup() {
}
},
{
useKey: true,
preventDefault: true,
ignoreModifiers: true,
},
@ -760,6 +761,7 @@ function Catchup() {
}
},
{
useKey: true,
preventDefault: true,
ignoreModifiers: true,
},
@ -789,6 +791,7 @@ function Catchup() {
}
},
{
useKey: true,
preventDefault: true,
ignoreModifiers: true,
enableOnFormTags: ['input'],
@ -817,6 +820,7 @@ function Catchup() {
});
},
{
useKey: true,
preventDefault: true,
ignoreModifiers: true,
enableOnFormTags: ['input'],

Wyświetl plik

@ -451,72 +451,90 @@ function Notifications({ columnMode }) {
}, []);
const itemsSelector = '.notification';
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);
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);
}
}
} else {
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0;
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
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);
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);
}
}
} else {
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0;
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
const oRef = useHotkeys(['enter', 'o'], () => {
const activeItem = document.activeElement.closest(itemsSelector);
const statusLink = activeItem?.querySelector('.status-link');
if (statusLink) {
statusLink.click();
}
});
const oRef = useHotkeys(
['enter', 'o'],
() => {
const activeItem = document.activeElement.closest(itemsSelector);
const statusLink = activeItem?.querySelector('.status-link');
if (statusLink) {
statusLink.click();
}
},
{
useKey: true,
},
);
const today = new Date();
const todaySubHeading = useMemo(() => {

Wyświetl plik

@ -198,75 +198,88 @@ function Search({ columnMode, ...props }) {
}, [q, type, instance]);
useHotkeys(
['/', 'Slash'],
['Slash', '/'],
(e) => {
searchFormRef.current?.focus?.();
searchFormRef.current?.select?.();
},
{
useKey: true,
preventDefault: true,
},
);
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);
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);
}
}
} else {
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0;
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
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);
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);
}
}
} else {
const topmostItem = allItems.find((item) => {
const itemRect = item.getBoundingClientRect();
return itemRect.top >= 44 && itemRect.left >= 0;
});
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
const [filterBarParent] = useAutoAnimate();

Wyświetl plik

@ -651,84 +651,102 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
location.hash = closeLink;
});
useHotkeys('j', () => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
const activeStatusRect = activeStatus?.getBoundingClientRect();
const allStatusLinks = Array.from(
scrollableRef.current.querySelectorAll(STATUSES_SELECTOR),
);
console.log({ allStatusLinks });
if (
activeStatus &&
activeStatusRect.top < scrollableRef.current.clientHeight &&
activeStatusRect.bottom > 0
) {
const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
let nextStatus = allStatusLinks[activeStatusIndex + 1];
if (nextStatus) {
nextStatus.focus();
nextStatus.scrollIntoView(scrollIntoViewOptions);
useHotkeys(
'j',
() => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
const activeStatusRect = activeStatus?.getBoundingClientRect();
const allStatusLinks = Array.from(
scrollableRef.current.querySelectorAll(STATUSES_SELECTOR),
);
console.log({ allStatusLinks });
if (
activeStatus &&
activeStatusRect.top < scrollableRef.current.clientHeight &&
activeStatusRect.bottom > 0
) {
const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
let nextStatus = allStatusLinks[activeStatusIndex + 1];
if (nextStatus) {
nextStatus.focus();
nextStatus.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostStatusLink = allStatusLinks.find((statusLink) => {
const statusLinkRect = statusLink.getBoundingClientRect();
return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostStatusLink) {
topmostStatusLink.focus();
topmostStatusLink.scrollIntoView(scrollIntoViewOptions);
}
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostStatusLink = allStatusLinks.find((statusLink) => {
const statusLinkRect = statusLink.getBoundingClientRect();
return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostStatusLink) {
topmostStatusLink.focus();
topmostStatusLink.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
useHotkeys('k', () => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
const activeStatusRect = activeStatus?.getBoundingClientRect();
const allStatusLinks = Array.from(
scrollableRef.current.querySelectorAll(STATUSES_SELECTOR),
);
if (
activeStatus &&
activeStatusRect.top < scrollableRef.current.clientHeight &&
activeStatusRect.bottom > 0
) {
const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
let prevStatus = allStatusLinks[activeStatusIndex - 1];
if (prevStatus) {
prevStatus.focus();
prevStatus.scrollIntoView(scrollIntoViewOptions);
useHotkeys(
'k',
() => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
const activeStatusRect = activeStatus?.getBoundingClientRect();
const allStatusLinks = Array.from(
scrollableRef.current.querySelectorAll(STATUSES_SELECTOR),
);
if (
activeStatus &&
activeStatusRect.top < scrollableRef.current.clientHeight &&
activeStatusRect.bottom > 0
) {
const activeStatusIndex = allStatusLinks.indexOf(activeStatus);
let prevStatus = allStatusLinks[activeStatusIndex - 1];
if (prevStatus) {
prevStatus.focus();
prevStatus.scrollIntoView(scrollIntoViewOptions);
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostStatusLink = allStatusLinks.find((statusLink) => {
const statusLinkRect = statusLink.getBoundingClientRect();
return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostStatusLink) {
topmostStatusLink.focus();
topmostStatusLink.scrollIntoView(scrollIntoViewOptions);
}
}
} else {
// If active status is not in viewport, get the topmost status-link in viewport
const topmostStatusLink = allStatusLinks.find((statusLink) => {
const statusLinkRect = statusLink.getBoundingClientRect();
return statusLinkRect.top >= 44 && statusLinkRect.left >= 0; // 44 is the magic number for header height, not real
});
if (topmostStatusLink) {
topmostStatusLink.focus();
topmostStatusLink.scrollIntoView(scrollIntoViewOptions);
}
}
});
},
{
useKey: true,
},
);
// NOTE: I'm not sure if 'x' is the best shortcut for this, might change it later
// IDEA: x is for expand
useHotkeys('x', () => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
if (activeStatus) {
const details = activeStatus.nextElementSibling;
if (details && details.tagName.toLowerCase() === 'details') {
details.open = !details.open;
useHotkeys(
'x',
() => {
const activeStatus = document.activeElement.closest(
'.status-link, .status-focus',
);
if (activeStatus) {
const details = activeStatus.nextElementSibling;
if (details && details.tagName.toLowerCase() === 'details') {
details.open = !details.open;
}
}
}
});
},
{
useKey: true,
},
);
const [reachTopPost, setReachTopPost] = useState(false);
// const { nearReachStart } = useScroll({