summaryrefslogtreecommitdiff
path: root/animism-align/frontend/app
diff options
context:
space:
mode:
Diffstat (limited to 'animism-align/frontend/app')
-rw-r--r--animism-align/frontend/app/constants.js5
-rw-r--r--animism-align/frontend/app/utils/index.js1
-rw-r--r--animism-align/frontend/app/views/media/components/media.formGallery.js93
-rw-r--r--animism-align/frontend/app/views/media/components/media.formImage.js6
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js2
-rw-r--r--animism-align/frontend/app/views/viewer/player/components.utility/media.citation.js8
-rw-r--r--animism-align/frontend/app/views/viewer/player/player.container.js1
-rw-r--r--animism-align/frontend/app/views/viewer/player/player.fullscreen.js1
-rw-r--r--animism-align/frontend/app/views/viewer/sections/sections.css30
-rw-r--r--animism-align/frontend/app/views/viewer/sections/viewer.sections.js44
-rw-r--r--animism-align/frontend/app/views/viewer/viewer.actions.js12
11 files changed, 130 insertions, 73 deletions
diff --git a/animism-align/frontend/app/constants.js b/animism-align/frontend/app/constants.js
index 69f2b44..16548ee 100644
--- a/animism-align/frontend/app/constants.js
+++ b/animism-align/frontend/app/constants.js
@@ -81,3 +81,8 @@ export const CURTAIN_COLOR_LOOKUP = CURTAIN_COLORS.reduce((a,b) => {
a[b.label] = b
return a
}, {})
+
+export const DISPLAY_SIZE = 2000
+export const DISPLAY_QUALITY= 80
+export const THUMBNAIL_SIZE = 320
+export const THUMBNAIL_QUALITY = 80
diff --git a/animism-align/frontend/app/utils/index.js b/animism-align/frontend/app/utils/index.js
index b7c05da..9a47df3 100644
--- a/animism-align/frontend/app/utils/index.js
+++ b/animism-align/frontend/app/utils/index.js
@@ -92,6 +92,7 @@ export const angle = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1)
export const floatLT = (a,b) => ((a*10|0) < (b*10|0))
export const floatLTE = (a,b) => ((a*10|0) === (b*10|0) || floatLT(a,b))
export const floatInRange = (a,b,c) => floatLTE(a, b) && floatLT(b, c)
+export const simpleArraysEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b)
/* URLs */
diff --git a/animism-align/frontend/app/views/media/components/media.formGallery.js b/animism-align/frontend/app/views/media/components/media.formGallery.js
index e5311cb..f785b40 100644
--- a/animism-align/frontend/app/views/media/components/media.formGallery.js
+++ b/animism-align/frontend/app/views/media/components/media.formGallery.js
@@ -4,16 +4,12 @@ import { ReactSortable } from "react-sortablejs"
import { session } from 'app/session'
import actions from 'app/actions'
-import { capitalize, preloadImage } from 'app/utils'
+import { capitalize, preloadImage, simpleArraysEqual } from 'app/utils'
+import { DISPLAY_SIZE, DISPLAY_QUALITY, THUMBNAIL_SIZE, THUMBNAIL_QUALITY } from 'app/constants'
import { TextInput, LabelDescription, FileInputField, Select, TextArea, Checkbox, SubmitButton, Loader } from 'app/common'
import { renderThumbnail } from 'app/common/upload.helpers'
-const DISPLAY_SIZE = 2000
-const DISPLAY_QUALITY= 80
-const THUMBNAIL_SIZE = 320
-const THUMBNAIL_QUALITY = 80
-
export default class MediaGalleryForm extends Component {
state = {
loading: false,
@@ -44,13 +40,20 @@ export default class MediaGalleryForm extends Component {
handleUpload(files) {
const { data } = this.props
this.setState({ loading: true })
+ this.uploadFullsize(files)
+ .then(() => {
+ this.setState({ loading: false })
+ })
+ }
+
+ uploadFullsize(files) {
+ const { data } = this.props
// first, upload all the fullsize files
let fullsizeUploadPromises = files.map(file => {
return this.uploadSize(file, 'fullsize')
})
// when these are done
- Promise.all(fullsizeUploadPromises)
- .then(results => {
+ return Promise.all(fullsizeUploadPromises).then(results => {
// get the added IDs in order
const added_image_order = results.map(result => result.id)
// append the new IDs to the image order
@@ -66,29 +69,44 @@ export default class MediaGalleryForm extends Component {
image_lookup: image_lookup,
thumbnail_lookup: data.settings.thumbnail_lookup || {},
})
- // construct thumbnails and upload these
- const thumbnailUploadPromises = files.map(file => {
- return this.uploadThumbnail(file)
+ return this.uploadResizedFiles(files, added_image_order)
+ })
+ }
+
+ uploadResizedFiles(files, added_image_order) {
+ return (
+ this.uploadThumbnails(files, added_image_order, 'thumbnail', THUMBNAIL_SIZE, THUMBNAIL_QUALITY)
+ .then(() => {
+ return this.uploadThumbnails(files, added_image_order, 'display', DISPLAY_SIZE, DISPLAY_QUALITY)
})
- // once the thumbnails are done uploading
- Promise.all(thumbnailUploadPromises)
- .then(thumbnail_results => {
- // add them to the thumbnail lookup, keyed off the ID of the fullsize image
- const thumbnail_lookup = thumbnail_results.reduce((a, b, i) => {
- const id = added_image_order[i]
- a[id] = b
- return a
- }, (data.settings.thumbnail_lookup || {}))
- // update the settings object
- this.handleSettingsChange('multiple', {
- thumbnail_lookup: thumbnail_lookup,
- })
- this.setState({ loading: false })
+ )
+ }
+
+ uploadThumbnails(files, added_image_order, tag, maxSide, quality) {
+ const { data } = this.props
+ // construct thumbnails and upload these
+ const thumbnailUploadPromises = files.map(file => {
+ return this.uploadThumbnail(file, tag, maxSide, quality)
+ })
+ // once the thumbnails are done uploading...
+ return Promise.all(thumbnailUploadPromises).then(thumbnail_results => {
+ // decide which lookup we're adding to
+ const tag_lookup_name = tag + '_lookup'
+ const tag_lookup = data.settings[tag_lookup_name] || {}
+ // add them to the thumbnail lookup, keyed off the ID of the fullsize image
+ const thumbnail_lookup = thumbnail_results.reduce((a, b, i) => {
+ const id = added_image_order[i]
+ a[id] = b
+ return a
+ }, tag_lookup)
+ // update the settings object
+ this.handleSettingsChange('multiple', {
+ [tag_lookup_name]: thumbnail_lookup,
})
})
}
- uploadThumbnail(file) {
+ uploadThumbnail(file, tag, maxSide, quality) {
return new Promise((resolve, reject) => {
const type = (file.name.match('.png') !== -1) ? 'image/png' : 'image/jpg'
const fr = new FileReader()
@@ -97,16 +115,16 @@ export default class MediaGalleryForm extends Component {
const image = new Image()
image.onload = () => {
image.onload = null
- const thumbnailCanvas = renderThumbnail(image, { maxSide: THUMBNAIL_SIZE })
+ const thumbnailCanvas = renderThumbnail(image, { maxSide })
thumbnailCanvas.toBlob(thumbnail => {
- this.uploadSize(thumbnail, 'thumbnail', file.name)
+ this.uploadSize(thumbnail, tag, file.name)
.then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
- }, type, THUMBNAIL_QUALITY)
+ }, type, quality)
}
image.src = fileReaderEvent.target.result
}
@@ -115,7 +133,7 @@ export default class MediaGalleryForm extends Component {
}
uploadSize(image, tag, fn) {
- console.log('uploading size', tag)
+ // console.log('uploading size', tag)
const uploadData = {
image,
tag,
@@ -131,12 +149,13 @@ export default class MediaGalleryForm extends Component {
})
}
- handleOrderChanged(image_order) {
- console.log(image_order)
- // if (image_order !== this.props.data.settings.image_order) {
- // console.log('handle order chagned', image_order)
- // this.handleSettingsChange('image_order', image_order)
- // }
+ handleOrderChanged(new_image_order) {
+ // console.log(new_image_order)
+ const image_order = new_image_order.map(el => el.id)
+ if (!simpleArraysEqual(image_order, this.props.data.settings.image_order)) {
+ console.log('order changed', image_order)
+ this.handleSettingsChange('image_order', image_order)
+ }
}
render() {
@@ -173,7 +192,7 @@ export default class MediaGalleryForm extends Component {
}
const GalleryImageForm = ({ id, key, image, thumbnail }) => {
- console.log(image, thumbnail)
+ // console.log(image, thumbnail)
return (
<div>
{thumbnail
diff --git a/animism-align/frontend/app/views/media/components/media.formImage.js b/animism-align/frontend/app/views/media/components/media.formImage.js
index 04b821f..7f22af0 100644
--- a/animism-align/frontend/app/views/media/components/media.formImage.js
+++ b/animism-align/frontend/app/views/media/components/media.formImage.js
@@ -4,17 +4,13 @@ import { Link } from 'react-router-dom'
import { session } from 'app/session'
import actions from 'app/actions'
import { capitalize, preloadImage, cropImage } from 'app/utils'
+import { DISPLAY_SIZE, DISPLAY_QUALITY, THUMBNAIL_SIZE, THUMBNAIL_QUALITY } from 'app/constants'
import { TextInput, LabelDescription, UploadImage, Select, TextArea, Checkbox, SubmitButton, Loader } from 'app/common'
import { renderThumbnail } from 'app/common/upload.helpers'
import ImageSelection from './media.formImageSelection'
-const DISPLAY_SIZE = 2000
-const DISPLAY_QUALITY= 80
-const THUMBNAIL_SIZE = 320
-const THUMBNAIL_QUALITY = 80
-
export default class MediaImageForm extends Component {
state = {
img: null,
diff --git a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js
index 6ca7ec8..a048fa1 100644
--- a/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js
+++ b/animism-align/frontend/app/views/viewer/player/components.fullscreen/fullscreen.video.js
@@ -9,7 +9,7 @@ export const FullscreenVideo = ({ element, media, transitionDuration }) => {
color: color.textColor,
transitionDuration,
}
- console.log(item, window.innerWidth, window.innerHeight)
+ console.log(item)
return (
<div
className='fullscreen-element video'
diff --git a/animism-align/frontend/app/views/viewer/player/components.utility/media.citation.js b/animism-align/frontend/app/views/viewer/player/components.utility/media.citation.js
index 7b3212d..14c8c53 100644
--- a/animism-align/frontend/app/views/viewer/player/components.utility/media.citation.js
+++ b/animism-align/frontend/app/views/viewer/player/components.utility/media.citation.js
@@ -10,9 +10,13 @@ export const MediaCitation = ({ media }) => {
<div className='citation'>
{media.author}
{', '}
- {media.pre_title}
+ {media.pre_title && (
+ media.pre_title + ' '
+ )}
<i>{media.title}</i>
- {media.post_title}
+ {media.post_title && (
+ ' ' + media.post_title
+ )}
{'. '}
{media.date && (
' ' + media.date + '.'
diff --git a/animism-align/frontend/app/views/viewer/player/player.container.js b/animism-align/frontend/app/views/viewer/player/player.container.js
index 0ac5662..8a23720 100644
--- a/animism-align/frontend/app/views/viewer/player/player.container.js
+++ b/animism-align/frontend/app/views/viewer/player/player.container.js
@@ -36,6 +36,7 @@ class PlayerContainer extends Component {
}
return false
})
+
if (!insideSection) {
actions.viewer.setCurrentSection(sections[sections.length-1], null)
}
diff --git a/animism-align/frontend/app/views/viewer/player/player.fullscreen.js b/animism-align/frontend/app/views/viewer/player/player.fullscreen.js
index a4acef9..133653d 100644
--- a/animism-align/frontend/app/views/viewer/player/player.fullscreen.js
+++ b/animism-align/frontend/app/views/viewer/player/player.fullscreen.js
@@ -27,6 +27,7 @@ class PlayerFullscreen extends Component {
const elements = timeline.filter(element => (
floatInRange(element.start_ts, play_ts, element.fade_out_start_ts + 0.1)
))
+ console.log(elements)
if (elements.length) {
const lastElement = elements[elements.length - 1]
if (lastElement.color && lastElement.color.textColor === '#ffffff') {
diff --git a/animism-align/frontend/app/views/viewer/sections/sections.css b/animism-align/frontend/app/views/viewer/sections/sections.css
index a94b712..0ca84a2 100644
--- a/animism-align/frontend/app/views/viewer/sections/sections.css
+++ b/animism-align/frontend/app/views/viewer/sections/sections.css
@@ -8,7 +8,6 @@
background: black;
color: white;
display: block;
- white-space: nowrap;
transition: transform 0.2s;
transform: translateZ(0) translateY(25rem);
border-top: 1px solid #fff;
@@ -17,10 +16,37 @@
transform: translateZ(0) translateY(0);
}
.checklist-open .viewer-sections {
- transform: translateZ(0) translateY(calc(3rem - 100vh));
+ transform: translateZ(0) translateY(calc(3rem - 100vh - 4px));
z-index: 20;
}
+/* scrolling part */
+
+.viewer-sections .viewer-sections-scroll {
+ width: 100%;
+ white-space: nowrap;
+ overflow-y: auto;
+}
+.viewer-sections-scroll::-webkit-scrollbar {
+ cursor: pointer;
+ user-select: none;
+ height: 4px
+}
+.viewer-sections-scroll::-webkit-scrollbar-button {
+ display: block;
+ width: 0;
+ height: 0;
+}
+.viewer-sections-scroll::-webkit-scrollbar-track-piece {
+ background:rgba(211,211,211,0.8);
+}
+.viewer-sections-scroll::-webkit-scrollbar-thumb {
+ display: block;
+ background: #000;
+}
+
+/* clickable section indicators */
+
.viewer-sections .viewer-section {
display: inline-flex;
white-space: normal;
diff --git a/animism-align/frontend/app/views/viewer/sections/viewer.sections.js b/animism-align/frontend/app/views/viewer/sections/viewer.sections.js
index f4abbd6..4bb61ec 100644
--- a/animism-align/frontend/app/views/viewer/sections/viewer.sections.js
+++ b/animism-align/frontend/app/views/viewer/sections/viewer.sections.js
@@ -12,29 +12,31 @@ class ViewerSections extends Component {
const { sections } = this.props
return (
<div className="viewer-sections">
- {sections.map(section => {
- // console.log(section)
- return (
- <div
- className="viewer-section"
- key={section.index}
- onClick={() => actions.viewer.seekToSection(section)}
- >
- <div>
- <div className="section-thumbnail" style={{
- backgroundImage: section.media.length && 'url(' + thumbnailURL(section.media[0].media) + ')',
- }}/>
- <div className="section-title">
- {ROMAN_NUMERALS[section.index]}<br />
- {section.title}
- </div>
- <div className="section-media">
- {section.mediaLabels}
+ <div className="viewer-sections-scroll">
+ {sections.map(section => {
+ // console.log(section)
+ return (
+ <div
+ className="viewer-section"
+ key={section.index}
+ onClick={() => actions.viewer.seekToSection(section)}
+ >
+ <div>
+ <div className="section-thumbnail" style={{
+ backgroundImage: section.media.length && 'url(' + thumbnailURL(section.media[0].media) + ')',
+ }}/>
+ <div className="section-title">
+ {ROMAN_NUMERALS[section.index]}<br />
+ {section.title}
+ </div>
+ <div className="section-media">
+ {section.mediaLabels}
+ </div>
</div>
</div>
- </div>
- )
- })}
+ )
+ })}
+ </div>
<ViewerSectionsNav />
</div>
)
diff --git a/animism-align/frontend/app/views/viewer/viewer.actions.js b/animism-align/frontend/app/views/viewer/viewer.actions.js
index 1547606..ae2bf5b 100644
--- a/animism-align/frontend/app/views/viewer/viewer.actions.js
+++ b/animism-align/frontend/app/views/viewer/viewer.actions.js
@@ -80,10 +80,12 @@ export const loadSections = () => dispatch => {
if (MEDIA_ANNOTATION_TYPES.has(annotation.type)) {
// fetch the media and add it to the list of media (TODO: handle carousels)
const media = mediaLookup[annotation.settings.media_id]
- currentSection.media.push({
- start_ts: annotation.start_ts,
- media
- })
+ if (!media.settings.hide_in_bibliography) {
+ currentSection.media.push({
+ start_ts: annotation.start_ts,
+ media
+ })
+ }
// get the display string for this media type
if (media.type in MEDIA_LABEL_TYPES) {
@@ -93,7 +95,7 @@ export const loadSections = () => dispatch => {
// increment the media tally
mediaIndex += 1
- // non-fullscreen, inline media should be displayed in the transcript.
+ // non-fullscreen (or fullscreen-inline) media should be displayed in the transcript.
if (!annotation.settings.fullscreen || annotation.settings.inline) {
sectionTextAnnotationOrder.push(annotation.id)
}