diff --git a/src/components/deck/index.js b/src/components/deck/index.js index a401d5e01..b77d39c51 100644 --- a/src/components/deck/index.js +++ b/src/components/deck/index.js @@ -22,6 +22,7 @@ import { DEFAULT_SLIDE_INDEX } from '../../utils/constants'; import searchChildrenForAppear from '../../utils/search-children-appear'; +import OverviewDeck from './overview-deck'; const AnimatedDeckDiv = styled(animated.div)` height: 100vh; @@ -65,6 +66,7 @@ const initialState = { currentSlideElement: DEFAULT_SLIDE_ELEMENT_INDEX, reverseDirection: false, presenterMode: false, + overviewMode: false, notes: {}, resolvedInitialUrl: false }; @@ -172,7 +174,17 @@ const Deck = ({ let content = null; if (state.resolvedInitialUrl) { - if (state.presenterMode) { + if (state.overviewMode) { + const staticSlides = filteredChildren.map((slide, index) => + React.cloneElement(slide, { + slideNum: index, + template: rest.template + }) + ); + content = ( + {staticSlides} + ); + } else if (state.presenterMode) { const staticSlides = filteredChildren.map((slide, index) => React.cloneElement(slide, { slideNum: index, diff --git a/src/components/deck/overview-deck.js b/src/components/deck/overview-deck.js new file mode 100644 index 000000000..1ad7cec81 --- /dev/null +++ b/src/components/deck/overview-deck.js @@ -0,0 +1,41 @@ +import * as React from 'react'; +import propTypes from 'prop-types'; +import styled from 'styled-components'; + +const SlideGrid = styled('div')` + display: grid; + grid-template-columns: repeat(3, 30vw); + grid-column-gap: 3vw; + grid-row-gap: 15px; + padding: 15px; + width: 100vw; +`; + +const SlideGridItem = styled('div')` + height: 200px; + + .spectacle-progress-indicator, + .spectacle-fullscreen-button { + display: none; + } +`; + +export default function OverviewDeck(props) { + return ( + + {props.children.map((child, idx) => ( + props.goToSlide(idx)} + key={`slide-${idx}`} + > + {child} + + ))} + + ); +} + +OverviewDeck.propTypes = { + children: propTypes.node, + goToSlide: propTypes.func.isRequired +}; diff --git a/src/components/fullscreen.js b/src/components/fullscreen.js index 43917830d..e546672ef 100644 --- a/src/components/fullscreen.js +++ b/src/components/fullscreen.js @@ -12,7 +12,11 @@ const FullScreen = props => { } }, []); return ( -
+
{ const { numberOfSlides, state, goToSlide } = React.useContext(DeckContext); return ( -
+
{Array(numberOfSlides) .fill(0) .map((_, idx) => ( diff --git a/src/hooks/use-deck.js b/src/hooks/use-deck.js index f77ab780c..e9bf89eb6 100644 --- a/src/hooks/use-deck.js +++ b/src/hooks/use-deck.js @@ -19,6 +19,7 @@ function useDeck(initialState) { immediateElement: false, reverseDirection: action.payload.reverseDirection, presenterMode: action.payload.presenterMode, + overviewMode: action.payload.overviewMode, resolvedInitialUrl: true }; return newState; diff --git a/src/hooks/use-url-routing.js b/src/hooks/use-url-routing.js index b475f5815..1b67b69dc 100644 --- a/src/hooks/use-url-routing.js +++ b/src/hooks/use-url-routing.js @@ -13,6 +13,7 @@ export default function useUrlRouting(options) { currentSlide, currentSlideElement, currentPresenterMode, + currentOverviewMode, loop, animationsWhenGoingBack, onUrlChange @@ -55,6 +56,7 @@ export default function useUrlRouting(options) { const query = queryString.parse(url); const immediate = Boolean(query.immediate); const presenterMode = Boolean(query.presenterMode); + const overviewMode = Boolean(query.overviewMode); const proposedSlideNumber = parseInt(query.slide, 10); const proposedSlideElementNumber = parseInt(query.slideElement, 10); const slideNumber = isSlideOutOfBounds(proposedSlideNumber) @@ -68,9 +70,16 @@ export default function useUrlRouting(options) { ? DEFAULT_SLIDE_ELEMENT_INDEX : proposedSlideElementNumber; + if (overviewMode && presenterMode) { + throw new Error( + 'Presenter Mode and Overview Mode cannot be used at the same time.' + ); + } + return { immediate, presenterMode, + overviewMode, proposedSlideNumber, proposedSlideElementNumber, slideNumber, @@ -84,13 +93,14 @@ export default function useUrlRouting(options) { slideNumber => { const qs = queryString.stringify({ presenterMode: currentPresenterMode || undefined, + overviewMode: currentOverviewMode || undefined, immediate: true, slide: slideNumber, slideElement: DEFAULT_SLIDE_ELEMENT_INDEX }); history.current.push(`?${qs}`); }, - [currentPresenterMode] + [currentPresenterMode, currentOverviewMode] ); const onHistoryChange = React.useCallback(() => { @@ -100,6 +110,7 @@ export default function useUrlRouting(options) { proposedSlideNumber, proposedSlideElementNumber, presenterMode, + overviewMode, immediate } = stateFromUrl(window.location.search); /** @@ -115,7 +126,8 @@ export default function useUrlRouting(options) { slide: slideNumber, slideElement: slideElementNumber, immediate: immediate || undefined, - presenterMode: presenterMode || undefined + presenterMode: presenterMode || undefined, + overviewMode: overviewMode || undefined }); history.current.replace(`?${qs}`); return; @@ -132,7 +144,8 @@ export default function useUrlRouting(options) { type: 'GO_TO_SLIDE', payload: { ...update, - presenterMode + presenterMode, + overviewMode } }); onUrlChange(update); @@ -175,13 +188,15 @@ export default function useUrlRouting(options) { slide: nextSafeSlideIndex, slideElement: nextSafeSlideElementIndex, immediate: immediate || undefined, - presenterMode: currentPresenterMode || undefined + presenterMode: currentPresenterMode || undefined, + overviewMode: currentOverviewMode || undefined }); history.current.push(`?${qs}`); }, [ countSlideElements, currentPresenterMode, + currentOverviewMode, currentSlide, currentSlideElement, loop, @@ -227,13 +242,15 @@ export default function useUrlRouting(options) { slide: previousSafeSlideIndex, slideElement: previousSafeSlideElementIndex, immediate: immediate || undefined, - presenterMode: currentPresenterMode || undefined + presenterMode: currentPresenterMode || undefined, + overviewMode: currentOverviewMode || undefined }); history.current.push(`?${qs}`); }, [ animationsWhenGoingBack, countSlideElements, currentPresenterMode, + currentOverviewMode, currentSlide, currentSlideElement, loop,