Add arrow down/up keybinding for scrolling page
This commit is contained in:
@@ -12,6 +12,8 @@ export interface FoliateView extends HTMLElement {
|
||||
init: (options: { lastLocation: string }) => void;
|
||||
goTo: (href: string) => void;
|
||||
goToFraction: (fraction: number) => void;
|
||||
prev: (distance: number) => void;
|
||||
next: (distance: number) => void;
|
||||
goLeft: () => void;
|
||||
goRight: () => void;
|
||||
getCFI: (index: number, range: Range) => string;
|
||||
@@ -57,7 +59,8 @@ const FoliateViewer: React.FC<{
|
||||
};
|
||||
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Backspace') {
|
||||
// prevent default navigation keys in iframes
|
||||
if (['Backspace', 'ArrowDown', 'ArrowUp'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
window.postMessage(
|
||||
|
||||
@@ -14,8 +14,12 @@ const useBookShortcuts = ({
|
||||
openSplitView,
|
||||
getNextBookKey,
|
||||
}: UseBookShortcutsProps) => {
|
||||
const { getView, setSideBarBookKey } = useReaderStore();
|
||||
const { toggleSideBar } = useReaderStore();
|
||||
const { getView, getConfig, toggleSideBar, setSideBarBookKey } = useReaderStore();
|
||||
const config = getConfig(sideBarBookKey);
|
||||
const viewSettings = config?.viewSettings;
|
||||
const fontSize = viewSettings?.defaultFontSize ?? 16;
|
||||
const lineHeight = viewSettings?.lineHeight ?? 1.6;
|
||||
const distance = fontSize * lineHeight * 3;
|
||||
|
||||
const switchSideBar = () => {
|
||||
if (sideBarBookKey) setSideBarBookKey(getNextBookKey(sideBarBookKey));
|
||||
@@ -29,6 +33,14 @@ const useBookShortcuts = ({
|
||||
getView(sideBarBookKey)?.goRight();
|
||||
};
|
||||
|
||||
const goPrev = () => {
|
||||
getView(sideBarBookKey)?.prev(distance);
|
||||
};
|
||||
|
||||
const goNext = () => {
|
||||
getView(sideBarBookKey)?.next(distance);
|
||||
};
|
||||
|
||||
const reloadPage = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
@@ -41,6 +53,8 @@ const useBookShortcuts = ({
|
||||
onReloadPage: reloadPage,
|
||||
onGoLeft: goLeft,
|
||||
onGoRight: goRight,
|
||||
onGoPrev: goPrev,
|
||||
onGoNext: goNext,
|
||||
},
|
||||
[sideBarBookKey, bookKeys],
|
||||
);
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
export interface ShortcutConfig {
|
||||
switchSidebar: string[];
|
||||
toggleSidebar: string[];
|
||||
openSplitView: string[];
|
||||
reloadPage: string[];
|
||||
goLeft: string[];
|
||||
goRight: string[];
|
||||
onSwitchSideBar: string[];
|
||||
onToggleSideBar: string[];
|
||||
onOpenSplitView: string[];
|
||||
onReloadPage: string[];
|
||||
onGoLeft: string[];
|
||||
onGoRight: string[];
|
||||
onGoNext: string[];
|
||||
onGoPrev: string[];
|
||||
}
|
||||
|
||||
const DEFAULT_SHORTCUTS: ShortcutConfig = {
|
||||
switchSidebar: ['ctrl+Tab', 'opt+Tab', 'alt+Tab'],
|
||||
toggleSidebar: ['t'],
|
||||
openSplitView: ['shift+p'],
|
||||
reloadPage: ['shift+r'],
|
||||
goLeft: ['ArrowLeft', 'PageUp', 'h'],
|
||||
goRight: ['ArrowRight', 'PageDown', 'l'],
|
||||
onSwitchSideBar: ['ctrl+Tab', 'opt+Tab', 'alt+Tab'],
|
||||
onToggleSideBar: ['t'],
|
||||
onOpenSplitView: ['shift+p'],
|
||||
onReloadPage: ['shift+r'],
|
||||
onGoLeft: ['ArrowLeft', 'PageUp', 'h'],
|
||||
onGoRight: ['ArrowRight', 'PageDown', 'l'],
|
||||
onGoNext: ['ArrowDown', 'j'],
|
||||
onGoPrev: ['ArrowUp', 'k'],
|
||||
};
|
||||
|
||||
// Load shortcuts from localStorage or fallback to defaults
|
||||
export const loadShortcuts = (): ShortcutConfig => {
|
||||
const storedShortcuts = localStorage.getItem('customShortcuts');
|
||||
return storedShortcuts ? JSON.parse(storedShortcuts) : DEFAULT_SHORTCUTS;
|
||||
const customShortcuts = JSON.parse(localStorage.getItem('customShortcuts') || '{}');
|
||||
return {
|
||||
...DEFAULT_SHORTCUTS,
|
||||
...customShortcuts,
|
||||
};
|
||||
};
|
||||
|
||||
// Save custom shortcuts to localStorage
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { loadShortcuts, ShortcutConfig } from '../helpers/shortcuts';
|
||||
|
||||
interface KeyActionHandlers {
|
||||
onSwitchSideBar?: () => void;
|
||||
onToggleSideBar?: () => void;
|
||||
onOpenSplitView?: () => void;
|
||||
onReloadPage?: () => void;
|
||||
onGoLeft?: () => void;
|
||||
onGoRight?: () => void;
|
||||
}
|
||||
export type KeyActionHandlers = {
|
||||
[K in keyof ShortcutConfig]?: () => void;
|
||||
};
|
||||
|
||||
const useShortcuts = (actions: KeyActionHandlers, dependencies: React.DependencyList = []) => {
|
||||
const [shortcuts, setShortcuts] = useState<ShortcutConfig>(loadShortcuts);
|
||||
@@ -60,53 +55,19 @@ const useShortcuts = (actions: KeyActionHandlers, dependencies: React.Dependency
|
||||
) => {
|
||||
// FIXME: This is a temporary fix to disable Back button navigation
|
||||
if (key === 'backspace') return true;
|
||||
if (
|
||||
shortcuts.switchSidebar.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onSwitchSideBar?.();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
shortcuts.toggleSidebar.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onToggleSideBar?.();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
shortcuts.openSplitView.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onOpenSplitView?.();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
shortcuts.reloadPage.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onReloadPage?.();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
shortcuts.goLeft.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onGoLeft?.();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
shortcuts.goRight.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
actions.onGoRight?.();
|
||||
return true;
|
||||
for (const [actionName, actionHandler] of Object.entries(actions)) {
|
||||
const shortcutKey = actionName as keyof ShortcutConfig;
|
||||
const handler = actionHandler as (() => void) | undefined;
|
||||
const shortcutList = shortcuts[shortcutKey as keyof ShortcutConfig];
|
||||
if (
|
||||
handler &&
|
||||
shortcutList?.some((shortcut) =>
|
||||
isShortcutMatch(shortcut, key, ctrlKey, altKey, metaKey, shiftKey),
|
||||
)
|
||||
) {
|
||||
handler();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ interface ReaderStore {
|
||||
) => void;
|
||||
getProgress: (key: string) => BookProgress | null;
|
||||
setConfig: (key: string, config: BookConfig) => void;
|
||||
getConfig: (key: string) => BookConfig | null;
|
||||
getConfig: (key: string | null) => BookConfig | null;
|
||||
setView: (key: string, view: FoliateView) => void;
|
||||
getView: (key: string | null) => FoliateView | null;
|
||||
getViewsById: (id: string) => FoliateView[];
|
||||
@@ -135,7 +135,8 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
|
||||
});
|
||||
},
|
||||
|
||||
getConfig: (key: string) => {
|
||||
getConfig: (key: string | null) => {
|
||||
if (!key) return null;
|
||||
const id = key.split('-')[0]!;
|
||||
return get().booksData[id]?.config || null;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user