diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-09-08 16:05:54 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-09-08 16:05:54 +0200 |
| commit | 0a6a7fb9b49a2180a68f6c96815ebd9b7f6b5ab7 (patch) | |
| tree | 09d112663ca6e6b8255b58fec64522b2b6888c8d /animism-align/frontend/app/views/viewer | |
| parent | 064e8652dc4fae7167e3cd34a6fbe6b36e6239d1 (diff) | |
section 2 carousel
Diffstat (limited to 'animism-align/frontend/app/views/viewer')
8 files changed, 218 insertions, 54 deletions
diff --git a/animism-align/frontend/app/views/viewer/nav/viewer.router.js b/animism-align/frontend/app/views/viewer/nav/viewer.router.js index 837bd5e..7f18b94 100644 --- a/animism-align/frontend/app/views/viewer/nav/viewer.router.js +++ b/animism-align/frontend/app/views/viewer/nav/viewer.router.js @@ -3,6 +3,7 @@ import { Link } from 'react-router-dom' import { connect } from 'react-redux' import { timestampToSeconds } from 'app/utils' +import { getSection } from 'app/utils/viewer.utils' import actions from 'app/actions' class ViewerRouter extends Component { @@ -21,11 +22,17 @@ class ViewerRouter extends Component { case 'checklist': actions.viewer.showComponent('checklist') break + case 'carousel': + actions.viewer.seekToSection(getSection(1)) + break case 'vitrine': - actions.audio.seek(timestampToSeconds('7:36')) + actions.viewer.seekToSection(getSection(2)) break case 'gallery': - actions.audio.seek(timestampToSeconds('27:36')) + actions.viewer.seekToSection(getSection(3)) + break + case 'video': + actions.viewer.seekToSection(getSection(4)) break case 'end': break diff --git a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.gallery.js b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.gallery.js index 0549f09..9cd2787 100644 --- a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.gallery.js +++ b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.gallery.js @@ -1,6 +1,7 @@ import React from 'react' -import { MediaCitation, Vitrine } from '../components.media' +import { CURTAIN_COLOR_LOOKUP } from 'app/constants' +import { MediaCitation, Vitrine, Gallery, Carousel, Grid } from '../components.media' export const FullscreenVitrine = ({ element, media, transitionDuration }) => { const { color } = element @@ -38,3 +39,22 @@ export const FullscreenGallery = ({ element, media, transitionDuration }) => { </div> ) } + +export const FullscreenCarousel = ({ element, media, transitionDuration }) => { + const { color } = element + const item = media.lookup[element.settings.media_id] + const style = { + backgroundColor: color.backgroundColor, + color: color.textColor, + transitionDuration, + } + return ( + <div + className='fullscreen-element carousel' + style={style} + > + {element.settings.title && <div className='heading'>{element.settings.title}</div>} + <Carousel media={item} withCitation /> + </div> + ) +} diff --git a/animism-align/frontend/app/views/viewer/player/components.fullscreen/index.js b/animism-align/frontend/app/views/viewer/player/components.fullscreen/index.js index 538632f..25fbc83 100644 --- a/animism-align/frontend/app/views/viewer/player/components.fullscreen/index.js +++ b/animism-align/frontend/app/views/viewer/player/components.fullscreen/index.js @@ -9,7 +9,9 @@ import { } from './fullscreen.video' import { - FullscreenVitrine + FullscreenVitrine, + FullscreenGallery, + FullscreenCarousel } from './fullscreen.gallery' import { @@ -20,6 +22,7 @@ export const fullscreenComponents = { curtain: React.memo(FullscreenCurtain), video: React.memo(FullscreenVideo), image: React.memo(FullscreenImage), - // gallery: React.memo(FullscreenGallery), + gallery: React.memo(FullscreenGallery), + carousel: React.memo(FullscreenCarousel), vitrine: React.memo(FullscreenVitrine), } diff --git a/animism-align/frontend/app/views/viewer/player/components.media/media.carousel.js b/animism-align/frontend/app/views/viewer/player/components.media/media.carousel.js index 914a8d9..edaa209 100644 --- a/animism-align/frontend/app/views/viewer/player/components.media/media.carousel.js +++ b/animism-align/frontend/app/views/viewer/player/components.media/media.carousel.js @@ -2,20 +2,32 @@ import React, { Component } from 'react' import { useKeenSlider } from "keen-slider/react" import "keen-slider/keen-slider.min.css" +import { MediaCitation } from './media.citation' +import { Arrow } from 'app/views/viewer/nav/viewer.icons' + export const Carousel = ({ media }) => { - const { image_order, image_lookup, display_lookup, thumbnail_lookup } = media.settings + const { image_order, image_lookup, display_lookup, thumbnail_lookup, caption_lookup } = media.settings - const [sliderRef] = useKeenSlider({ + const [currentSlide, setCurrentSlide] = React.useState(0) + const [currentCaption, setCurrentCaption] = React.useState(caption_lookup[image_order[0]]) + const [sliderRef, slider] = useKeenSlider({ slidesPerView: 2, mode: "free-snap", spacing: 15, centered: true, - loop: false - }); + loop: false, + slideChanged: slider => { + const currentSlideIndex = slider.details().relativeSlide + const currentImageId = image_order[currentSlideIndex] + const currentCaption = caption_lookup[currentImageId] + setCurrentSlide(currentSlideIndex) + setCurrentCaption(currentCaption) + } + }) // console.log(display_lookup) // console.log(width) - return ( - <div ref={sliderRef} className='keen-slider carousel-items'> + return [ + <div key={'carousel_' + media.id} ref={sliderRef} className='keen-slider carousel-items'> {image_order.map(id => { const image = display_lookup[id] // console.log(image) @@ -23,7 +35,63 @@ export const Carousel = ({ media }) => { <CarouselItem key={id} image={image} /> ) })} + </div>, + <MediaCitation key={'caption_' + media.id} media={currentCaption} />, + <CarouselNav + key={'arrows_' + media.id} + currentSlide={currentSlide} + slides={image_order} + onPrev={() => { + slider.prev() + }} + onNext={() => { + slider.next() + }} + onPick={index => { + slider.moveToSlideRelative(index) + }} + /> + ] +} + +const CarouselNav = ({ currentSlide, slides, onPrev, onNext, onPick }) => { + return ( + <div className="carousel-nav"> + <div + className={currentSlide ? "arrow-prev" : "arrow-prev arrow-disabled"} + onClick={e => { + e.stopPropagation() + onPrev() + }} + > + <Arrow type="left" /> + </div> + <div + className={currentSlide < slides.length - 1 ? "arrow-next" : "arrow-next arrow-disabled"} + onClick={e => { + e.stopPropagation() + onNext() + }} + > + <Arrow type="right" /> + </div> + <div className="dots"> + {[...slides.keys()].map(idx => { + return ( + <div + key={idx} + onClick={() => { + onPick(idx) + }} + className={"dot-item" + (currentSlide === idx ? " active" : "")} + > + <div className="dot-circle" /> + </div> + ) + })} + </div> </div> + ) } diff --git a/animism-align/frontend/app/views/viewer/player/components.media/media.citation.js b/animism-align/frontend/app/views/viewer/player/components.media/media.citation.js index 14c8c53..ea20a3b 100644 --- a/animism-align/frontend/app/views/viewer/player/components.media/media.citation.js +++ b/animism-align/frontend/app/views/viewer/player/components.media/media.citation.js @@ -1,9 +1,20 @@ import React, { Component } from 'react' export const MediaCitation = ({ media }) => { - if (media.settings.bibliography) { + if (!media) { return ( - <div className='citation' dangerouslySetInnerHTML={{ __html: media.settings.bibliography }} /> + <div className='citation' /> + ) + } + const settings = media.settings || media + if (settings.bibliography) { + return ( + <div className='citation' dangerouslySetInnerHTML={{ __html: settings.bibliography }} /> + ) + } + if (settings.short_caption) { + return ( + <div className='citation' dangerouslySetInnerHTML={{ __html: settings.short_caption }} /> ) } return ( diff --git a/animism-align/frontend/app/views/viewer/player/components.media/media.css b/animism-align/frontend/app/views/viewer/player/components.media/media.css index 62eb9af..f552eba 100644 --- a/animism-align/frontend/app/views/viewer/player/components.media/media.css +++ b/animism-align/frontend/app/views/viewer/player/components.media/media.css @@ -1,3 +1,90 @@ +/* heading and caption */ + +.viewer-fullscreen .heading { + font-family: "Freight Text", serif; + font-size: 3rem; + line-height: 1.28; + width: 80%; + margin: 4rem auto 0 auto; + padding-bottom: 1rem; + text-align: center; +} +.viewer-fullscreen .citation { + width: 45rem; + margin: 0 auto 3rem auto; + padding: 1rem 0; + font-family: "Neue Haas Unica"; + color: #888; +} + +.viewer-fullscreen .fullscreen-element.gallery, +.viewer-fullscreen .fullscreen-element.carousel, +.viewer-fullscreen .fullscreen-element.vitrine { + flex-direction: column; + justify-content: space-between; + align-items: center; +} +.viewer-fullscreen .fullscreen-element.gallery .citation, +.viewer-fullscreen .fullscreen-element.carousel .citation, +.viewer-fullscreen .fullscreen-element.vitrine .citation { + margin-top: 3rem; +} + +/* arrows and dots */ + +.carousel-nav .arrow-prev { + position: absolute; + left: 1rem; + top: 50%; + margin-top: -3.5rem; + transform: translateY(-50%); + cursor: pointer; +} +.carousel-nav .arrow-next { + position: absolute; + right: 1rem; + top: 50%; + margin-top: -3.5rem; + transform: translateY(-50%); + cursor: pointer; +} +.carousel-nav .arrow { + width: 4rem; +} +.carousel-nav .arrow-disabled { + cursor: default; + opacity: 0.2; +} +.carousel-nav .dots { + position: absolute; + bottom: 5.5rem; + left: 0; + width: 100%; + display: flex; + padding: 10px 0; + justify-content: center; +} +.dots .dot-item { + cursor: pointer; + opacity: 0.2; + margin: 0; + padding: 15px 7px; + background: transparent; + cursor: pointer; +} +.dots .dot-circle { + border-radius: 50%; + background: #000; + width: 10px; + height: 10px; +} +.dots .dot-item:focus { + outline: none; +} +.dots .dot-item.active { + opacity: 1.0; +} + /* carousel */ .carousel-container { @@ -6,12 +93,18 @@ padding: 1rem; } .carousel-item { - height: calc(100vh - 9rem); - width: 50vw; background-size: contain; background-position: center center; background-repeat: no-repeat; } +.player-transcript .carousel-item { + width: 50vw; + height: calc(100vh - 9rem); +} +.viewer-fullscreen .carousel-item { + width: 50vw; + height: calc(100vh - 8rem); +} /* gallery */ @@ -91,22 +184,6 @@ /* vitrine */ -.vitrine .heading { - font-family: "Freight Text", serif; - font-size: 3rem; - line-height: 1.28; - width: 80%; - margin: 0 auto; - padding-bottom: 2rem; - text-align: center; -} -.vitrine .citation { - width: 45rem; - margin: 0 auto; - padding: 1rem 0; - font-family: "Neue Haas Unica"; - color: #888; -} .vitrine-items { display: flex; flex-flow: row wrap; diff --git a/animism-align/frontend/app/views/viewer/player/player.fullscreen.css b/animism-align/frontend/app/views/viewer/player/player.fullscreen.css index e6a3504..8d38fa0 100644 --- a/animism-align/frontend/app/views/viewer/player/player.fullscreen.css +++ b/animism-align/frontend/app/views/viewer/player/player.fullscreen.css @@ -53,18 +53,3 @@ background-repeat: no-repeat; background-position: center center; } - -/* vitrine */ - -.viewer-fullscreen .fullscreen-element.vitrine { - flex-direction: column; - justify-content: space-between; - align-items: center; -} -.viewer-fullscreen .fullscreen-element.vitrine .heading { - margin-top: 4rem; - padding-bottom: 1rem; -} -.viewer-fullscreen .fullscreen-element.vitrine .citation { - margin-bottom: 3rem; -} diff --git a/animism-align/frontend/app/views/viewer/viewer.actions.js b/animism-align/frontend/app/views/viewer/viewer.actions.js index c1b11be..3b6fbdd 100644 --- a/animism-align/frontend/app/views/viewer/viewer.actions.js +++ b/animism-align/frontend/app/views/viewer/viewer.actions.js @@ -11,6 +11,7 @@ import { import { floatInRange } from 'app/utils' import { buildParagraphs } from 'app/utils/transcript.utils' import { annotationFadeTimings } from 'app/utils/annotation.utils' +import { getNextSection } from 'app/utils/viewer.utils' const newSection = (annotation, index, mediaIndex) => ({ start_ts: annotation.start_ts, @@ -176,14 +177,6 @@ export const toggleComponent = key => dispatch => { dispatch({ type: types.viewer.toggle_component, key, value: !store.getState().viewer[key] }) } -const getNextSection = section => { - const { sections } = store.getState().viewer - if (section.index === sections.length - 1) { - return null - } - return sections[section.index + 1] -} - export const reachedEndOfSection = () => dispatch => { actions.audio.pause() dispatch({ type: types.viewer.reached_end_of_section }) |
