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" // Global keyboard shortcuts "service"
useHotkeys('shift+alt+k', () => { useHotkeys(
const currentCloakMode = states.settings.cloakMode; 'shift+alt+k',
states.settings.cloakMode = !currentCloakMode; (e) => {
showToast({ // Need modifers check due to useKey: true
text: currentCloakMode ? t`Cloak mode disabled` : t`Cloak mode enabled`, 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; return null;
}); });

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -143,91 +143,115 @@ function Timeline({
const itemsSelector = '.timeline-item, .timeline-item-alt'; const itemsSelector = '.timeline-item, .timeline-item-alt';
const jRef = useHotkeys('j, shift+j', (_, handler) => { const jRef = useHotkeys(
// focus on next status after active item 'j, shift+j',
const activeItem = document.activeElement.closest(itemsSelector); (e, handler) => {
const activeItemRect = activeItem?.getBoundingClientRect(); // Fix bug: shift+j is fired even when j is pressed due to useKey: true
const allItems = Array.from( if (e.shiftKey !== handler.shift) return;
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 kRef = useHotkeys('k, shift+k', (_, handler) => { // focus on next status after active item
// focus on previous status after active item const activeItem = document.activeElement.closest(itemsSelector);
const activeItem = document.activeElement.closest(itemsSelector); const activeItemRect = activeItem?.getBoundingClientRect();
const activeItemRect = activeItem?.getBoundingClientRect(); const allItems = Array.from(
const allItems = Array.from( scrollableRef.current.querySelectorAll(itemsSelector),
scrollableRef.current.querySelectorAll(itemsSelector), ).filter((item) => !!item.offsetHeight);
).filter((item) => !!item.offsetHeight); if (
if ( activeItem &&
activeItem && activeItemRect.top < scrollableRef.current.clientHeight &&
activeItemRect.top < scrollableRef.current.clientHeight && activeItemRect.bottom > 0
activeItemRect.bottom > 0 ) {
) { const activeItemIndex = allItems.indexOf(activeItem);
const activeItemIndex = allItems.indexOf(activeItem); let nextItem = allItems[activeItemIndex + 1];
let prevItem = allItems[activeItemIndex - 1]; if (handler.shift) {
if (handler.shift) { // get next status that's not .timeline-item-alt
// get prev status that's not .timeline-item-alt nextItem = allItems.find(
prevItem = allItems.findLast( (item, index) =>
(item, index) => index > activeItemIndex &&
index < activeItemIndex && !item.classList.contains('timeline-item-alt'),
!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); useKey: true,
} },
} 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 oRef = useHotkeys(['enter', 'o'], () => { const kRef = useHotkeys(
// open active status 'k, shift+k',
const activeItem = document.activeElement; (e, handler) => {
if (activeItem?.matches(itemsSelector)) { // Fix bug: shift+k is fired even when k is pressed due to useKey: true
activeItem.click(); 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 = const showNewPostsIndicator =
items.length > 0 && uiState !== 'loading' && showNew; 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, preventDefault: true,
ignoreModifiers: true, ignoreModifiers: true,
}, },
@ -760,6 +761,7 @@ function Catchup() {
} }
}, },
{ {
useKey: true,
preventDefault: true, preventDefault: true,
ignoreModifiers: true, ignoreModifiers: true,
}, },
@ -789,6 +791,7 @@ function Catchup() {
} }
}, },
{ {
useKey: true,
preventDefault: true, preventDefault: true,
ignoreModifiers: true, ignoreModifiers: true,
enableOnFormTags: ['input'], enableOnFormTags: ['input'],
@ -817,6 +820,7 @@ function Catchup() {
}); });
}, },
{ {
useKey: true,
preventDefault: true, preventDefault: true,
ignoreModifiers: true, ignoreModifiers: true,
enableOnFormTags: ['input'], enableOnFormTags: ['input'],

Wyświetl plik

@ -451,72 +451,90 @@ function Notifications({ columnMode }) {
}, []); }, []);
const itemsSelector = '.notification'; const itemsSelector = '.notification';
const jRef = useHotkeys('j', () => { const jRef = useHotkeys(
const activeItem = document.activeElement.closest(itemsSelector); 'j',
const activeItemRect = activeItem?.getBoundingClientRect(); () => {
const allItems = Array.from( const activeItem = document.activeElement.closest(itemsSelector);
scrollableRef.current.querySelectorAll(itemsSelector), const activeItemRect = activeItem?.getBoundingClientRect();
); const allItems = Array.from(
if ( scrollableRef.current.querySelectorAll(itemsSelector),
activeItem && );
activeItemRect.top < scrollableRef.current.clientHeight && if (
activeItemRect.bottom > 0 activeItem &&
) { activeItemRect.top < scrollableRef.current.clientHeight &&
const activeItemIndex = allItems.indexOf(activeItem); activeItemRect.bottom > 0
let nextItem = allItems[activeItemIndex + 1]; ) {
if (nextItem) { const activeItemIndex = allItems.indexOf(activeItem);
nextItem.focus(); let nextItem = allItems[activeItemIndex + 1];
nextItem.scrollIntoView(scrollIntoViewOptions); 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(); useKey: true,
return itemRect.top >= 44 && itemRect.left >= 0; },
}); );
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
const kRef = useHotkeys('k', () => { const kRef = useHotkeys(
// focus on previous status after active item 'k',
const activeItem = document.activeElement.closest(itemsSelector); () => {
const activeItemRect = activeItem?.getBoundingClientRect(); // focus on previous status after active item
const allItems = Array.from( const activeItem = document.activeElement.closest(itemsSelector);
scrollableRef.current.querySelectorAll(itemsSelector), const activeItemRect = activeItem?.getBoundingClientRect();
); const allItems = Array.from(
if ( scrollableRef.current.querySelectorAll(itemsSelector),
activeItem && );
activeItemRect.top < scrollableRef.current.clientHeight && if (
activeItemRect.bottom > 0 activeItem &&
) { activeItemRect.top < scrollableRef.current.clientHeight &&
const activeItemIndex = allItems.indexOf(activeItem); activeItemRect.bottom > 0
let prevItem = allItems[activeItemIndex - 1]; ) {
if (prevItem) { const activeItemIndex = allItems.indexOf(activeItem);
prevItem.focus(); let prevItem = allItems[activeItemIndex - 1];
prevItem.scrollIntoView(scrollIntoViewOptions); 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(); useKey: true,
return itemRect.top >= 44 && itemRect.left >= 0; },
}); );
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
const oRef = useHotkeys(['enter', 'o'], () => { const oRef = useHotkeys(
const activeItem = document.activeElement.closest(itemsSelector); ['enter', 'o'],
const statusLink = activeItem?.querySelector('.status-link'); () => {
if (statusLink) { const activeItem = document.activeElement.closest(itemsSelector);
statusLink.click(); const statusLink = activeItem?.querySelector('.status-link');
} if (statusLink) {
}); statusLink.click();
}
},
{
useKey: true,
},
);
const today = new Date(); const today = new Date();
const todaySubHeading = useMemo(() => { const todaySubHeading = useMemo(() => {

Wyświetl plik

@ -198,75 +198,88 @@ function Search({ columnMode, ...props }) {
}, [q, type, instance]); }, [q, type, instance]);
useHotkeys( useHotkeys(
['/', 'Slash'], ['Slash', '/'],
(e) => { (e) => {
searchFormRef.current?.focus?.(); searchFormRef.current?.focus?.();
searchFormRef.current?.select?.(); searchFormRef.current?.select?.();
}, },
{ {
useKey: true,
preventDefault: true, preventDefault: true,
}, },
); );
const itemsSelector = '.timeline > li > a, .hashtag-list > li > a'; const itemsSelector = '.timeline > li > a, .hashtag-list > li > a';
const jRef = useHotkeys('j', () => { const jRef = useHotkeys(
const activeItem = document.activeElement.closest(itemsSelector); 'j',
const activeItemRect = activeItem?.getBoundingClientRect(); () => {
const allItems = Array.from( const activeItem = document.activeElement.closest(itemsSelector);
scrollableRef.current.querySelectorAll(itemsSelector), const activeItemRect = activeItem?.getBoundingClientRect();
); const allItems = Array.from(
if ( scrollableRef.current.querySelectorAll(itemsSelector),
activeItem && );
activeItemRect.top < scrollableRef.current.clientHeight && if (
activeItemRect.bottom > 0 activeItem &&
) { activeItemRect.top < scrollableRef.current.clientHeight &&
const activeItemIndex = allItems.indexOf(activeItem); activeItemRect.bottom > 0
let nextItem = allItems[activeItemIndex + 1]; ) {
if (nextItem) { const activeItemIndex = allItems.indexOf(activeItem);
nextItem.focus(); let nextItem = allItems[activeItemIndex + 1];
nextItem.scrollIntoView(scrollIntoViewOptions); 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(); useKey: true,
return itemRect.top >= 44 && itemRect.left >= 0; },
}); );
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
const kRef = useHotkeys('k', () => { const kRef = useHotkeys(
// focus on previous status after active item 'k',
const activeItem = document.activeElement.closest(itemsSelector); () => {
const activeItemRect = activeItem?.getBoundingClientRect(); // focus on previous status after active item
const allItems = Array.from( const activeItem = document.activeElement.closest(itemsSelector);
scrollableRef.current.querySelectorAll(itemsSelector), const activeItemRect = activeItem?.getBoundingClientRect();
); const allItems = Array.from(
if ( scrollableRef.current.querySelectorAll(itemsSelector),
activeItem && );
activeItemRect.top < scrollableRef.current.clientHeight && if (
activeItemRect.bottom > 0 activeItem &&
) { activeItemRect.top < scrollableRef.current.clientHeight &&
const activeItemIndex = allItems.indexOf(activeItem); activeItemRect.bottom > 0
let prevItem = allItems[activeItemIndex - 1]; ) {
if (prevItem) { const activeItemIndex = allItems.indexOf(activeItem);
prevItem.focus(); let prevItem = allItems[activeItemIndex - 1];
prevItem.scrollIntoView(scrollIntoViewOptions); 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(); useKey: true,
return itemRect.top >= 44 && itemRect.left >= 0; },
}); );
if (topmostItem) {
topmostItem.focus();
topmostItem.scrollIntoView(scrollIntoViewOptions);
}
}
});
const [filterBarParent] = useAutoAnimate(); const [filterBarParent] = useAutoAnimate();

Wyświetl plik

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