diff --git a/src/components/keyboard-shortcuts-help.jsx b/src/components/keyboard-shortcuts-help.jsx
index 0bf76daa..a3739ce8 100644
--- a/src/components/keyboard-shortcuts-help.jsx
+++ b/src/components/keyboard-shortcuts-help.jsx
@@ -129,6 +129,26 @@ export default function KeyboardShortcutsHelp() {
action: 'Search',
keys: /,
},
+ {
+ action: 'Reply',
+ keys: r,
+ },
+ {
+ action: 'Favourite',
+ keys: f,
+ },
+ {
+ action: 'Boost',
+ keys: (
+ <>
+ Shift + b
+ >
+ ),
+ },
+ {
+ action: 'Bookmark',
+ keys: d,
+ },
].map(({ action, keys }) => (
{action} |
diff --git a/src/components/status.jsx b/src/components/status.jsx
index 5f85f235..955b65e0 100644
--- a/src/components/status.jsx
+++ b/src/components/status.jsx
@@ -19,6 +19,7 @@ import {
useRef,
useState,
} from 'preact/hooks';
+import { useHotkeys } from 'react-hotkeys-hook';
import { InView } from 'react-intersection-observer';
import { useLongPress } from 'use-long-press';
import useResizeObserver from 'use-resize-observer';
@@ -621,8 +622,9 @@ function Status({
onClick={() => {
try {
favouriteStatus();
- if (!isSizeLarge)
+ if (!isSizeLarge) {
showToast(favourited ? 'Unfavourited' : 'Favourited');
+ }
} catch (e) {}
}}
>
@@ -644,8 +646,9 @@ function Status({
onClick={() => {
try {
bookmarkStatus();
- if (!isSizeLarge)
+ if (!isSizeLarge) {
showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked');
+ }
} catch (e) {}
}}
>
@@ -832,9 +835,72 @@ function Status({
const showContextMenu = size !== 'l' && !previewMode && !_deleted && !quoted;
+ const hotkeysEnabled = !readOnly && !previewMode;
+ const rRef = useHotkeys('r', replyStatus, {
+ enabled: hotkeysEnabled,
+ });
+ const fRef = useHotkeys(
+ 'f',
+ () => {
+ try {
+ favouriteStatus();
+ if (!isSizeLarge) {
+ showToast(favourited ? 'Unfavourited' : 'Favourited');
+ }
+ } catch (e) {}
+ },
+ {
+ enabled: hotkeysEnabled,
+ },
+ );
+ const dRef = useHotkeys(
+ 'd',
+ () => {
+ try {
+ bookmarkStatus();
+ if (!isSizeLarge) {
+ showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked');
+ }
+ } catch (e) {}
+ },
+ {
+ enabled: hotkeysEnabled,
+ },
+ );
+ const bRef = useHotkeys(
+ 'shift+b',
+ () => {
+ (async () => {
+ try {
+ const done = await confirmBoostStatus();
+ if (!isSizeLarge && done) {
+ showToast(reblogged ? 'Unboosted' : 'Boosted');
+ }
+ } catch (e) {}
+ })();
+ },
+ {
+ enabled: hotkeysEnabled && canBoost,
+ },
+ );
+
return (
{
+ statusRef.current = node;
+ // Use parent node if it's in focus
+ // Use case:
+ // When navigating (j/k), the is focused instead of
+ // Hotkey binding doesn't bubble up thus this hack
+ const nodeRef =
+ node?.closest?.(
+ '.timeline-item, .timeline-item-alt, .status-link, .status-focus',
+ ) || node;
+ rRef.current = nodeRef;
+ fRef.current = nodeRef;
+ dRef.current = nodeRef;
+ bRef.current = nodeRef;
+ }}
tabindex="-1"
class={`status ${
!withinContext && inReplyToId && inReplyToAccount