Update Components

demo
NB 4 years ago
parent 802d8d8c08
commit eb0dc1fdf2
  1. 5
      README.md
  2. 1
      package.json
  3. BIN
      public/images/logo.png
  4. BIN
      public/images/reactEpubIcon.png
  5. 7
      src/components/footer/Item.tsx
  6. 3
      src/components/header/Layout.tsx
  7. 13
      src/components/header/Logo.tsx
  8. 34
      src/components/learning/SortedBtn.tsx
  9. 10
      src/components/learning/SortedBtnWrapper.tsx
  10. 4
      src/components/nav/NavItem.tsx
  11. 0
      src/components/note/Layout.tsx
  12. 0
      src/components/note/highlight/PageNum.tsx
  13. 0
      src/components/note/highlight/Post.tsx
  14. 0
      src/components/note/highlight/Title.tsx
  15. 0
      src/components/note/highlight/Wrapper.tsx
  16. 0
      src/components/option/ControlIconBtn.tsx
  17. 29
      src/components/option/ControlIconBtnWrapper.tsx
  18. 7
      src/components/sideMenu/Wrapper.tsx
  19. 99
      src/containers/Header.tsx
  20. 6
      src/containers/Reader.tsx
  21. 43
      src/containers/menu/Note.tsx
  22. 85
      src/containers/menu/Option.tsx
  23. 8
      src/containers/menu/commons/Highlight.tsx
  24. 2
      src/index.tsx
  25. 4
      src/lib/styles/viewerLayout.ts

