diff --git a/presentation/config.js b/presentation/config.js index 8b23da325..1ecf70ec1 100644 --- a/presentation/config.js +++ b/presentation/config.js @@ -1,5 +1,6 @@ module.exports = { width: 1000, + height: 700, margin: 40, theme: require('../themes/default/index'), print: require('../themes/default/print'), diff --git a/presentation/deck.jsx b/presentation/deck.jsx index 010d15991..1de1b22b9 100644 --- a/presentation/deck.jsx +++ b/presentation/deck.jsx @@ -39,12 +39,11 @@ export default class extends React.Component { Wait what? - + + margin="20px auto"/> @@ -92,7 +91,7 @@ export default class extends React.Component { Combinable Transitions - + Inline style based theme system Autofit text diff --git a/src/deck.jsx b/src/deck.jsx index c39b1f2ab..67d3f6047 100644 --- a/src/deck.jsx +++ b/src/deck.jsx @@ -4,11 +4,13 @@ import cloneWithProps from 'react/lib/cloneWithProps'; import Radium from 'radium'; import _ from 'lodash'; +import Presenter from './presenter'; + React.initializeTouchEvents(true); const Style = Radium.Style; -const TransitionGroup = React.addons.TransitionGroup; +const TransitionGroup = Radium(React.addons.TransitionGroup); @Radium class Deck extends React.Component { @@ -16,24 +18,30 @@ class Deck extends React.Component { super(props); this._handleKeyPress = this._handleKeyPress.bind(this); this._handleClick = this._handleClick.bind(this); + this._goToSlide = this._goToSlide.bind(this); this.state = { lastSlide: null }; } componentDidMount() { + let slide = 'slide' in this.context.router.state.params ? + parseInt(this.context.router.state.params.slide) : 0; this.setState({ - lastSlide: 'slide' in this.context.router.state.params ? - parseInt(this.context.router.state.params.slide) : 0 + lastSlide: slide }); + localStorage.setItem('spectacle-slide', + JSON.stringify({slide: slide, forward: false, time: Date.now()})); this._attachEvents(); } componentWillUnmount() { this._detachEvents(); } _attachEvents() { + window.addEventListener('storage', this._goToSlide); window.addEventListener('keydown', this._handleKeyPress); } _detachEvents() { + window.removeEventListener('storage', this._goToSlide); window.removeEventListener('keydown', this._handleKeyPress); } _handleKeyPress(e) { @@ -41,33 +49,75 @@ class Deck extends React.Component { event.keyCode === 37 && this._prevSlide(); event.keyCode === 39 && this._nextSlide(); } + _goToSlide(e) { + if(e.key === 'spectacle-slide') { + let data = JSON.parse(e.newValue); + let presenter = this.context.presenter ? '?presenter' : ''; + let slide = 'slide' in this.context.router.state.params ? + parseInt(this.context.router.state.params.slide) : 0; + this.setState({ + lastSlide: slide || 0 + }); + if(this._checkFragments(slide, data.forward)) { + this.context.router.replaceWith('/' + (data.slide) + presenter); + } + } + } _prevSlide() { let slide = 'slide' in this.context.router.state.params ? parseInt(this.context.router.state.params.slide) : 0; + let presenter = this.context.presenter ? '?presenter' : ''; this.setState({ lastSlide: slide }); if (this._checkFragments(slide, false)) { if (slide > 0) { - this.context.router.replaceWith('/' + (slide - 1)); + this.context.router.replaceWith('/' + (slide - 1) + presenter); + localStorage.setItem('spectacle-slide', + JSON.stringify({slide: slide - 1, forward: false, time: Date.now()})); + } + } else { + if (slide > 0) { + localStorage.setItem('spectacle-slide', + JSON.stringify({slide: slide, forward: false, time: Date.now()})); } } } _nextSlide() { let slide = 'slide' in this.context.router.state.params ? parseInt(this.context.router.state.params.slide) : 0; + let presenter = this.context.presenter ? '?presenter' : ''; this.setState({ lastSlide: slide }); if(this._checkFragments(slide, true)) { if (slide < this.props.children.length - 1) { - this.context.router.replaceWith('/' + (slide + 1)); + this.context.router.replaceWith('/' + (slide + 1) + presenter); + localStorage.setItem('spectacle-slide', + JSON.stringify({slide: slide + 1, forward: true, time: Date.now()})); + } + } else { + if (slide < this.props.children.length - 1) { + localStorage.setItem('spectacle-slide', + JSON.stringify({slide: slide, forward: true, time: Date.now()})); } } } _checkFragments(slide, forward) { let store = this.context.flux.stores.SlideStore; let fragments = store.getState().fragments; + // Not proud of this at all. 0.14 Parent based contexts will fix this. + if(this.context.presenter) { + let main = document.querySelector('.spectacle-presenter-main'); + if (main) { + let fragments = main.querySelectorAll('.appear'); + if (!fragments.length) { + return true; + } + } else { + return true; + } + } if (slide in fragments) { let count = _.size(fragments[slide]); let visible = _.filter(fragments[slide], function(s){ @@ -223,6 +273,9 @@ class Deck extends React.Component { exportMode = true; } + let slide ='slide' in this.context.router.state.params ? + parseInt(this.context.router.state.params.slide) : 0; + let globals = exportMode ? { body: { minWidth: 1100, @@ -232,24 +285,34 @@ class Deck extends React.Component { } : {}; let styles = { - position: 'absolute', - top: 0, - left: 0, - width: '100%', - height: '100%', - perspective: 1000, - transformStyle: 'preserve-3d' + deck: { + backgroundColor: this.context.presenter ? 'black' : '', + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + perspective: 1000, + transformStyle: 'preserve-3d' + }, + transition: { + height: '100%', + width: '100%' + } }; return (
- - {this._renderSlide()} - + {this.context.presenter ? + : + + {this._renderSlide()} + }