forked from akai/readest
Unified keydown handling
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "Readest",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"identifier": "com.bilingify.digest",
|
||||
"build": {
|
||||
"frontendDist": "../out",
|
||||
|
||||
@@ -62,13 +62,34 @@ const FoliateViewer: React.FC<{
|
||||
bookKey: string;
|
||||
bookDoc: BookDoc;
|
||||
bookConfig: BookConfig;
|
||||
}> = ({ bookKey, bookDoc, bookConfig }) => {
|
||||
handleKeyDown: (event: KeyboardEvent) => void;
|
||||
}> = ({ bookKey, bookDoc, bookConfig, handleKeyDown }) => {
|
||||
const viewRef = useRef<HTMLDivElement>(null);
|
||||
const [view, setView] = useState<FoliateView | null>(null);
|
||||
const isViewCreated = useRef(false);
|
||||
const { setFoliateView } = useReaderStore();
|
||||
const setProgress = useReaderStore((state) => state.setProgress);
|
||||
|
||||
useFoliateEvents(bookKey, view);
|
||||
const progressRelocateHandler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
// console.log('relocate:', detail);
|
||||
setProgress(
|
||||
bookKey,
|
||||
detail.fraction,
|
||||
detail.cfi,
|
||||
detail.tocItem?.href,
|
||||
detail.tocItem?.label,
|
||||
detail.section,
|
||||
detail.location,
|
||||
);
|
||||
};
|
||||
|
||||
const docLoadHandler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
if (handleKeyDown) detail.doc?.addEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
|
||||
useFoliateEvents(view, { onLoad: docLoadHandler, onRelocate: progressRelocateHandler });
|
||||
|
||||
useEffect(() => {
|
||||
if (isViewCreated.current) return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { RiArrowLeftWideLine, RiArrowRightWideLine } from 'react-icons/ri';
|
||||
|
||||
@@ -9,7 +9,6 @@ interface FooterBarProps {
|
||||
progress: number | undefined;
|
||||
isHoveredAnim: boolean;
|
||||
hoveredBookKey: string;
|
||||
sideBarBookKey: string;
|
||||
setHoveredBookKey: (key: string) => void;
|
||||
}
|
||||
|
||||
@@ -18,7 +17,6 @@ const FooterBar: React.FC<FooterBarProps> = ({
|
||||
progress,
|
||||
isHoveredAnim,
|
||||
hoveredBookKey,
|
||||
sideBarBookKey,
|
||||
setHoveredBookKey,
|
||||
}) => {
|
||||
const { getFoliateView } = useReaderStore();
|
||||
@@ -39,23 +37,6 @@ const FooterBar: React.FC<FooterBarProps> = ({
|
||||
foliateView?.goRight();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (sideBarBookKey === bookKey) {
|
||||
if (e.key === 'ArrowLeft') {
|
||||
handleGoPrev();
|
||||
} else if (e.key === 'ArrowRight') {
|
||||
handleGoNext();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [sideBarBookKey, bookKey]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
||||
@@ -49,7 +49,7 @@ const HeaderBar: React.FC<HeaderBarProps> = ({
|
||||
onMouseLeave={() => setHoveredBookKey('')}
|
||||
>
|
||||
<div className='absolute inset-0 flex items-center justify-center'>
|
||||
<h2 className='line-clamp-1 max-w-[80%] px-2 text-center text-xs font-semibold'>
|
||||
<h2 className='line-clamp-1 max-w-[70%] px-2 text-center text-xs font-semibold'>
|
||||
{bookTitle}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
@@ -22,6 +22,7 @@ const ReaderContent = () => {
|
||||
|
||||
const { envConfig } = useEnv();
|
||||
const { books, settings, initBookState, saveConfig, saveSettings } = useReaderStore();
|
||||
const { getFoliateView } = useReaderStore();
|
||||
|
||||
const [sideBarWidth, setSideBarWidth] = useState(
|
||||
settings.globalReadSettings.sideBarWidth ?? '25%',
|
||||
@@ -36,7 +37,27 @@ const ReaderContent = () => {
|
||||
const [sideBarBookKey, setSideBarBookKey] = useState(getKey(ids[0] ?? '', 0));
|
||||
const [hoveredBookKey, setHoveredBookKey] = useState('');
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (
|
||||
(e.ctrlKey && e.key === 'Tab') ||
|
||||
(e.altKey && e.key === 'Tab') ||
|
||||
(e.metaKey && e.key === 'Tab')
|
||||
) {
|
||||
setSideBarBookKey((prevKey) => {
|
||||
const index = ids.findIndex((id) => prevKey.startsWith(id));
|
||||
const nextIndex = (index + 1) % ids.length;
|
||||
return getKey(ids[nextIndex]!, nextIndex);
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
if (e.key === 'ArrowLeft') {
|
||||
getFoliateView(sideBarBookKey)?.goLeft();
|
||||
} else if (e.key === 'ArrowRight') {
|
||||
getFoliateView(sideBarBookKey)?.goRight();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (ids.length === 0) return;
|
||||
const uniqueIds = new Set<string>();
|
||||
ids.forEach((id, index) => {
|
||||
@@ -49,6 +70,13 @@ const ReaderContent = () => {
|
||||
});
|
||||
}, [ids, settings]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [sideBarBookKey]);
|
||||
|
||||
const handleSideBarResize = (newWidth: string) => {
|
||||
setSideBarWidth(newWidth);
|
||||
settings.globalReadSettings.sideBarWidth = newWidth;
|
||||
@@ -152,7 +180,12 @@ const ReaderContent = () => {
|
||||
setSideBarBookKey={setSideBarBookKey}
|
||||
setHoveredBookKey={setHoveredBookKey}
|
||||
/>
|
||||
<FoliateViewer bookKey={key} bookDoc={bookDoc!} bookConfig={config!} />
|
||||
<FoliateViewer
|
||||
bookKey={key}
|
||||
bookDoc={bookDoc!}
|
||||
bookConfig={config!}
|
||||
handleKeyDown={handleKeyDown}
|
||||
/>
|
||||
<SectionInfo chapter={chapter} />
|
||||
<PageInfo bookFormat={book.format} section={section} pageinfo={pageinfo} />
|
||||
<FooterBar
|
||||
@@ -160,7 +193,6 @@ const ReaderContent = () => {
|
||||
progress={progress}
|
||||
isHoveredAnim={false}
|
||||
hoveredBookKey={hoveredBookKey}
|
||||
sideBarBookKey={sideBarBookKey}
|
||||
setHoveredBookKey={setHoveredBookKey}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -136,8 +136,7 @@ const TOCView: React.FC<{
|
||||
}
|
||||
};
|
||||
|
||||
const foliateView = getFoliateView(bookKey);
|
||||
useFoliateEvents(bookKey, foliateView, { onRelocate: tocRelocateHandler });
|
||||
useFoliateEvents(getFoliateView(bookKey), { onRelocate: tocRelocateHandler });
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentHref(href);
|
||||
|
||||
@@ -1,50 +1,24 @@
|
||||
import { useEffect } from 'react';
|
||||
import { FoliateView } from '@/app/reader/components/FoliateViewer';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
|
||||
type FoliateEventHandler = {
|
||||
onLoad?: (event: Event) => void;
|
||||
onRelocate?: (event: Event) => void;
|
||||
};
|
||||
|
||||
export const useFoliateEvents = (
|
||||
bookKey: string,
|
||||
view: FoliateView | null,
|
||||
handlers?: FoliateEventHandler,
|
||||
) => {
|
||||
const setProgress = useReaderStore((state) => state.setProgress);
|
||||
|
||||
const defaultLoadHandler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
console.log('load event:', detail);
|
||||
};
|
||||
|
||||
const defaultRelocateHandler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
// console.log('relocate:', detail);
|
||||
setProgress(
|
||||
bookKey,
|
||||
detail.fraction,
|
||||
detail.cfi,
|
||||
detail.tocItem?.href,
|
||||
detail.tocItem?.label,
|
||||
detail.section,
|
||||
detail.location,
|
||||
);
|
||||
};
|
||||
|
||||
const onLoad = handlers?.onLoad || defaultLoadHandler;
|
||||
const onRelocate = handlers?.onRelocate || defaultRelocateHandler;
|
||||
export const useFoliateEvents = (view: FoliateView | null, handlers?: FoliateEventHandler) => {
|
||||
const onLoad = handlers?.onLoad;
|
||||
const onRelocate = handlers?.onRelocate;
|
||||
|
||||
useEffect(() => {
|
||||
if (!view) return;
|
||||
|
||||
view.addEventListener('load', onLoad);
|
||||
view.addEventListener('relocate', onRelocate);
|
||||
if (onLoad) view.addEventListener('load', onLoad);
|
||||
if (onRelocate) view.addEventListener('relocate', onRelocate);
|
||||
|
||||
return () => {
|
||||
view.removeEventListener('load', onLoad);
|
||||
view.removeEventListener('relocate', onRelocate);
|
||||
if (onLoad) view.removeEventListener('load', onLoad);
|
||||
if (onRelocate) view.removeEventListener('relocate', onRelocate);
|
||||
};
|
||||
}, [view, onLoad, onRelocate, handlers]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user