@ -1,11 +1,10 @@
<div align=left>
<div align=center>
<br />
<a href="https://github.com/altmshfkgudtjr/react-epub-viewer"><img src="https://user-images.githubusercontent.com/47492535/115000155-73a3ae80-9edd-11eb-8ae9-a19e1c012d35.png" alt="react_epub" style="zoom:50%;" /></a>
<a href="https://github.com/altmshfkgudtjr/react-epub-viewer"><img src="https://user-images.githubusercontent.com/47492535/115026922-02c0be80-9efe-11eb-8c0c-40379e3249d1.png" alt="react_epub" style="zoom:50%;" /></a>
<br />
<br />
</div>
# React-Epub-Viewer
[![Latest Stable Version](https://img.shields.io/npm/v/react-epub-viewer.svg?style=for-the-badge)](https://www.npmjs.com/package/react-epub-viewer) [![License](https://img.shields.io/badge/license-mit-red.svg?style=for-the-badge)](https://www.npmjs.com/package/react-epub-viewer)

@ -18,7 +18,6 @@
"lib",
"README.md"
],
"homepage": "https://altmshfkgudtjr.github.io/react-epub-viewer",
"repository": {
"type": "git",
"url": "https://github.com/altmshfkgudtjr/react-epub-viewer"

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

@ -16,8 +16,15 @@ const Container = styled.div`
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
& > span {
color: ${palette.gray4};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`;

@ -9,8 +9,7 @@ const Layout = styled.div`
align-items: center;
justify-content: center;
width: 100%;
height: 54px;
background-color: ${palette.white};
height: 64px;
z-index: ${zIndex.header};
`;

@ -2,11 +2,12 @@ import styled from 'styled-components'
// lib
import * as styles from 'lib/styles/styles'
import palette from 'lib/styles/palette'
import { mediaQuery } from 'lib/styles/media'
const Logo = () => {
return (
<Wrapper href="https://github.com/altmshfkgudtjr/react-epub-viewer" target="__blank__">
<Img src="react-epub-viewer/images/reactEpubIcon.png" alt="Logo" />
<Img src="/images/logo.png" alt="Logo" />
</Wrapper>
);
}
@ -18,18 +19,22 @@ const Wrapper = styled.a`
outline: none;
margin-left: 16px;
background-color: rgba(0,0,0,0);
transition: .3s ${styles.transition};
transition: .2s ${styles.transition};
border-radius: 8px;
padding: 4px 8px;
cursor: pointer;
${mediaQuery(700)} {
display: none;
}
&:focus, &:hover {
background-color: ${palette.blue1};
background-color: ${palette.blue0};
}
`;
const Img = styled.img`
height: 32px;
height: 44px;
`;
export default Logo

@ -1,34 +0,0 @@
import styled from 'styled-components'
// lib
import * as styles from 'lib/styles/styles'
import palette from 'lib/styles/palette'
const SortedBtn = ({ text, isSelected, onClick }: Props) => {
return <Btn isSelected={isSelected} onClick={onClick}>{text}</Btn>;
}
const Btn = styled.button<{isSelected: boolean}>`
height: 20px;
line-height: 20px;
font-size: 14px;
cursor: pointer;
text-align: center;
margin-left: 16px;
color: ${({isSelected}) => isSelected
? palette.blue3
: palette.gray4
};
transition: .2s ${styles.transition};
&:hover {
color: ${palette.blue3};
}
`;
interface Props {
text: string;
isSelected: boolean;
onClick: () => void;
}
export default SortedBtn

@ -1,10 +0,0 @@
import styled from 'styled-components'
const SortedBtnWrapper = styled.div`
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 24px 24px 24px;
`;
export default SortedBtnWrapper

@ -33,6 +33,10 @@ const Content = styled.button`
margin-left: 12px;
}
}
&:last-child {
margin-bottom: 32px;
}
`;
interface Props {

@ -0,0 +1,29 @@
import styled from 'styled-components'
// components
import OptionWrapper from 'components/option/OptionWrapper'
import OptionTitle from 'components/option/OptionTitle'
const ControlIconBtnWrapper = ({ title, children }: Props) => {
return (
<OptionWrapper>
<OptionTitle>{title}</OptionTitle>
<BtnWrapper>
{children}
</BtnWrapper>
</OptionWrapper>
);
}
const BtnWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-around;
padding: 8px 0;
`;
interface Props {
title: string;
children: any[]
}
export default ControlIconBtnWrapper

@ -24,6 +24,7 @@ const Container = styled.div`
flex-direction: column;
position: fixed;
width: 340px;
max-width: 95vw;
height: 100vh;
top: 0;
right: 0;
@ -33,9 +34,9 @@ const Container = styled.div`
border-radius: 16px 0 0 16px;
transform: ${({ show }: { show: boolean }) => show
? `translateX(0px) scale(1)`
: `translateX(420px) scale(.8)`
: `translateX(420px) scale(.9)`
};
transition: .3s ${styles.transition};
transition: .4s ${styles.transition};
overflow-y: auto;
${styles.scrollbar()};
`;
@ -46,7 +47,7 @@ const Header = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 30px;
padding-top: 4px;
& > span {
padding-left: 24px;

@ -1,109 +1,24 @@
import { useState } from 'react'
// components
import Wrapper from 'components/header/Wrapper'
import Layout, { AutoLayout } from 'components/header/Layout'
import Logo from 'components/header/Logo'
import ControlBtn from 'components/header/ControlBtn'
import ControlIconBtn from 'components/header/ControlIconBtn'
import VerticalLine from 'components/header/VerticalLine'
// types
import { BookOption } from 'types/book'
const Header = ({
title,
bookOption,
const Header = ({
onNavToggle,
onOptionToggle,
onLearningToggle,
onBookOptionChange
onLearningToggle
}: Props) => {
const [isScrollHorizontal, setIsScrollHorizontal] = useState<boolean>(true);
const [viewType, setViewType] = useState<ViewType>({
active: true,
spread: true
});
/**
* Select view direction
* @param type Direction
*/
const onClickDirection = (type: "Horizontal" | "Vertical") => {
if (type === "Horizontal") {
setIsScrollHorizontal(true);
setViewType({ ...viewType, active: true });
onBookOptionChange({
...bookOption,
flow: "paginated"
});
} else {
setIsScrollHorizontal(false);
setViewType({ ...viewType, active: false });
onBookOptionChange({
...bookOption,
flow: "scrolled-doc"
});
}
}
/**
* Select isSpread
* @param isSpread Whether spread view
*/
const onClickViewType = (isSpread: boolean) => {
if (isSpread) {
setViewType({ ...viewType, spread: true });
onBookOptionChange({
...bookOption,
spread: "auto"
});
} else {
setViewType({ ...viewType, spread: false });
onBookOptionChange({
...bookOption,
spread: "none"
});
}
}
return (
<Wrapper>
<Layout>
<AutoLayout>
<Logo />
<div>
<Logo />
<ControlBtn message="Contents" onClick={onNavToggle} />
<ControlBtn message="Setting" onClick={onOptionToggle} />
<ControlBtn message="Highlights" onClick={onLearningToggle} />
</div>
<div>
<ControlIconBtn type="ScrollHorizontal"
alt="Horizontal View"
active={true}
isSelected={isScrollHorizontal}
onClick={() => onClickDirection("Horizontal")} />
<ControlIconBtn type="ScrollVertical"
alt="Vertical View"
active={true}
isSelected={!isScrollHorizontal}
onClick={() => onClickDirection("Vertical")} />
<VerticalLine />
<ControlIconBtn type="BookOpen"
alt="Two Page View"
active={viewType.active}
isSelected={viewType.spread}
onClick={() => onClickViewType(true)} />
<ControlIconBtn type="BookClose"
alt="One Page View"
active={viewType.active}
isSelected={!viewType.spread}
onClick={() => onClickViewType(false)} />
</div>
</AutoLayout>
</Layout>
</Wrapper>
@ -111,17 +26,9 @@ const Header = ({
}
interface Props {
title: string;
bookOption: BookOption;
onNavToggle: (value?: boolean) => void;
onOptionToggle: (value?: boolean) => void;
onLearningToggle: (value?: boolean) => void;
onBookOptionChange: (bookOption: BookOption) => void;
}
type ViewType = {
active: boolean,
spread: boolean
}
export default Header

@ -32,7 +32,6 @@ import Toc from 'types/toc'
const Reader = ({ url, loadingView }: Props) => {
const dispatch = useDispatch();
const book = useSelector<RootState, Book>(state => state.book.book);
const currentLocation = useSelector<RootState, Page>(state => state.book.currentLocation);
const viewerRef = useRef<ViewerRef | null>(null);
@ -138,12 +137,9 @@ const Reader = ({ url, loadingView }: Props) => {
return (<>
<ViewerWrapper>
<Header
title={book.title}
bookOption={bookOption}
onNavToggle={onNavToggle}
onOptionToggle={onOptionToggle}
onLearningToggle={onLearningToggle}
onBookOptionChange={onBookOptionChange}
/>
<Viewer
@ -177,10 +173,12 @@ const Reader = ({ url, loadingView }: Props) => {
<Option
control={optionControl}
bookStyle={bookStyle}
bookOption={bookOption}
bookFlow={bookOption.flow}
onToggle={onOptionToggle}
emitEvent={emitEvent}
onBookStyleChange={onBookStyleChange}
onBookOptionChange={onBookOptionChange}
ref={optionRef}
/>

@ -4,9 +4,7 @@ import { useSelector } from 'react-redux'
import Highlight from 'containers/menu/commons/Highlight'
// components
import Wrapper from 'components/sideMenu/Wrapper'
import LearningLayout from 'components/learning/Layout'
import SortedBtnWrapper from 'components/learning/SortedBtnWrapper'
import SortedBtn from 'components/learning/SortedBtn'
import LearningLayout from 'components/note/Layout'
import MenuEmpty from 'components/sideMenu/MenuEmpty'
// types
import { RootState } from 'slices'
@ -22,36 +20,20 @@ const Note = ({
viewerRef
}: Props, ref: any) => {
const highlights = useSelector<RootState, HighlightType[]>(state => state.book.highlights);
const [sorted, setSorted] = useState<Sorted>("CART");
const [highlightList, setHighlightList] = useState<any[]>([]);
/**
* Select sort type
* @param type Viewed or Created
*/
const onSortedClick = (type: Sorted) => setSorted(type);
/** Set highlight contents */
useEffect(() => {
const sortedKey = sorted === "LOOK"
? "accessTime"
: "createTime";
const highlightList = highlights.slice().sort(function (a, b) {
return new Date(b[sortedKey]).getTime() - new Date(a[sortedKey]).getTime();
});
const Items = highlightList.map(h => <Highlight key={h.key}
highlight={h}
onClick={onClickHighlight}
emitEvent={emitEvent}
viewerRef={viewerRef} />
const Items = highlights.map(h => <Highlight key={h.key}
highlight={h}
onClick={onClickHighlight}
emitEvent={emitEvent}
viewerRef={viewerRef} />
);
setHighlightList(Items);
}, [
viewerRef,
sorted,
highlights,
onClickHighlight,
emitEvent,
@ -65,19 +47,6 @@ const Note = ({
onClose={onToggle}
ref={ref} >
<LearningLayout>
<SortedBtnWrapper>
<SortedBtn
text="viewed"
isSelected={sorted === "LOOK"}
onClick={() => onSortedClick("LOOK")}
/>
<SortedBtn
text="created"
isSelected={sorted === "CART"}
onClick={() => onSortedClick("CART")}
/>
</SortedBtnWrapper>
{highlightList.length > 0
? highlightList
: <MenuEmpty text="Empty highlights!" />

@ -5,23 +5,33 @@ import Wrapper from 'components/sideMenu/Wrapper'
import OptionLayout from 'components/option/Layout'
import OptionDropdown from 'components/option/Dropdown'
import OptionSlider from 'components/option/Slider'
import ControlIconBtnWrapper from 'components/option/ControlIconBtnWrapper'
import ControlIconBtn from 'components/option/ControlIconBtn'
// types
import { BookStyle, BookFontFamily, BookFlow } from 'types/book'
import { MenuControl } from 'lib/hooks/useMenu'
import { BookOption } from 'types/book'
const Option = ({
control,
bookStyle,
bookOption,
bookFlow,
onToggle,
emitEvent,
onBookStyleChange
onBookStyleChange,
onBookOptionChange
}: Props, ref: any) => {
const [fontFamily, setFontFamily] = useState<BookFontFamily>(bookStyle.fontFamily);
const [fontSize, setFontSize] = useState<number>(bookStyle.fontSize);
const [lineHeight, setLineHeight] = useState<number>(bookStyle.lineHeight);
const [marginHorizontal, setMarginHorizontal] = useState<number>(bookStyle.marginHorizontal);
const [marginVertical, setMarginVertical] = useState<number>(bookStyle.marginVertical);
const [isScrollHorizontal, setIsScrollHorizontal] = useState<boolean>(true);
const [viewType, setViewType] = useState<ViewType>({
active: true,
spread: true
});
/** Change font family */
@ -48,6 +58,48 @@ const Option = ({
}
}
/**
* Select view direction
* @param type Direction
*/
const onClickDirection = (type: "Horizontal" | "Vertical") => {
if (type === "Horizontal") {
setIsScrollHorizontal(true);
setViewType({ ...viewType, active: true });
onBookOptionChange({
...bookOption,
flow: "paginated"
});
} else {
setIsScrollHorizontal(false);
setViewType({ ...viewType, active: false });
onBookOptionChange({
...bookOption,
flow: "scrolled-doc"
});
}
}
/**
* Select isSpread
* @param isSpread Whether spread view
*/
const onClickViewType = (isSpread: boolean) => {
if (isSpread) {
setViewType({ ...viewType, spread: true });
onBookOptionChange({
...bookOption,
spread: "auto"
});
} else {
setViewType({ ...viewType, spread: false });
onBookOptionChange({
...bookOption,
spread: "none"
});
}
}
/* Save userdata */
// TODO Fix the infinite re-rendering issue, when inlcude `onBookStyleChange` to dependencies array.
@ -83,6 +135,30 @@ const Option = ({
onClose={onToggle}
ref={ref}>
<OptionLayout>
<ControlIconBtnWrapper title="View Direction">
<ControlIconBtn type="ScrollHorizontal"
alt="Horizontal View"
active={true}
isSelected={isScrollHorizontal}
onClick={() => onClickDirection("Horizontal")} />
<ControlIconBtn type="ScrollVertical"
alt="Vertical View"
active={true}
isSelected={!isScrollHorizontal}
onClick={() => onClickDirection("Vertical")} />
</ControlIconBtnWrapper>
<ControlIconBtnWrapper title="View Spread">
<ControlIconBtn type="BookOpen"
alt="Two Page View"
active={viewType.active}
isSelected={viewType.spread}
onClick={() => onClickViewType(true)} />
<ControlIconBtn type="BookClose"
alt="One Page View"
active={viewType.active}
isSelected={!viewType.spread}
onClick={() => onClickViewType(false)} />
</ControlIconBtnWrapper>
<OptionDropdown title="Font"
defaultValue={fontFamily}
valueList={["Origin", "Roboto"]}
@ -123,10 +199,12 @@ const Option = ({
interface Props {
control: MenuControl;
bookStyle: BookStyle;
bookOption: BookOption;
bookFlow: BookFlow;
onToggle: () => void;
emitEvent: () => void;
onBookStyleChange: (bookStyle: BookStyle) => void;
onBookOptionChange: (bookOption: BookOption) => void;
}
type SliderType = "FontSize"
@ -134,4 +212,9 @@ type SliderType = "FontSize"
| "MarginHorizontal"
| "MarginVertical";
type ViewType = {
active: boolean,
spread: boolean
}
export default React.forwardRef(Option)

@ -1,9 +1,9 @@
import { useDispatch } from 'react-redux'
// components
import Wrapper from 'components/learning/highlight/Wrapper'
import Title from 'components/learning/highlight/Title'
import Post from 'components/learning/highlight/Post'
import PageNum from 'components/learning/highlight/PageNum'
import Wrapper from 'components/note/highlight/Wrapper'
import Title from 'components/note/highlight/Title'
import Post from 'components/note/highlight/Post'
import PageNum from 'components/note/highlight/PageNum'
// slices
import { updateHighlight } from 'slices/book'
// utils

@ -1,6 +1,6 @@
import ReactDOM from 'react-dom';
import Reader from 'containers/Reader'
const EPUB_URL = "react-epub-viewer/files/Alices Adventures in Wonderland.epub";
const EPUB_URL = "/files/Alices Adventures in Wonderland.epub";
ReactDOM.render(<Reader url={EPUB_URL} />, document.getElementById('root'));

@ -2,9 +2,9 @@ import ViewerLayout from 'types/viewerLayout'
/** Epub viewer layout size */
const viewerLayout: ViewerLayout = {
MIN_VIEWER_WIDTH: 600,
MIN_VIEWER_WIDTH: 300,
MIN_VIEWER_HEIGHT: 300,
VIEWER_HEADER_HEIGHT: 54,
VIEWER_HEADER_HEIGHT: 64,
VIEWER_FOOTER_HEIGHT: 60,
VIEWER_SIDEMENU_WIDTH: 0
}

Loading…
Cancel
Save