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/BookComponent.tsx b/src/components/BookComponent.tsx index 7240c07..1e84b3c 100644 --- a/src/components/BookComponent.tsx +++ b/src/components/BookComponent.tsx @@ -1,5 +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({}) @@ -9,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, } ] @@ -36,7 +45,12 @@ export interface IBookContext { } -class BookComponent extends React.Component{ +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) this.state = { @@ -45,13 +59,26 @@ class BookComponent extends React.Component{ flagToReverse: false, mode: "one page", setBookContextState: (newState: IBookContext)=>{ - this.setState(oldState=> ({ + this.setState((oldState: any)=> ({ ...oldState, ...newState })) - } + }, + 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') @@ -70,13 +97,39 @@ 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 + return {state=>( <> - + {mode === "one page" && } + {mode === "two pages" && } + { + this.changePage(true) + }} + onNextClick={()=>{ + this.changePage(false) + }} + {...this.getControlsDisable()} + {...this.state} + /> )} 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 94fb235..f7b9cfb 100644 --- a/src/components/JumpControls.tsx +++ b/src/components/JumpControls.tsx @@ -1,14 +1,23 @@ 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 {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, @@ -17,31 +26,43 @@ const JumpControls = (props: any)=>{ } } }, - [inputValue]) + [inputValue, src.length, setBookContextState]) useEffect(()=>{ setInputValue(currIndex + 1) }, [currIndex]) - return - + useEffect(() => { + setSliderValue(inputValue) + }, [inputValue]) + + + const sliderRestProps = ()=>{ + return sliderValue === inputValue? {}: {value: inputValue} + } + + return - - + - - + } export default JumpControls diff --git a/src/components/OnePageView.tsx b/src/components/OnePageView.tsx index 85768d7..11b36fd 100644 --- a/src/components/OnePageView.tsx +++ b/src/components/OnePageView.tsx @@ -1,7 +1,6 @@ -import React, {useState, useCallback, useEffect} from 'react' +import React from 'react' import {Transition, animated} from 'react-spring/renderprops' import styled, { } from 'styled-components' -import BookComponentsController from './BookComponentsController' const ComponentContainer = styled.div` display: flex; @@ -24,10 +23,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,30 +34,13 @@ 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 [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) - setPrevDisable(currIndex <= 0) - }, [currIndex, src]) - + const {src, currIndex, flagToReverse} = props return ( @@ -77,8 +58,6 @@ function BookComponent(props: any) { return( {React.createElement(()=>)} @@ -87,17 +66,8 @@ function BookComponent(props: any) { } - - changePage(-1, true)} - nextDisable={nextDisable} - onNextClick={()=>changePage(1, false)} - {...props} - /> - ) } -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..4c856cd --- /dev/null +++ b/src/components/TwoPagesView.tsx @@ -0,0 +1,91 @@ +import React, {useState, useEffect} from 'react' +import {Transition, animated} from 'react-spring/renderprops' +import {ComponentContainer, PageComponent, PageContainer} from './OnePageView' +import { IBookContext } from './BookComponent' + +export default function TwoPagesView(props: any) { + let {src, currIndex, flagToReverse} = props + const [pagesToshow, setPagesToShow] = useState([]) + + 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: '', + } + ]) + } + }, [currIndex, src]) + + 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 + })} + + ) + } + } + + + + ) +} + +interface Book { + name: string +} + diff --git a/src/components/ViewSwitcher.tsx b/src/components/ViewSwitcher.tsx index 5183a29..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,15 +10,16 @@ export default function ViewSwitcher(props: IBookContext) { const viewModeChange = useCallback((mode) => { setBookContextState({ - mode + mode, + pagesToTurn: getBookViewModes().find(item=> item.value === mode)?.pagesToTurn || 0 }) - },[]) + },[setBookContextState]) return ( diff --git a/src/components/index.css b/src/components/index.css new file mode 100644 index 0000000..eb1ba0c --- /dev/null +++ b/src/components/index.css @@ -0,0 +1,3 @@ +.jump-control .ant-input-number-handler-wrap{ + display: none; +} \ No newline at end of file