Unified keydown handling

This commit is contained in:
chrox
2024-10-28 17:01:26 +01:00
parent 572a97febe
commit 4457d9b6fb
7 changed files with 70 additions and 63 deletions
+1 -1
View File
@@ -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]);
};