From e4a862d142891596c4d5fced73670fa075f60686 Mon Sep 17 00:00:00 2001 From: Vut Pov Date: Sat, 9 May 2020 11:45:34 +0700 Subject: [PATCH 1/4] add two pages view --- src/components/BookComponent.tsx | 18 ++++- src/components/JumpControls.tsx | 2 +- src/components/OnePageView.tsx | 27 +++---- src/components/TwoPagesView.tsx | 118 +++++++++++++++++++++++++++++++ src/components/ViewSwitcher.tsx | 4 +- 5 files changed, 144 insertions(+), 25 deletions(-) create mode 100644 src/components/TwoPagesView.tsx diff --git a/src/components/BookComponent.tsx b/src/components/BookComponent.tsx index 7240c07..2f2fe35 100644 --- a/src/components/BookComponent.tsx +++ b/src/components/BookComponent.tsx @@ -1,5 +1,6 @@ import React, {createContext} from 'react' import OnePageView from './OnePageView' +import TwoPagesView from './TwoPagesView' export const BookContext = createContext({}) @@ -36,7 +37,7 @@ export interface IBookContext { } -class BookComponent extends React.Component{ +class BookComponent extends React.Component{ constructor(props: any){ super(props) this.state = { @@ -45,10 +46,18 @@ class BookComponent extends React.Component{ flagToReverse: false, mode: "one page", setBookContextState: (newState: IBookContext)=>{ - this.setState(oldState=> ({ + this.setState((oldState: any)=> ({ ...oldState, ...newState })) + }, + changePage: (indexToGo: number, goToPrevious: boolean)=>{ + const newCurrIndex = this.state.currIndex + indexToGo + + this.setState({ + currIndex: newCurrIndex, + flagToReverse: goToPrevious + }) } } } @@ -72,11 +81,14 @@ class BookComponent extends React.Component{ } render(){ + const {mode} = this.state + return {state=>( <> - + {mode === "one page" && } + {mode === "two pages" && } )} diff --git a/src/components/JumpControls.tsx b/src/components/JumpControls.tsx index 94fb235..e30e76c 100644 --- a/src/components/JumpControls.tsx +++ b/src/components/JumpControls.tsx @@ -17,7 +17,7 @@ const JumpControls = (props: any)=>{ } } }, - [inputValue]) + [inputValue, src.length, setBookContextState]) useEffect(()=>{ setInputValue(currIndex + 1) diff --git a/src/components/OnePageView.tsx b/src/components/OnePageView.tsx index 85768d7..808a0bd 100644 --- a/src/components/OnePageView.tsx +++ b/src/components/OnePageView.tsx @@ -1,4 +1,4 @@ -import React, {useState, useCallback, useEffect} from 'react' +import React, {useState, useEffect} from 'react' import {Transition, animated} from 'react-spring/renderprops' import styled, { } from 'styled-components' import BookComponentsController from './BookComponentsController' @@ -24,10 +24,9 @@ const PageContainer = styled.div` height: 100%; } ` - -const StyledImage = styled(animated.div)<{src:string}>` - width: 100%; - height: 100%; +const StyledImage = styled(animated.div)<{src:string, width:number | string, height: number| string}>` + width: ${props=> props.width? props.width: '100%'}; + height: ${props=> props.height? props.height: '100%'}; display: flex; justify-content: center; align-items: center; @@ -36,24 +35,16 @@ const StyledImage = styled(animated.div)<{src:string}>` ` const PageComponent = (props: any)=>{ - const {src} = props - return + const {src, width, height} = props + return } function BookComponent(props: any) { - const {src, currIndex, setBookContextState, flagToReverse} = props + const {src, currIndex, flagToReverse, changePage} = props const [prevDisable, setPrevDisable] = useState(true) const [nextDisable, setNextDisable] = useState(false) - const changePage = useCallback((indexToGo, goToPrevious)=>{ - const newCurrIndex = currIndex + indexToGo - setBookContextState({ - currIndex: newCurrIndex, - flagToReverse: goToPrevious - }) - - }, [currIndex]) useEffect(() => { setNextDisable(currIndex >= src.length - 1) @@ -77,8 +68,6 @@ function BookComponent(props: any) { return( {React.createElement(()=>)} @@ -100,4 +89,4 @@ function BookComponent(props: any) { ) } -export default BookComponent \ No newline at end of file +export {ComponentContainer, PageContainer, PageComponent, BookComponent as default } \ No newline at end of file diff --git a/src/components/TwoPagesView.tsx b/src/components/TwoPagesView.tsx new file mode 100644 index 0000000..6b5cb1f --- /dev/null +++ b/src/components/TwoPagesView.tsx @@ -0,0 +1,118 @@ +import React, {useState, useEffect, useCallback} from 'react' +import {Transition, animated} from 'react-spring/renderprops' +import BookComponentsController from './BookComponentsController' +import {ComponentContainer, PageComponent, PageContainer} from './OnePageView' +import { IBookContext } from './BookComponent' + +export default function TwoPagesView(props: any) { + let {src, currIndex, changePage, flagToReverse} = props + const [pagesToshow, setPagesToShow] = useState([]) + const [prevDisable, setPrevDisable] = useState(true) + const [nextDisable, setNextDisable] = useState(false) + + + useEffect(()=>{ + const shouldShowPage = (pageIndex: number)=>{ + return src.length > 0 && pageIndex <= src.length - 1 + } + + const newCurrIndex = currIndex % 2 === 0 ? currIndex: currIndex - 1 + + const shouldShowFirstPage = shouldShowPage(newCurrIndex) + if(shouldShowFirstPage){ + const shouldShowSecondPage = shouldShowPage(newCurrIndex + 1) + setPagesToShow([ + src[newCurrIndex], + shouldShowSecondPage? src[newCurrIndex + 1]: { + src: '', + alt: '', + thumbnail: '', + } + ]) + } + + setPrevDisable(newCurrIndex <= 1) + setNextDisable(newCurrIndex >= src.length - 2) + }, [currIndex, src]) + + const pageChangeClick = useCallback((indexToGo, flagToReverse)=>{ + const newIndex = currIndex + indexToGo + const shouldChangePage = newIndex >= 0 && newIndex < src.length + if(shouldChangePage){ + changePage(indexToGo, flagToReverse) + } + }, [src.length, currIndex, changePage]) + + return ( + + + item.src} + initial={{}} + from={{opacity: 1, transform: flagToReverse? "translate3d(-50%, 0, 0)": "translate3d(100%, 0, 0)"}} + enter={{ opacity: 1, transform: "translate3d(0%, 0, 0)" }} + leave={{ opacity: 0, transform: flagToReverse? "translate3d(100%, 0, 0)": "translate3d(-50%, 0, 0)"}} + > + { + currIndex=> style=>{ + return( + + {React.createElement(()=>{ + return + })} + + ) + } + } + + + item.src} + from={{opacity: 1, transform: flagToReverse? "translate3d(0%, 0, 0)": "translate3d(150%, 0, 0)"}} + enter={{ opacity: 1, transform: "translate3d(50%, 0, 0)" }} + leave={{ opacity: 0, transform: flagToReverse? "translate3d(150%, 0, 0)": "translate3d(0%, 0, 0)"}} + initial={{}} + > + { + currIndex=> style=>{ + return( + + {React.createElement(()=>{ + return + })} + + ) + } + } + + + { + pageChangeClick(-2, true) + + }} + nextDisable={nextDisable} + onNextClick={()=>{ + pageChangeClick(2, false) + }} + {...props} + /> + + ) +} + +interface Book { + name: string +} + diff --git a/src/components/ViewSwitcher.tsx b/src/components/ViewSwitcher.tsx index 5183a29..06a6867 100644 --- a/src/components/ViewSwitcher.tsx +++ b/src/components/ViewSwitcher.tsx @@ -12,13 +12,13 @@ export default function ViewSwitcher(props: IBookContext) { setBookContextState({ mode }) - },[]) + },[setBookContextState]) return ( From 716ddba5eff9e21439d9fdb7bea6291faa7d8720 Mon Sep 17 00:00:00 2001 From: Vut Pov Date: Sat, 9 May 2020 11:51:01 +0700 Subject: [PATCH 2/4] update jump control slider event --- src/components/JumpControls.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/JumpControls.tsx b/src/components/JumpControls.tsx index e30e76c..7f0f7d7 100644 --- a/src/components/JumpControls.tsx +++ b/src/components/JumpControls.tsx @@ -7,6 +7,7 @@ const JumpControls = (props: any)=>{ const onChange = useCallback( (value) => { + console.log(value, "hello") if(value){ const newCurrIndex = value -1 if(newCurrIndex < src.length && newCurrIndex >=0){ @@ -28,8 +29,8 @@ const JumpControls = (props: any)=>{ From b1b15ee45dd8432594654aeabc2f3cbdef7dfd5b Mon Sep 17 00:00:00 2001 From: Vut Pov Date: Sat, 9 May 2020 12:32:54 +0700 Subject: [PATCH 3/4] update component controller --- package.json | 2 +- src/components/BookComponentsController.tsx | 35 +++++++++++---------- src/components/JumpControls.tsx | 35 +++++++++++++++------ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 419a926..b6faef4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "image-viewer", - "version": "0.1.2", + "version": "0.1.3", "private": false, "dependencies": { "@testing-library/jest-dom": "^4.2.4", diff --git a/src/components/BookComponentsController.tsx b/src/components/BookComponentsController.tsx index b530efb..d00aac7 100644 --- a/src/components/BookComponentsController.tsx +++ b/src/components/BookComponentsController.tsx @@ -1,45 +1,48 @@ import React from 'react' import styled from 'styled-components' -import {Button, Popover} from 'antd' +import {Button} from 'antd' import ViewSwitcher from './ViewSwitcher' import JumpControls from './JumpControls' +import { + CaretLeftOutlined, + CaretRightOutlined, + } from '@ant-design/icons'; const ControlsContanter = styled.div` display: inline-flex; justify-content: space-between; - width: 500px; + width: 100%; ` export default function BookCoponentsController(props: any) { const {onPrevClick, prevDisable, onNextClick, nextDisable, ...restProps} = props return ( + + + style={{ + marginRight: 8 + }} + icon={} + /> + - - - }> - - - + diff --git a/src/components/JumpControls.tsx b/src/components/JumpControls.tsx index 7f0f7d7..dc553d8 100644 --- a/src/components/JumpControls.tsx +++ b/src/components/JumpControls.tsx @@ -1,13 +1,18 @@ import React, {useState, useCallback, useEffect} from 'react' -import {Row, Col, Slider, InputNumber} from 'antd' +import {Slider, InputNumber} from 'antd' +import styled from 'styled-components' + +const Container = styled.div` + width: 100%; + display: inline-flex; +` const JumpControls = (props: any)=>{ const {src, currIndex, setBookContextState} = props const [inputValue, setInputValue] = useState(currIndex) - + const [sliderValue, setSliderValue] = useState(currIndex) const onChange = useCallback( (value) => { - console.log(value, "hello") if(value){ const newCurrIndex = value -1 if(newCurrIndex < src.length && newCurrIndex >=0){ @@ -24,16 +29,27 @@ const JumpControls = (props: any)=>{ setInputValue(currIndex + 1) }, [currIndex]) - return - + useEffect(() => { + setSliderValue(inputValue) + }, [inputValue]) + + + const sliderRestProps = ()=>{ + return sliderValue === inputValue? {}: {value: inputValue} + } + + return - - + { value={inputValue} onChange={onChange} /> - - + } export default JumpControls From fb1bd05161e588b243ee55deb0d86272eb4bd163 Mon Sep 17 00:00:00 2001 From: Vut Pov Date: Mon, 11 May 2020 10:17:26 +0700 Subject: [PATCH 4/4] move state logic up to book component --- src/components/BookComponent.tsx | 63 ++++++++++++++++++++++++++------ src/components/JumpControls.tsx | 7 +++- src/components/OnePageView.tsx | 23 +----------- src/components/TwoPagesView.tsx | 31 +--------------- src/components/ViewSwitcher.tsx | 7 ++-- src/components/index.css | 3 ++ 6 files changed, 69 insertions(+), 65 deletions(-) create mode 100644 src/components/index.css diff --git a/src/components/BookComponent.tsx b/src/components/BookComponent.tsx index 2f2fe35..1e84b3c 100644 --- a/src/components/BookComponent.tsx +++ b/src/components/BookComponent.tsx @@ -1,6 +1,8 @@ import React, {createContext} from 'react' import OnePageView from './OnePageView' import TwoPagesView from './TwoPagesView' +import BookComponentsController from './BookComponentsController' +import './index.css' export const BookContext = createContext({}) @@ -10,16 +12,22 @@ export interface IBookPage { thumbnail?: string } -export const bookViewModes = [ +export const getBookViewModes = (currIndex = 0, srcLength = 0)=>[ { text: 'One Page', value: 'one page', - icon: '' + icon: '', + pagesToTurn: 1, + nextDisable: currIndex >= srcLength - 1, + prevDisable: currIndex === 0, }, { text: 'Two Pages', value: 'two pages', - icon: '' + icon: '', + pagesToTurn: 2, + nextDisable: currIndex >= srcLength - 2, + prevDisable: currIndex <= 1, } ] @@ -37,6 +45,11 @@ export interface IBookContext { } +const getPagesCountToTurn = (mode: string)=>{ + let pagesToTurn = getBookViewModes().find(item=> item.value === mode)?.pagesToTurn + return pagesToTurn || 0 +} + class BookComponent extends React.Component{ constructor(props: any){ super(props) @@ -51,16 +64,21 @@ class BookComponent extends React.Component{ ...newState })) }, - changePage: (indexToGo: number, goToPrevious: boolean)=>{ - const newCurrIndex = this.state.currIndex + indexToGo - - this.setState({ - currIndex: newCurrIndex, - flagToReverse: goToPrevious - }) - } + changePage: this.changePage, + pagesToTurn: 1, } } + + changePage = (goToPrevious: boolean, indexToGo?: number)=>{ + const {mode, currIndex} = this.state + const pagesCountToTurn = indexToGo || getPagesCountToTurn(mode) + const prefixPageCount = goToPrevious? -1 : 1 + + this.setState({ + currIndex: (pagesCountToTurn * prefixPageCount) + currIndex, + flagToReverse: goToPrevious + }) + } componentDidMount(){ fetch('https://picsum.photos/v2/list') @@ -79,6 +97,19 @@ class BookComponent extends React.Component{ }) }) } + + getControlsDisable = ()=>{ + const {mode, currIndex, src} = this.state + const {nextDisable, prevDisable} = getBookViewModes(currIndex, src.length).find(item=> item.value === mode) || { + nextDisable: true, + prevDisable: true + } + + return { + nextDisable, + prevDisable + } + } render(){ const {mode} = this.state @@ -89,6 +120,16 @@ class BookComponent extends React.Component{ <> {mode === "one page" && } {mode === "two pages" && } + { + this.changePage(true) + }} + onNextClick={()=>{ + this.changePage(false) + }} + {...this.getControlsDisable()} + {...this.state} + /> )} diff --git a/src/components/JumpControls.tsx b/src/components/JumpControls.tsx index dc553d8..f7b9cfb 100644 --- a/src/components/JumpControls.tsx +++ b/src/components/JumpControls.tsx @@ -2,19 +2,22 @@ import React, {useState, useCallback, useEffect} from 'react' import {Slider, InputNumber} from 'antd' import styled from 'styled-components' + const Container = styled.div` width: 100%; display: inline-flex; ` const JumpControls = (props: any)=>{ - const {src, currIndex, setBookContextState} = props + const {src, currIndex, setBookContextState, pagesToTurn} = props const [inputValue, setInputValue] = useState(currIndex) const [sliderValue, setSliderValue] = useState(currIndex) const onChange = useCallback( (value) => { + if(value){ const newCurrIndex = value -1 + if(newCurrIndex < src.length && newCurrIndex >=0){ setBookContextState({ currIndex: value - 1, @@ -46,11 +49,13 @@ const JumpControls = (props: any)=>{ min={1} max={src.length} onAfterChange={onChange} + step={pagesToTurn} defaultValue={typeof inputValue === 'number' ? inputValue : 1} {...sliderRestProps()} /> { function BookComponent(props: any) { - const {src, currIndex, flagToReverse, changePage} = props - const [prevDisable, setPrevDisable] = useState(true) - const [nextDisable, setNextDisable] = useState(false) - - - useEffect(() => { - setNextDisable(currIndex >= src.length - 1) - setPrevDisable(currIndex <= 0) - }, [currIndex, src]) - + const {src, currIndex, flagToReverse} = props return ( @@ -76,15 +66,6 @@ function BookComponent(props: any) { } - - changePage(-1, true)} - nextDisable={nextDisable} - onNextClick={()=>changePage(1, false)} - {...props} - /> - ) } diff --git a/src/components/TwoPagesView.tsx b/src/components/TwoPagesView.tsx index 6b5cb1f..4c856cd 100644 --- a/src/components/TwoPagesView.tsx +++ b/src/components/TwoPagesView.tsx @@ -1,15 +1,11 @@ -import React, {useState, useEffect, useCallback} from 'react' +import React, {useState, useEffect} from 'react' import {Transition, animated} from 'react-spring/renderprops' -import BookComponentsController from './BookComponentsController' import {ComponentContainer, PageComponent, PageContainer} from './OnePageView' import { IBookContext } from './BookComponent' export default function TwoPagesView(props: any) { - let {src, currIndex, changePage, flagToReverse} = props + let {src, currIndex, flagToReverse} = props const [pagesToshow, setPagesToShow] = useState([]) - const [prevDisable, setPrevDisable] = useState(true) - const [nextDisable, setNextDisable] = useState(false) - useEffect(()=>{ const shouldShowPage = (pageIndex: number)=>{ @@ -30,19 +26,8 @@ export default function TwoPagesView(props: any) { } ]) } - - setPrevDisable(newCurrIndex <= 1) - setNextDisable(newCurrIndex >= src.length - 2) }, [currIndex, src]) - const pageChangeClick = useCallback((indexToGo, flagToReverse)=>{ - const newIndex = currIndex + indexToGo - const shouldChangePage = newIndex >= 0 && newIndex < src.length - if(shouldChangePage){ - changePage(indexToGo, flagToReverse) - } - }, [src.length, currIndex, changePage]) - return ( @@ -96,18 +81,6 @@ export default function TwoPagesView(props: any) { } - { - pageChangeClick(-2, true) - - }} - nextDisable={nextDisable} - onNextClick={()=>{ - pageChangeClick(2, false) - }} - {...props} - /> ) } diff --git a/src/components/ViewSwitcher.tsx b/src/components/ViewSwitcher.tsx index 06a6867..91377e1 100644 --- a/src/components/ViewSwitcher.tsx +++ b/src/components/ViewSwitcher.tsx @@ -1,6 +1,6 @@ import React, {useCallback} from 'react' import {Select} from 'antd' -import {IBookContext, bookViewModes} from './BookComponent' +import {IBookContext, getBookViewModes} from './BookComponent' const {Option} = Select @@ -10,14 +10,15 @@ export default function ViewSwitcher(props: IBookContext) { const viewModeChange = useCallback((mode) => { setBookContextState({ - mode + mode, + pagesToTurn: getBookViewModes().find(item=> item.value === mode)?.pagesToTurn || 0 }) },[setBookContextState]) return (