diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-07-17 18:52:24 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-07-17 18:52:24 +0200 |
| commit | 4bb72b9f6d2a56fc6bd67f4248fcabfcc8166493 (patch) | |
| tree | 55874ddef076c2b608844388fc40deedf8da55d0 /animism-align/frontend/views | |
| parent | d579a10ba169d6e95e8ea8a9d7f2821fe89bca1f (diff) | |
refactor annotation and paragraph types
Diffstat (limited to 'animism-align/frontend/views')
15 files changed, 285 insertions, 163 deletions
diff --git a/animism-align/frontend/views/align/components/annotations/annotation.form.js b/animism-align/frontend/views/align/components/annotations/annotation.form.js index 53f640f..01b1663 100644 --- a/animism-align/frontend/views/align/components/annotations/annotation.form.js +++ b/animism-align/frontend/views/align/components/annotations/annotation.form.js @@ -11,8 +11,13 @@ import { clamp, timestamp, capitalize } from '../../../../util' import { timeToPosition } from '../../align.util' import { Select } from '../../../../common' +import { + AnnotationFormVideo, + AnnotationFormImage, +} from './annotationForms' + const ANNOTATION_TYPES = [ - 'sentence', 'header', 'paragraph_end', 'video', + 'sentence', 'header', 'paragraph_end', 'video', 'image', 'image_carousel', ].map(name => ({ name, label: capitalize(name.replace('_', ' ')) })) class AnnotationForm extends Component { @@ -105,7 +110,7 @@ class AnnotationForm extends Component { } } render() { - const { timeline, annotation } = this.props + const { timeline, annotation, media } = this.props if (!annotation.start_ts) return <div></div> return ( <div @@ -117,7 +122,15 @@ class AnnotationForm extends Component { {this.renderButtons()} {annotation.type === 'sentence' && this.renderTextarea()} {annotation.type === 'header' && this.renderTextarea()} - {annotation.type === 'video' && this.renderVideo()} + {annotation.type === 'video' && + <AnnotationFormVideo annotation={annotation} media={media} handleSettingsSelect={this.handleSettingsSelect} /> + } + {annotation.type === 'image' && + <AnnotationFormImage annotation={annotation} media={media} handleSettingsSelect={this.handleSettingsSelect} /> + } + {annotation.type === 'image_carousel' && + <AnnotationFormImageCarousel annotation={annotation} media={media} handleSettingsSelect={this.handleSettingsSelect} /> + } </div> ) } @@ -156,30 +169,6 @@ class AnnotationForm extends Component { </div> ) } - renderVideo() { - const { annotation, media } = this.props - if (!media.lookup) return <div /> - const { lookup, order } = media - const video_list_items = order.filter(id => lookup[id].type === 'video').map(id => { - const video = lookup[id] - return { - name: video.id, - label: video.author + ' - ' + video.title - } - }) - return ( - <div> - <Select - name='media_id' - className="media_id" - selected={annotation.settings.media_id} - options={video_list_items} - defaultOption='Choose a video' - onChange={this.handleSettingsSelect} - /> - </div> - ) - } } const mapStateToProps = state => ({ diff --git a/animism-align/frontend/views/align/components/annotations/annotation.index.js b/animism-align/frontend/views/align/components/annotations/annotation.index.js index b055d60..65de5dd 100644 --- a/animism-align/frontend/views/align/components/annotations/annotation.index.js +++ b/animism-align/frontend/views/align/components/annotations/annotation.index.js @@ -8,7 +8,7 @@ import { ZOOM_STEPS, INNER_HEIGHT } from '../../constants' import { clamp } from '../../../../util' import { positionToTime, timeToPosition } from '../../align.util' -import { AnnotationElementLookup } from './annotation.types' +import { AnnotationElementLookup } from './annotationTypes' class AnnotationIndex extends Component { state = { diff --git a/animism-align/frontend/views/align/components/annotations/annotation.types.js b/animism-align/frontend/views/align/components/annotations/annotation.types.js deleted file mode 100644 index 55cc3e7..0000000 --- a/animism-align/frontend/views/align/components/annotations/annotation.types.js +++ /dev/null @@ -1,108 +0,0 @@ -import React, { Component } from 'react' - -import actions from '../../../../actions' - -import { ZOOM_STEPS } from '../../constants' -import { clamp } from '../../../../util' -import { positionToTime, timeToPosition, thumbnailURL } from '../../align.util' - -export const AnnotationSentence = ({ y, annotation, selected, onClick, onDoubleClick }) => { - const { start_ts, text, paragraph_id } = annotation - let className = !paragraph_id - ? 'annotation sentence' - : (paragraph_id % 2) - ? 'annotation sentence odd' - : 'annotation sentence even' - if (selected) className += ' selected' - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - dangerouslySetInnerHTML={{ __html: text }} - /> - ) -} - -export const AnnotationHeader = ({ y, annotation, selected, onClick, onDoubleClick }) => { - const { start_ts, text } = annotation - const className = selected ? 'annotation header selected' : 'annotation header' - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - > - {text} - </div> - ) -} - -export const AnnotationParagraphEnd = ({ y, annotation, selected, onClick, onDoubleClick }) => { - const { start_ts, text } = annotation - const className = selected ? 'annotation paragraph_end selected' : 'annotation paragraph_end' - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - > - </div> - ) -} - -export const AnnotationVideo = ({ y, annotation, media, selected, onClick, onDoubleClick }) => { - const { start_ts, text } = annotation - const className = selected ? 'annotation media video selected' : 'annotation media video' - if (!media) { - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - >LOADING...</div> - ) - } - if (!(annotation.settings.media_id in media)) { - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - >MEDIA NOT FOUND</div> - ) - } - const data = media[annotation.settings.media_id] - return ( - <div - className={className} - style={{ top: y }} - onClick={e => onClick(e, annotation)} - onDoubleClick={e => onDoubleClick(e, annotation)} - > - <div className='img'> - <img src={thumbnailURL(data)} alt={data.title} /> - </div> - <div className='meta center'> - <div> - <i>{data.title}</i><br /> - {data.author}<br /> - {data.date} - </div> - </div> - </div> - ) -} - - -export const AnnotationElementLookup = { - sentence: React.memo(AnnotationSentence), - header: React.memo(AnnotationHeader), - paragraph_end: React.memo(AnnotationParagraphEnd), - video: React.memo(AnnotationVideo), -} diff --git a/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.image.js b/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.image.js new file mode 100644 index 0000000..e2df98b --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.image.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' + +import { Select } from '../../../../../common' + +export const AnnotationFormImage = ({ annotation, media, handleSettingsSelect }) => { + if (!media.lookup) return <div /> + const { lookup, order } = media + const image_list_items = order.filter(id => lookup[id].type === 'image').map(id => { + const image = lookup[id] + return { + name: image.id, + label: image.author + ' - ' + image.title + } + }) + return ( + <div> + <Select + name='media_id' + className="media_id" + selected={annotation.settings.media_id} + options={image_list_items} + defaultOption='Choose an image' + onChange={handleSettingsSelect} + /> + </div> + ) +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.video.js b/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.video.js new file mode 100644 index 0000000..9302ba4 --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.video.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' + +import { Select } from '../../../../../common' + +export const AnnotationFormVideo = ({ annotation, media, handleSettingsSelect }) => { + if (!media.lookup) return <div /> + const { lookup, order } = media + const video_list_items = order.filter(id => lookup[id].type === 'video').map(id => { + const video = lookup[id] + return { + name: video.id, + label: video.author + ' - ' + video.title + } + }) + return ( + <div> + <Select + name='media_id' + className="media_id" + selected={annotation.settings.media_id} + options={video_list_items} + defaultOption='Choose a video' + onChange={handleSettingsSelect} + /> + </div> + ) +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationForms/index.js b/animism-align/frontend/views/align/components/annotations/annotationForms/index.js new file mode 100644 index 0000000..1411efc --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationForms/index.js @@ -0,0 +1,12 @@ +import { + AnnotationFormVideo, +} from './annotationForm.video' + +import { + AnnotationFormImage, +} from './annotationForm.image' + +export { + AnnotationFormImage, + AnnotationFormVideo, +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.image.js b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.image.js new file mode 100644 index 0000000..c3e0c22 --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.image.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' + +import { thumbnailURL } from '../../../align.util' + +import { checkAnnotationMediaNotReady, AnnotationMediaLoading } from './annotationTypes.util' + +export const AnnotationImage = ({ y, annotation, media, selected, onClick, onDoubleClick }) => { + const { start_ts, text } = annotation + const className = selected ? 'annotation media image selected' : 'annotation media image' + if (checkAnnotationMediaNotReady(annotation, media)) { + return <AnnotationMediaLoading y={y} className={className} onClick={onClick} onDoubleClick={onDoubleClick} /> + } + const data = media[annotation.settings.media_id] + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + > + <div className='img'> + <img src={thumbnailURL(data)} alt={data.title} /> + </div> + <div className='meta center'> + <div> + <i>{data.title}</i><br /> + {data.author}<br /> + {data.date} + </div> + </div> + </div> + ) +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.text.js b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.text.js new file mode 100644 index 0000000..be4674f --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.text.js @@ -0,0 +1,49 @@ +import React, { Component } from 'react' + +export const AnnotationSentence = ({ y, annotation, selected, onClick, onDoubleClick }) => { + const { start_ts, text, paragraph_id } = annotation + let className = !paragraph_id + ? 'annotation sentence' + : (paragraph_id % 2) + ? 'annotation sentence odd' + : 'annotation sentence even' + if (selected) className += ' selected' + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + dangerouslySetInnerHTML={{ __html: text }} + /> + ) +} + +export const AnnotationHeader = ({ y, annotation, selected, onClick, onDoubleClick }) => { + const { start_ts, text } = annotation + const className = selected ? 'annotation header selected' : 'annotation header' + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + > + {text} + </div> + ) +} + +export const AnnotationParagraphEnd = ({ y, annotation, selected, onClick, onDoubleClick }) => { + const { start_ts, text } = annotation + const className = selected ? 'annotation paragraph_end selected' : 'annotation paragraph_end' + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + > + </div> + ) +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.util.js b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.util.js new file mode 100644 index 0000000..17abebd --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.util.js @@ -0,0 +1,28 @@ +import React, { Component } from 'react' + +export const checkAnnotationMediaNotReady = (annotation, media) => { + return (!media) || (!(annotation.settings.media_id in media)) +} + +export const AnnotationMediaLoading = ({ y, className, onClick, onDoubleClick }) => { + if (!media) { + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + >LOADING...</div> + ) + } + if (!(annotation.settings.media_id in media)) { + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + >MEDIA NOT FOUND</div> + ) + } +} diff --git a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.video.js b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.video.js new file mode 100644 index 0000000..dc4f469 --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.video.js @@ -0,0 +1,34 @@ +import React, { Component } from 'react' + +import { thumbnailURL } from '../../../align.util' + +import { checkAnnotationMediaNotReady, AnnotationMediaLoading } from './annotationTypes.util' + +export const AnnotationVideo = ({ y, annotation, media, selected, onClick, onDoubleClick }) => { + const { start_ts, text } = annotation + const className = selected ? 'annotation media video selected' : 'annotation media video' + if (checkAnnotationMediaNotReady(annotation, media)) { + return <AnnotationMediaLoading y={y} className={className} onClick={onClick} onDoubleClick={onDoubleClick} /> + } + const data = media[annotation.settings.media_id] + return ( + <div + className={className} + style={{ top: y }} + onClick={e => onClick(e, annotation)} + onDoubleClick={e => onDoubleClick(e, annotation)} + > + <div className='img'> + <img src={thumbnailURL(data)} alt={data.title} /> + </div> + <div className='meta center'> + <div> + <i>{data.title}</i><br /> + {data.author}<br /> + {data.date} + </div> + </div> + </div> + ) +} + diff --git a/animism-align/frontend/views/align/components/annotations/annotationTypes/index.js b/animism-align/frontend/views/align/components/annotations/annotationTypes/index.js new file mode 100644 index 0000000..3a2fae1 --- /dev/null +++ b/animism-align/frontend/views/align/components/annotations/annotationTypes/index.js @@ -0,0 +1,22 @@ +import React from 'React' + +import { + AnnotationSentence, AnnotationHeader, + AnnotationParagraphEnd, +} from './annotationTypes.text' + +import { + AnnotationVideo, +} from './annotationTypes.video' + +import { + AnnotationImage, +} from './annotationTypes.image' + +export const AnnotationElementLookup = { + sentence: React.memo(AnnotationSentence), + header: React.memo(AnnotationHeader), + paragraph_end: React.memo(AnnotationParagraphEnd), + video: React.memo(AnnotationVideo), + image: React.memo(AnnotationImage), +} diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js new file mode 100644 index 0000000..990c911 --- /dev/null +++ b/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js @@ -0,0 +1,16 @@ +import React from 'react' + +import { + Paragraph, ParagraphHeader +} from './paragraphTypes.text' + +import { + MediaVideo +} from './paragraphTypes.video' + +export const ParagraphElementLookup = { + paragraph: React.memo(Paragraph), + blockquote: React.memo(Paragraph), + header: React.memo(ParagraphHeader), + video: React.memo(MediaVideo), +} diff --git a/animism-align/frontend/views/paragraph/components/paragraph.types.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js index fe8158a..5f8dbc3 100644 --- a/animism-align/frontend/views/paragraph/components/paragraph.types.js +++ b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js @@ -1,7 +1,4 @@ import React, { Component } from 'react' -import VimeoPlayer from '@u-wave/react-vimeo' - -import actions from '../../../actions' export const Paragraph = ({ paragraph, selectedParagraph, selectedAnnotation, onAnnotationClick, onDoubleClick }) => { let className = paragraph.type @@ -37,26 +34,3 @@ export const ParagraphHeader = ({ paragraph, selectedParagraph, selectedAnnotati </div> ) } - -export const MediaVideo = ({ paragraph, media, selectedParagraph, selectedAnnotation, onAnnotationClick, onDoubleClick }) => { - if (!media.lookup) return <div /> - const className = selectedParagraph ? 'media selected' : 'media' - const annotation = paragraph.annotations[0] - const item = media.lookup[annotation.settings.media_id] - if (!item) return <div>Media not found: {annotation.settings.media_id}</div> - return ( - <div - className={className} - onDoubleClick={e => onDoubleClick(e, paragraph)} - > - <VimeoPlayer video={item.url} autoplay muted width="650" /> - </div> - ) -} - -export const ParagraphElementLookup = { - paragraph: React.memo(Paragraph), - blockquote: React.memo(Paragraph), - header: React.memo(ParagraphHeader), - video: React.memo(MediaVideo), -} diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js new file mode 100644 index 0000000..8e224f3 --- /dev/null +++ b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js @@ -0,0 +1,19 @@ +import React, { Component } from 'react' + +import VimeoPlayer from '@u-wave/react-vimeo' + +export const MediaVideo = ({ paragraph, media, selectedParagraph, selectedAnnotation, onAnnotationClick, onDoubleClick }) => { + if (!media.lookup) return <div /> + const className = selectedParagraph ? 'media selected' : 'media' + const annotation = paragraph.annotations[0] + const item = media.lookup[annotation.settings.media_id] + if (!item) return <div>Media not found: {annotation.settings.media_id}</div> + return ( + <div + className={className} + onDoubleClick={e => onDoubleClick(e, paragraph)} + > + <VimeoPlayer video={item.url} autoplay muted width="650" /> + </div> + ) +} diff --git a/animism-align/frontend/views/paragraph/containers/paragraphList.container.js b/animism-align/frontend/views/paragraph/containers/paragraphList.container.js index fc1a687..deeb347 100644 --- a/animism-align/frontend/views/paragraph/containers/paragraphList.container.js +++ b/animism-align/frontend/views/paragraph/containers/paragraphList.container.js @@ -4,7 +4,7 @@ import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import actions from '../../../actions' -import { ParagraphElementLookup } from '../components/paragraph.types' +import { ParagraphElementLookup } from '../components/paragraphTypes' const floatLT = (a,b) => ((a*10|0) < (b*10|0)) const floatLTE = (a,b) => ((a*10|0) === (b*10|0) || floatLT(a,b)) |
