You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

424 lines
12 KiB

import { useState, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Provider } from "react-redux";
import { ReactEpubViewer } from "react-epub-viewer";
// import styled from "styled-components";
// containers
import Header from "containers/Header";
import Footer from "containers/Footer";
import Nav from "containers/menu/Nav";
import Option from "containers/menu/Option";
import Learning from "containers/menu/Note";
import ContextMenu from "containers/commons/ContextMenu";
import Snackbar from "containers/commons/Snackbar";
// components
import ViewerWrapper from "components/commons/ViewerWrapper";
import LoadingView from "LoadingView";
// import BookInfo from "components/nav/BookInfo";
// slices
import store from "slices";
import { updateBook, updateCurrentPage, updateToc } from "slices/book";
// hooks
import useMenu from "lib/hooks/useMenu";
import useHighlight from "lib/hooks/useHighlight";
// styles
import "lib/styles/readerStyle.css";
import viewerLayout from "lib/styles/viewerLayout";
// types
import { RootState } from "slices";
import { ViewerRef } from "types";
import Book, { BookStyle, BookOption } from "types/book";
import Page from "types/page";
import Toc from "types/toc";
// import { title } from "node:process";
import ArrowBackIosRoundedIcon from "@material-ui/icons/ArrowBackIosRounded";
import ArrowForwardIosRoundedIcon from "@material-ui/icons/ArrowForwardIosRounded";
import Setting from "components/Setting/setting";
// import MoveBtn from "components/footer/MoveBtn";
const Reader = ({ url, loadingView }: Props) => {
const dispatch = useDispatch();
const currentLocation = useSelector<RootState, Page>((state) => {
return state.book.currentLocation;
});
const viewerRef = useRef<ViewerRef | any>(null);
const navRef = useRef<HTMLDivElement | null>(null);
const optionRef = useRef<HTMLDivElement | null>(null);
const learningRef = useRef<HTMLDivElement | null>(null);
const [isContextMenu, setIsContextMenu] = useState<boolean>(false);
const [bookStyle, setBookStyle] = useState<BookStyle>({
fontFamily: "Sans",
color: "red",
fontSize: 14,
lineHeight: 1.4,
marginHorizontal: 15,
marginVertical: 5,
});
const [bookOption, setBookOption] = useState<BookOption>({
flow: "paginated",
resizeOnOrientationChange: true,
spread: "auto",
});
const [navControl, onNavToggle] = useMenu(navRef, 300);
const [optionControl, onOptionToggle, emitEvent] = useMenu(optionRef, 300);
const [learningControl, onLearningToggle] = useMenu(learningRef, 300);
const {
selection,
onSelection,
onClickHighlight,
onAddHighlight,
onRemoveHighlight,
onUpdateHighlight,
} = useHighlight(viewerRef, setIsContextMenu, bookStyle, bookOption.flow);
/**
* Change Epub book information
* @param book Epub Book Info
*/
const loadFont = () => {
const iframe = document.querySelector("iframe");
const new_style_element = document.createElement("style");
new_style_element.textContent = `@font-face {
font-family: "Nazanin";
src: url(/react-epub-viewer/css/Nazanin.woff);
}
@font-face {
font-family: "Sans";
src: url(/react-epub-viewer/css/IRANSansWebFaNum.woff);
}`;
const node =
iframe && iframe.contentWindow && iframe.contentWindow.document;
// node && node.head && node.head.appendChild(new_style_element);
};
const onBookInfoChange = (book: Book) => {
loadFont();
dispatch(updateBook(book));
};
/**
* Change Epub location
* @param loc epubCFI or href
*/
const onLocationChange = (loc: string) => {
if (!viewerRef.current) return;
viewerRef.current.setLocation(loc);
};
/**
* Move page
* @param type Direction
*/
const onPageMove = (type: "NEXT" | "PREV") => {
//loadFont();
const node = viewerRef.current;
if (!node || !node.prevPage || !node.nextPage) return;
type === "NEXT" && node.nextPage();
type === "PREV" && node.prevPage();
};
/**
* Set toc
* @param toc Table of Epub contents
*/
const onTocChange = (toc: Toc[]) => {
// loadFont();
dispatch(updateToc(toc));
};
/**
* Set Epub viewer styles
* @param bokkStyle_ viewer style
*/
const onBookStyleChange = (bookStyle_: BookStyle) => setBookStyle(bookStyle_);
/**
* Set Epub viewer options
* @param bookOption_ viewer option
*/
const onBookOptionChange = (bookOption_: BookOption) =>
setBookOption(bookOption_);
/**
* Change current page
* @param page Epub page
*/
const onPageChange = (page: Page) => dispatch(updateCurrentPage(page));
/**
* ContextMenu on
* @param cfiRange CfiRange
*/
const onContextMenu = (cfiRange: string) => {
const result = onSelection(cfiRange);
setIsContextMenu(result);
};
/** ContextMenu off */
const onContextmMenuRemove = () => setIsContextMenu(false);
// const [settingicon, setsettingicon] = useState(false);
// const changeiconsettinghandler = () => {
// setsettingicon(!settingicon);
// };
const [isScrollHorizontal, setIsScrollHorizontal] = useState(true);
const onClickDirection = (type: "Horizontal" | "Vertical") => {
if (type === "Horizontal") {
onBookOptionChange({
...bookOption,
flow: "paginated",
});
} else if (type === "Vertical") {
onBookOptionChange({
...bookOption,
flow: "scrolled-doc",
});
}
};
const [viewType, setViewType] = useState({
spread: true,
});
const onClickViewType = (isSpread: boolean) => {
if (isSpread) {
setViewType({ ...viewType, spread: true });
onBookOptionChange({
...bookOption,
spread: "auto",
});
} else {
setViewType({ ...viewType, spread: false });
onBookOptionChange({
...bookOption,
spread: "none",
});
}
};
const book = useSelector<RootState, Book>((state) => state.book.book);
const [CountPage, setCountPage] = useState(0);
const [isOpen, setIsOpen] = useState(false);
const [color, setcolor] = useState("light-white");
// const Colors = [
// { name: "dark-white", value: "#fff" },
// { name: "dark-blue", value: "#fff" },
// { name: "dark-brown", value: "#fff4e1" },
// { name: "light-white", value: "#121212" },
// { name: "light-brown", value: "#af622e" },
// { name: "light-blue", value: "#5858df" },
// ];
const readyColors = [
{ name: "dark-white", bgColor: "#4e4e4e", color: "#fff" },
{ name: "light-white", bgColor: "#fff", color: "#292929" },
{ name: "dark-blue", bgColor: "#5858d3", color: "#fff" },
{ name: "dark-brown", bgColor: "#af622e", color: "#fff4e1" },
{ name: "light-brown", bgColor: "#fff4e1", color: "#af622e" },
{ name: "light-blue", bgColor: "#C3DDFF", color: "#5858df" },
];
const colorHandler = (color: any) => {
let myColor = readyColors.filter((item) => item.name === color);
return myColor[0].bgColor;
};
return (
<>
<ViewerWrapper>
<Header
nameBook={book.title}
title={currentLocation.chapterName}
onNavToggle={onNavToggle}
onOptionToggle={onOptionToggle}
onLearningToggle={onLearningToggle}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
<Setting
setcolor={setcolor}
setBookStyle={setBookStyle}
bookStyle={bookStyle}
bookOption={bookOption}
setBookOption={setBookOption}
isOpen={isOpen}
/>
<nav
style={{
backgroundColor: colorHandler(color),
color: "green",
display: "flex",
justifyContent: "center",
paddingTop: "1rem",
}}
>
{window.innerWidth < 768 ? (
<>
<nav onClick={() => setCountPage(CountPage + 1)}>
<button
style={{
opacity: "0",
position: "absolute",
left: "0",
width: "20%",
height: "85%",
top: "6rem",
zIndex: 10,
}}
onClick={() => onPageMove("NEXT")}
>
<ArrowBackIosRoundedIcon />
</button>
</nav>
</>
) : (
<>
<nav
style={{ display: "flex" }}
onClick={() => setCountPage(CountPage + 1)}
>
<button onClick={() => onPageMove("NEXT")}>
<ArrowBackIosRoundedIcon />
</button>
</nav>
</>
)}
<nav className="nav-book">
<ReactEpubViewer
url={url}
viewerLayout={viewerLayout}
viewerStyle={bookStyle}
viewerOption={bookOption}
onBookInfoChange={onBookInfoChange}
onPageChange={onPageChange}
onTocChange={onTocChange}
onSelection={onContextMenu}
loadingView={loadingView || <LoadingView />}
ref={viewerRef}
/>
</nav>
{window.innerWidth < 768 ? (
<>
<nav onClick={() => setCountPage(CountPage - 1)}>
<button
style={{
opacity: "0",
position: "absolute",
right: "0",
width: "20%",
height: "85%",
top: "6rem",
}}
onClick={() => onPageMove("PREV")}
>
<ArrowForwardIosRoundedIcon />
</button>
</nav>
</>
) : (
<>
<nav
style={{ display: "flex" }}
onClick={() => setCountPage(CountPage - 1)}
>
<button onClick={() => onPageMove("PREV")}>
<ArrowForwardIosRoundedIcon />
</button>
</nav>
</>
)}
</nav>
<Footer
viewType={viewType}
bookOption={bookOption}
onBookOptionChange={onBookOptionChange}
onClickViewType={onClickViewType}
onClickDirection={onClickDirection}
CountPage={CountPage}
title={currentLocation.chapterName}
nowPage={currentLocation.currentPage}
totalPage={currentLocation.totalPage}
onPageMove={onPageMove}
/>
</ViewerWrapper>
<Nav
control={navControl}
onToggle={onNavToggle}
onLocation={onLocationChange}
ref={navRef}
/>
<Option
control={optionControl}
bookStyle={bookStyle}
bookOption={bookOption}
bookFlow={bookOption.flow}
onToggle={onOptionToggle}
emitEvent={emitEvent}
onBookStyleChange={onBookStyleChange}
onBookOptionChange={onBookOptionChange}
ref={optionRef}
/>
<Learning
control={learningControl}
onToggle={onLearningToggle}
onClickHighlight={onClickHighlight}
emitEvent={emitEvent}
viewerRef={viewerRef}
ref={learningRef}
/>
<ContextMenu
active={isContextMenu}
viewerRef={viewerRef}
selection={selection}
onAddHighlight={onAddHighlight}
onRemoveHighlight={onRemoveHighlight}
onUpdateHighlight={onUpdateHighlight}
onContextmMenuRemove={onContextmMenuRemove}
/>
<Snackbar />
</>
);
};
const ReaderWrapper = ({ url, loadingView, colorHandler }: Props) => {
return (
<>
<Provider store={store}>
<Reader
colorHandler={colorHandler}
url={url}
loadingView={loadingView}
/>
</Provider>
</>
);
};
interface Props {
colorHandler?: () => void;
viewerStyle?: BookStyle;
url: string;
loadingView?: React.ReactNode;
isOpen?: any;
setIsOpen?: any;
setIsScrollHorizontal?: any;
color?: any;
}
export default ReaderWrapper;