summaryrefslogtreecommitdiff
path: root/frontend/site
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2021-03-17 18:11:26 +0100
committerJules Laplace <julescarbon@gmail.com>2021-03-17 18:11:26 +0100
commitd165a0727e42349d935ab3ee287242f1e5029742 (patch)
treeb4fa68209127efdd4eb46c82eaef280535692611 /frontend/site
parent92566ba17f5e921d5bff1f3fb4e4b0d92ca4fd39 (diff)
frontend. export/view button. interactivity sanity check
Diffstat (limited to 'frontend/site')
-rw-r--r--frontend/site/audio/audio.player.js43
-rw-r--r--frontend/site/index.js2
-rw-r--r--frontend/site/site.css20
-rw-r--r--frontend/site/site/site.actions.js4
-rw-r--r--frontend/site/site/site.reducer.js7
-rw-r--r--frontend/site/store.js3
-rw-r--r--frontend/site/types.js4
-rw-r--r--frontend/site/viewer/viewer.container.js60
8 files changed, 131 insertions, 12 deletions
diff --git a/frontend/site/audio/audio.player.js b/frontend/site/audio/audio.player.js
new file mode 100644
index 0000000..9a2d783
--- /dev/null
+++ b/frontend/site/audio/audio.player.js
@@ -0,0 +1,43 @@
+export default class AudioPlayer {
+ players = {}
+
+ play({ item, restart, loop }) {
+ return new Promise((resolve, reject) => {
+ const { id, url } = item
+ if (id in players) {
+ if (restart) {
+ players[id].currentTime = 0
+ players[id].play()
+ return resolve()
+ }
+ return reject()
+ }
+ const player = document.createElement('audio')
+ const handleEnded = () => {
+ unbind()
+ resolve()
+ }
+ const handleError = (error) => {
+ console.error(error)
+ unbind()
+ reject(error)
+ }
+ const bind = () => {
+ player.addEventListener('ended', handleEnded)
+ player.addEventListener('error', handleError)
+ this.players[id] = player
+ }
+ const unbind = () => {
+ player.removeEventListener('ended', handleEnded)
+ player.removeEventListener('error', handleError)
+ delete this.players[id]
+ }
+ const start = () => {
+ player.src = url
+ player.play()
+ }
+ bind()
+ start()
+ })
+ }
+}
diff --git a/frontend/site/index.js b/frontend/site/index.js
index 36eeae8..337d362 100644
--- a/frontend/site/index.js
+++ b/frontend/site/index.js
@@ -2,6 +2,8 @@ import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
+import './site.css'
+
import App from 'site/app'
import { store, history } from 'site/store'
diff --git a/frontend/site/site.css b/frontend/site/site.css
new file mode 100644
index 0000000..0597514
--- /dev/null
+++ b/frontend/site/site.css
@@ -0,0 +1,20 @@
+.roadblock {
+ position: fixed;
+ top: 0; left: 0;
+ display: flex;
+ width: 100vw;
+ height: 100vh;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+}
+.roadblock div {
+ display: inline-block;
+ text-align: center;
+}
+.roadblock h2 {
+ font-style: italic;
+}
+.roadblock button {
+ padding: 0.5rem;
+}
diff --git a/frontend/site/site/site.actions.js b/frontend/site/site/site.actions.js
index 3547ec0..07814d6 100644
--- a/frontend/site/site/site.actions.js
+++ b/frontend/site/site/site.actions.js
@@ -9,3 +9,7 @@ export const setSiteTitle = title => dispatch => {
export const loadSite = (graph_name, path_name) => dispatch => (
api(dispatch, types.site, 'site', '/' + graph_name + '/index.json')
)
+
+export const interact = () => dispatch => {
+ dispatch({ type: types.site.interact })
+} \ No newline at end of file
diff --git a/frontend/site/site/site.reducer.js b/frontend/site/site/site.reducer.js
index 53fa555..e0b53fb 100644
--- a/frontend/site/site/site.reducer.js
+++ b/frontend/site/site/site.reducer.js
@@ -2,6 +2,7 @@ import * as types from 'site/types'
const initialState = {
siteTitle: 'swimmer',
+ interactive: false,
graph: {
loading: true,
}
@@ -22,6 +23,12 @@ export default function siteReducer(state = initialState, action) {
graph: action.data.graph,
}
+ case types.site.interact:
+ return {
+ ...state,
+ interactive: true,
+ }
+
case '@@router/LOCATION_CHANGE':
return {
...state,
diff --git a/frontend/site/store.js b/frontend/site/store.js
index 6511613..5cb1a1b 100644
--- a/frontend/site/store.js
+++ b/frontend/site/store.js
@@ -4,6 +4,7 @@ import { createBrowserHistory } from 'history'
import thunk from 'redux-thunk'
import siteReducer from 'site/site/site.reducer'
+import AudioPlayer from 'site/audio/audio.player'
const createRootReducer = history => (
combineReducers({
@@ -13,7 +14,7 @@ const createRootReducer = history => (
})
)
-const configureStore = (initialState = {}, history) => {
+const configureStore = (initialState = { audio: audioPlayer }, history) => {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
diff --git a/frontend/site/types.js b/frontend/site/types.js
index 23bed98..4ab897f 100644
--- a/frontend/site/types.js
+++ b/frontend/site/types.js
@@ -1,7 +1,7 @@
-import { with_type, crud_type } from 'app/api/crud.types'
+import { with_type } from 'app/api/crud.types'
export const site = with_type('site', [
- 'set_site_title', 'loading', 'loaded', 'error',
+ 'set_site_title', 'loading', 'loaded', 'error', 'interact'
])
export const system = with_type('system', [
diff --git a/frontend/site/viewer/viewer.container.js b/frontend/site/viewer/viewer.container.js
index 1b3d564..3f1c9c5 100644
--- a/frontend/site/viewer/viewer.container.js
+++ b/frontend/site/viewer/viewer.container.js
@@ -12,12 +12,17 @@ import 'app/views/page/page.css'
class ViewerContainer extends Component {
state = {
page: {},
+ bounds: { width: window.innerWidth, height: window.innerHeight },
+ roadblock: false,
}
constructor(props) {
super(props)
this.pageRef = React.createRef()
this.handleMouseDown = this.handleMouseDown.bind(this)
+ this.handleResize = this.handleResize.bind(this)
+ this.removeRoadblock = this.removeRoadblock.bind(this)
+ window.addEventListener('resize', this.handleResize)
}
componentDidUpdate(prevProps) {
@@ -27,20 +32,30 @@ class ViewerContainer extends Component {
}
}
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.handleResize)
+ actions.site.interact()
+ }
+
+ handleResize() {
+ this.setState({
+ bounds: {
+ width: window.innerWidth,
+ height: window.innerHeight,
+ }
+ })
+ }
+
load() {
const { graph_name, page_name } = this.props.match.params
const page_path = ["", graph_name, page_name].join('/')
const { pages, home_page } = this.props.graph
- const page = pages[page_path]
- if (!page) {
- // console.log('-> home page')
- console.log(page_path)
- const { home_page } = this.props.graph
- this.setState({ page: pages[home_page] })
+ const page = pages[page_path] || pages[home_page]
+ if (!this.props.interactive && hasAutoplayVideo(page)) {
+ this.setState({ page, roadblock: true })
} else {
- // console.log(page)
- console.log(page_path)
- this.setState({ page })
+ this.setState({ page, roadblock: false })
+ actions.site.interact()
}
}
@@ -50,6 +65,9 @@ class ViewerContainer extends Component {
render() {
const { page } = this.state
+ if (this.state.roadblock) {
+ return this.renderRoadblock()
+ }
if (this.props.graph.loading || !page.id) {
return (
<div>
@@ -83,11 +101,35 @@ class ViewerContainer extends Component {
</div>
)
}
+
+ removeRoadblock() {
+ actions.site.interact()
+ this.setState({ roadblock: false })
+ }
+
+ renderRoadblock() {
+ const { title } = this.props.graph
+ return (
+ <div className='roadblock' onClick={this.removeRoadblock}>
+ <div>
+ <h2>{title}</h2>
+ <button>Enter</button>
+ </div>
+ </div>
+ )
+ }
+}
+
+const hasAutoplayVideo = page => {
+ return page.tiles.some(tile => {
+ return tile.type === 'video' && !tile.settings.muted
+ })
}
const mapStateToProps = state => ({
site: state.site,
graph: state.site.graph,
+ interactive: state.site.interactive,
})
const mapDispatchToProps = dispatch => ({