From a5edc770771479532f6e4af08e71b242744625d2 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 2 Apr 2021 15:54:30 +0200 Subject: mitigating some weird nav issues and FOUC --- frontend/site/actions.js | 6 +- frontend/site/projects/museum/app.js | 21 ++++-- frontend/site/projects/museum/constants.js | 17 +++-- frontend/site/projects/museum/museum.actions.js | 21 ++++++ frontend/site/projects/museum/views/home.css | 12 ++++ frontend/site/projects/museum/views/home.js | 24 +++++-- frontend/site/projects/museum/views/nav.css | 71 ++++++++++++++++++++- frontend/site/projects/museum/views/nav.overlay.js | 74 +++++++++++++++++----- frontend/site/site/site.actions.js | 9 ++- frontend/site/site/site.reducer.js | 7 ++ frontend/site/types.js | 7 +- frontend/site/viewer/viewer.container.js | 20 ++++-- 12 files changed, 242 insertions(+), 47 deletions(-) create mode 100644 frontend/site/projects/museum/museum.actions.js (limited to 'frontend/site') diff --git a/frontend/site/actions.js b/frontend/site/actions.js index dea882c..2e3d7a6 100644 --- a/frontend/site/actions.js +++ b/frontend/site/actions.js @@ -3,7 +3,7 @@ import { bindActionCreators } from 'redux' import * as siteActions from 'site/site/site.actions' -import { store } from 'site/store' +import { dispatch } from 'site/store' export default // Object.keys(crudActions) @@ -12,8 +12,8 @@ export default [ ['site', siteActions], ] //) - .map(p => [p[0], bindActionCreators(p[1], store.dispatch)]) + .map(p => [p[0], bindActionCreators(p[1], dispatch)]) .concat([ // ['socket', socketActions], ]) - .reduce((a,b) => (a[b[0]] = b[1])&&a,{}) \ No newline at end of file + .reduce((a,b) => (a[b[0]] = b[1])&&a,{}) diff --git a/frontend/site/projects/museum/app.js b/frontend/site/projects/museum/app.js index 12dab41..44070b7 100644 --- a/frontend/site/projects/museum/app.js +++ b/frontend/site/projects/museum/app.js @@ -1,27 +1,30 @@ import React, { Component } from 'react' import { ConnectedRouter } from 'connected-react-router' import { Route } from 'react-router' +import { connect } from 'react-redux' import ViewerContainer from 'site/viewer/viewer.container' import Home from './views/home' import NavOverlay from './views/nav.overlay' -import actions from 'site/actions' -export default class App extends Component { +import { loadMuseum } from './museum.actions' + +class App extends Component { componentDidMount() { - const path_partz = window.location.pathname.split('/') - const graph_name = path_partz[1] - actions.site.loadSite(graph_name) + loadMuseum() } render() { + if (!this.props.ready) { + return
+ } return (
- { + { setTimeout(() => this.props.history.push('/last-museum/start'), 10) return null }} /> @@ -30,3 +33,9 @@ export default class App extends Component { ) } } + +const mapStateToProps = state => ({ + ready: state.site.ready, +}) + +export default connect(mapStateToProps)(App) diff --git a/frontend/site/projects/museum/constants.js b/frontend/site/projects/museum/constants.js index 0bb98ba..3676f2b 100644 --- a/frontend/site/projects/museum/constants.js +++ b/frontend/site/projects/museum/constants.js @@ -2,26 +2,35 @@ export const ARTISTS = { nora: { name: "Nora Al-Badri", location: "C-Base, Berlin, Germany", + start: "nora-1", }, leite: { name: "Juliana Cerqueria Leite", location: "Santa Ifigênia, São Paolo, Brazil", + start: "leite-chapter-1", }, foreshew: { name: "Nicole Foreshew", location: "Australia", + start: "foreshew-1", }, - stankievich: { - name: "Charles Stankievich", + stankievech: { + name: "Charles Stankievech", location: "Canada", + start: "stankievech-1", }, nilthamrong: { name: "Jakrawal Nilthamrong", location: "Thailand", + start: "nilthamrong-home", }, - opoko: { - name: "Zohra Opoko", + opoku: { + name: "Zohra Opoku", location: "Mortuary (Unfinished), Accra, Ghana", + start: "opoku-1-hail-to-you", } } +export const ARTIST_ORDER = [ + "nora", "foreshew", "leite", "opoku", "nilthamrong", "stankievech", +] \ No newline at end of file diff --git a/frontend/site/projects/museum/museum.actions.js b/frontend/site/projects/museum/museum.actions.js new file mode 100644 index 0000000..7f9867a --- /dev/null +++ b/frontend/site/projects/museum/museum.actions.js @@ -0,0 +1,21 @@ +import * as types from 'site/types' +import FontFaceObserver from 'fontfaceobserver' +import actions from 'site/actions' +import { dispatch } from 'site/store' + +export const loadMuseum = () => { + Promise.all([ + loadFonts, + actions.site.loadGraph('last-museum'), + ]) + .then(() => dispatch({ type: types.site.load_site })) +} + +const loadFonts = () => { + const fonts = [ + new FontFaceObserver('Gruk'), + new FontFaceObserver('Gruk Wide', { style: 'italic' }), + new FontFaceObserver('Gruk Medium'), + ] + return Promise.all(fonts.map(font => font.load())) +} diff --git a/frontend/site/projects/museum/views/home.css b/frontend/site/projects/museum/views/home.css index 597c66b..188840b 100644 --- a/frontend/site/projects/museum/views/home.css +++ b/frontend/site/projects/museum/views/home.css @@ -113,3 +113,15 @@ html { .home.open .home-byline { opacity: 0; } + +.curtain { + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + background: #111111; + transition: opacity 0.2s; + opacity: 1.0; +} +.curtain.hidden { + opacity: 0; +} \ No newline at end of file diff --git a/frontend/site/projects/museum/views/home.js b/frontend/site/projects/museum/views/home.js index e3c44d5..1520c11 100644 --- a/frontend/site/projects/museum/views/home.js +++ b/frontend/site/projects/museum/views/home.js @@ -1,22 +1,27 @@ import React, { Component } from 'react' +import { connect } from 'react-redux' import actions from 'site/actions' import "./home.css" -export default class Home extends Component { - state = { - open: false, - } - +class Home extends Component { constructor(props) { super(props) this.handleClick = this.handleClick.bind(this) + this.state = { + open: false, + hidden: this.props.interactive, + showCurtain: true, + } } componentDidMount() { const roadblock = document.querySelector('.roadblock') if (roadblock) roadblock.style.display = "none" + setTimeout(() => { + this.setState({ showCurtain: false }) + }, 100) } handleClick(e) { @@ -44,13 +49,20 @@ export default class Home extends Component {
CHARLES STANKIEVECH
JAKRAWAL NILTHAMRONG
- ZOHRA OPOKO + ZOHRA OPOKU
CURATED BY NADIM SAMMAN
Lorem ipsum dolor sit amet, pro ea errem nonumes, gubergren deterruisset sit eu. Quo nostrud definitiones ex, sea dicant accommodare ei, te vix habeo minim voluptatum.
+
) } } + +const mapStateToProps = state => ({ + interactive: state.site.interactive, +}) + +export default connect(mapStateToProps)(Home) diff --git a/frontend/site/projects/museum/views/nav.css b/frontend/site/projects/museum/views/nav.css index 2b6d75a..a44758f 100644 --- a/frontend/site/projects/museum/views/nav.css +++ b/frontend/site/projects/museum/views/nav.css @@ -1,13 +1,80 @@ +.museum-nav .home-link { + position: fixed; + top: 0; left: 0; + padding: 1rem; + color: rgba(255, 121, 13, 1.0); + font-family: 'Helvetica', sans-serif; + font-size: 1.2rem; + cursor: pointer; +} + +/* footer */ + .footer { position: fixed; bottom: 0; width: 100%; - background: linear-gradient(90deg, rgba(255, 121, 13, 0.0), rgba(255, 121, 13, 1.0)); + height: 5rem; + color: black; +} +.footer-gradient { + position: absolute; + bottom: 0rem; + width: 100%; + height: 5rem; + background: linear-gradient(180deg, rgba(255, 121, 13, 0.0), rgba(255, 121, 13, 1.0) 70%); + transform: translateY(2rem); + transition: transform 0.15s; +} +.footer .arrow { + position: absolute; + bottom: 0; + height: 3rem; + width: 4rem; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: transform 0.15s; + transform: translateY(3rem); +} +.footer .arrow-left { + left: 0; +} +.footer .arrow-right { + right: 0; +} +.footer .artist-desc { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + white-space: nowrap; + text-align: center; + padding-bottom: 0.5rem; + transition: transform 0.15s; + transform: translateY(3rem); } .footer .artist-name { font-family: "Druk Wide"; font-style: italic; + text-transform: uppercase; + margin-right: 1rem; + font-size: 28px; + line-height: 28px; + cursor: default; } .footer .artist-location { font-family: "Helvetica", sans-serif; -} \ No newline at end of file + font-size: 21px; + line-height: 21px; + cursor: default; +} + +.footer.with-artist:hover .arrow, +.footer.with-artist:hover .artist-desc { + transform: translateY(0); +} +.footer.with-artist:hover .footer-gradient { + transform: translateY(0); +} diff --git a/frontend/site/projects/museum/views/nav.overlay.js b/frontend/site/projects/museum/views/nav.overlay.js index 36af7db..ed6a0f5 100644 --- a/frontend/site/projects/museum/views/nav.overlay.js +++ b/frontend/site/projects/museum/views/nav.overlay.js @@ -4,7 +4,9 @@ import actions from 'site/actions' import "./nav.css" -import { ARTISTS } from "site/projects/museum/constants" +import { ARTISTS, ARTIST_ORDER } from "site/projects/museum/constants" +import { ArrowLeft, ArrowRight } from "site/projects/museum/icons" +import { history } from "site/store" export default class NavOverlay extends Component { state = { @@ -16,58 +18,98 @@ export default class NavOverlay extends Component { constructor(props) { super(props) + this.previousArtist = this.previousArtist.bind(this) + this.nextArtist = this.nextArtist.bind(this) + this.goHome = this.goHome.bind(this) } componentDidMount() { this.load() } - componentDidUpdate() { + + componentDidUpdate(prevProps) { + // console.log(this.props.location.pathname, prevProps.location.pathname) if (this.props.location.pathname !== prevProps.location.pathname) { this.load() } } load() { - const { pathname } = this.props.location - const pathPartz = pathname.split("-") + const { page_name } = this.props.match.params + const pathPartz = page_name.split("-") const pathkey = pathPartz[0] + // console.log(pathkey) if (pathkey === 'start') { this.setState({ showFooter: true, showArtist: false, - artist: {} + currentArtist: null, + artist: {}, }) } else if (pathkey in ARTISTS) { this.setState({ + showHome: true, showFooter: true, showArtist: true, - artist: ARTISTS[pathkey] + currentArtist: pathkey, + artist: ARTISTS[pathkey], }) } else { this.setState({ showFooter: false, showArtist: false, - artist: {} + currentArtist: null, + artist: {}, }) } } + previousArtist() { + this.go(-1) + } + + nextArtist() { + this.go(1) + } + + go(step) { + if (!this.state.currentArtist) return + const index = ARTIST_ORDER.indexOf(this.state.currentArtist) + const nextIndex = (index + step + ARTIST_ORDER.length) % ARTIST_ORDER.length + const currentArtist = ARTIST_ORDER[nextIndex] + const artist = ARTISTS[currentArtist] + this.setState({ currentArtist, artist }) + history.push(`/last-museum/${artist.start}`) + } + + goHome() { + history.push(`/last-museum/`) + } + render() { - const { showArtist, showHome, artist } = this.state + const { showArtist, showHome, showFooter, artist } = this.state return (
+ {showHome && ( +
+ Home +
+ )} {showFooter && ( showArtist ? ( -
- {ArrowLeft} - {artist.name} - {artist.location} - {ArrowRight} +
+
+
+ {artist.name} + {artist.location} +
+
{ArrowLeft}
+
{ArrowRight}
- } : ( -
+ ) : ( +
) - ))} + )}
) } diff --git a/frontend/site/site/site.actions.js b/frontend/site/site/site.actions.js index aab68e8..f0eeebc 100644 --- a/frontend/site/site/site.actions.js +++ b/frontend/site/site/site.actions.js @@ -6,7 +6,14 @@ export const setSiteTitle = title => dispatch => { dispatch({ type: types.site.set_site_title, payload: title }) } -export const loadSite = graph_name => dispatch => ( +export const loadSite = graph_name => dispatch => { + loadGraph(graph_name) + .then(() => { + dispatch({ type: types.site.load_site }) + }) +} + +export const loadGraph = graph_name => dispatch => ( api(dispatch, types.site, 'site', '/' + graph_name + '/index.json?t=' + (Date.now() / 3600000)) ) diff --git a/frontend/site/site/site.reducer.js b/frontend/site/site/site.reducer.js index 8b31786..8b7175c 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', + ready: false, interactive: false, graph: { loading: true, @@ -25,6 +26,12 @@ export default function siteReducer(state = initialState, action) { cursors: buildCursors(action.data.graph), } + case types.site.load_site: + return { + ...state, + ready: true, + } + case types.site.interact: return { ...state, diff --git a/frontend/site/types.js b/frontend/site/types.js index 4ab897f..a83febe 100644 --- a/frontend/site/types.js +++ b/frontend/site/types.js @@ -1,11 +1,8 @@ import { with_type } from 'app/api/crud.types' export const site = with_type('site', [ - 'set_site_title', 'loading', 'loaded', 'error', 'interact' -]) - -export const system = with_type('system', [ - 'load_site', + 'set_site_title', 'loading', 'loaded', 'error', + 'load_site', 'interact', ]) export const init = '@@INIT' diff --git a/frontend/site/viewer/viewer.container.js b/frontend/site/viewer/viewer.container.js index 09f04c3..4135586 100644 --- a/frontend/site/viewer/viewer.container.js +++ b/frontend/site/viewer/viewer.container.js @@ -32,13 +32,23 @@ class ViewerContainer extends Component { window.addEventListener('resize', this.handleResize) } + componentDidMount() { + if (this.props.graph && this.props.interactive) { + this.load() + } + } + componentDidUpdate(prevProps) { // console.log('didUpdate', this.props.graph !== prevProps.graph, this.props.location.pathname !== prevProps.location.pathname) - // console.log(this.props.location.pathname, prevProps.location.pathname, this.props.interactive) - if (this.props.graph !== prevProps.graph || this.props.location.pathname !== prevProps.location.pathname) { + // console.log(this.props.location.pathname, prevProps.location.pathname, this.props.interactive, prevProps.interactive) + if ( + this.props.graph !== prevProps.graph || + this.props.location.pathname !== prevProps.location.pathname || + this.props.interactive !== prevProps.interactive + ) { this.load() } - if (this.props.interactive && (this.props.interactive !== prevProps.interactive)) { + else if (this.props.interactive && (this.props.interactive !== prevProps.interactive)) { this.setState({ roadblock: false }) this.props.audio.player.playPage(this.state.page) this.resetTimer(this.state.page) @@ -52,6 +62,7 @@ class ViewerContainer extends Component { load() { const { page_name } = this.props.match.params + // console.log("load", page_name) const { pages, home_page, path: graph_name } = this.props.graph const page_path = ["", graph_name, page_name].join('/') // if ((!page_path in pages) || page_name === 'index.html') { @@ -60,7 +71,8 @@ class ViewerContainer extends Component { // } // console.log(this.props.interactive) const page = pages[page_path] || pages[home_page] - console.log("show page", page.id) + // console.log(pages, page) + // console.log("show page", page.id) if (!this.props.interactive && hasAutoplay(page)) { this.setState({ page, popups: {}, hidden: {}, roadblock: true, unloaded: false }) } else { -- cgit v1.2.3-70-g09d2