Add footer bar for flip paging
This commit is contained in:
@@ -48,6 +48,8 @@ export interface FoliateView extends HTMLElement {
|
||||
init: (options: { lastLocation: string }) => void;
|
||||
goTo: (href: string) => void;
|
||||
goToFraction: (fraction: number) => void;
|
||||
goLeft: () => void;
|
||||
goRight: () => void;
|
||||
renderer: {
|
||||
setStyles: (css: string) => void;
|
||||
next: () => Promise<void>;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { BsLayoutSidebar } from 'react-icons/bs';
|
||||
import { VscLayoutSidebarLeft, VscLayoutSidebarLeftOff } from 'react-icons/vsc';
|
||||
import { RiArrowLeftWideLine, RiArrowRightWideLine } from 'react-icons/ri';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore, DEFAULT_BOOK_STATE } from '@/store/readerStore';
|
||||
@@ -20,6 +20,7 @@ const ReaderContent = () => {
|
||||
|
||||
const { envConfig } = useEnv();
|
||||
const { books, settings, initBookState, saveConfig, saveSettings } = useReaderStore();
|
||||
const { getFoliateView } = useReaderStore();
|
||||
|
||||
const [sideBarWidth, setSideBarWidth] = useState(
|
||||
settings.globalReadSettings.sideBarWidth ?? '25%',
|
||||
@@ -33,6 +34,8 @@ const ReaderContent = () => {
|
||||
const bookStates = ids.map((id, index) => books[getKey(id, index)] || DEFAULT_BOOK_STATE);
|
||||
const [sideBarBookKey, setSideBarBookKey] = useState(getKey(ids[0] ?? '', 0));
|
||||
|
||||
let sliderProgress = 0;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (ids.length === 0) return;
|
||||
const uniqueIds = new Set<string>();
|
||||
@@ -70,6 +73,24 @@ const ReaderContent = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
const handleProgressChange = (bookKey: string, event: React.ChangeEvent) => {
|
||||
console.log('progress change', bookKey, event);
|
||||
const newProgress = parseInt((event.target as HTMLInputElement).value, 10);
|
||||
sliderProgress = newProgress;
|
||||
const foliateView = getFoliateView(bookKey);
|
||||
foliateView?.goToFraction(newProgress / 100.0);
|
||||
};
|
||||
|
||||
const handleGoPrev = (bookKey: string) => {
|
||||
const foliateView = getFoliateView(bookKey);
|
||||
foliateView?.goLeft();
|
||||
};
|
||||
|
||||
const handleGoNext = (bookKey: string) => {
|
||||
const foliateView = getFoliateView(bookKey);
|
||||
foliateView?.goRight();
|
||||
};
|
||||
|
||||
const getGridTemplate = () => {
|
||||
const count = ids.length;
|
||||
const aspectRatio = window.innerWidth / window.innerHeight;
|
||||
@@ -135,6 +156,17 @@ const ReaderContent = () => {
|
||||
const key = getKey(ids[index]!, index);
|
||||
const { book, config, bookDoc } = bookState;
|
||||
if (!book || !config || !bookDoc) return null;
|
||||
const { section, pageinfo, progress } = config;
|
||||
const pageInfo =
|
||||
book.format === 'PDF'
|
||||
? section
|
||||
? `${section.current + 1} / ${section.total}`
|
||||
: ''
|
||||
: pageinfo
|
||||
? `Loc. ${pageinfo.current + 1} / ${pageinfo.total}`
|
||||
: '';
|
||||
const progressInfo = progress ? `${Math.round(progress * 100)}%` : '';
|
||||
sliderProgress = progress ? progress * 100 : 0;
|
||||
return (
|
||||
<div key={key} className='relative h-full w-full overflow-hidden'>
|
||||
<div
|
||||
@@ -167,6 +199,34 @@ const ReaderContent = () => {
|
||||
</div>
|
||||
</div>
|
||||
<FoliateViewer bookKey={key} bookDoc={bookDoc!} bookConfig={config!} />
|
||||
<div className='pageinfo absolute bottom-0 left-0 right-0 flex h-12 items-center justify-center'>
|
||||
<h2 className='px-2 text-center font-sans text-xs font-extralight text-slate-500'>
|
||||
{pageInfo}
|
||||
</h2>
|
||||
</div>
|
||||
<div className='footer-bar shadow-xs absolute bottom-0 flex h-12 w-full items-center bg-gray-100 px-4 opacity-0 transition-opacity duration-300 hover:opacity-100'>
|
||||
<button
|
||||
className='btn btn-ghost mx-2 h-8 min-h-8 w-8 p-0'
|
||||
onClick={() => handleGoPrev(key)}
|
||||
>
|
||||
<RiArrowLeftWideLine size={20} />
|
||||
</button>
|
||||
<span className='mx-2 text-center text-sm text-black'>{progressInfo}</span>
|
||||
<input
|
||||
type='range'
|
||||
className='mx-2 w-full'
|
||||
min={0}
|
||||
max={100}
|
||||
value={sliderProgress}
|
||||
onChange={(e) => handleProgressChange(key, e)}
|
||||
/>
|
||||
<button
|
||||
className='btn btn-ghost mx-2 h-8 min-h-8 w-8 p-0'
|
||||
onClick={() => handleGoNext(key)}
|
||||
>
|
||||
<RiArrowRightWideLine size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -110,10 +110,10 @@ const SideBar: React.FC<{
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='border-b px-3 shadow-sm'>
|
||||
<div className='border-b px-3'>
|
||||
<BookCard cover={book.coverImageUrl!} title={book.title} author={book.author} />
|
||||
</div>
|
||||
<div className='sidebar-content overflow-y-auto'>
|
||||
<div className='sidebar-content overflow-y-auto border-b shadow-inner'>
|
||||
{activeTab === 'toc' && bookDoc!.toc && (
|
||||
<TOCView toc={bookDoc!.toc} bookKey={bookKey} currentHref={currentHref} />
|
||||
)}
|
||||
|
||||
@@ -21,8 +21,15 @@ export const useFoliateEvents = (
|
||||
|
||||
const defaultRelocateHandler = (event: Event) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
// console.log('relocate:', detail);
|
||||
setProgress(bookKey, detail.fraction, detail.cfi, detail.tocItem?.href, detail.location);
|
||||
console.log('relocate:', detail);
|
||||
setProgress(
|
||||
bookKey,
|
||||
detail.fraction,
|
||||
detail.cfi,
|
||||
detail.tocItem?.href,
|
||||
detail.section,
|
||||
detail.location,
|
||||
);
|
||||
};
|
||||
|
||||
const onLoad = handlers?.onLoad || defaultLoadHandler;
|
||||
|
||||
@@ -30,6 +30,7 @@ interface ReaderStore {
|
||||
progress: number,
|
||||
location: string,
|
||||
href: string,
|
||||
section: PageInfo,
|
||||
pageinfo: PageInfo,
|
||||
) => void;
|
||||
setFoliateView: (key: string, view: FoliateView) => void;
|
||||
@@ -137,6 +138,7 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
|
||||
progress: number,
|
||||
location: string,
|
||||
href: string,
|
||||
section: PageInfo,
|
||||
pageinfo: PageInfo,
|
||||
) =>
|
||||
set((state) => {
|
||||
@@ -153,6 +155,7 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
|
||||
href,
|
||||
progress,
|
||||
location,
|
||||
section,
|
||||
pageinfo,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface Book {
|
||||
|
||||
export interface PageInfo {
|
||||
current: number;
|
||||
next: number;
|
||||
next?: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface BookConfig {
|
||||
progress?: number;
|
||||
location?: string;
|
||||
href?: string;
|
||||
section?: PageInfo;
|
||||
pageinfo?: PageInfo;
|
||||
bookmarks?: BookNote[];
|
||||
annotations?: BookNote[];
|
||||
|
||||
Reference in New Issue
Block a user