summaryrefslogtreecommitdiff
path: root/animism-align/frontend/views
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2020-07-22 14:05:15 +0200
committerJules Laplace <julescarbon@gmail.com>2020-07-22 14:05:15 +0200
commitef78bc6a084f92b4794e987b5832240d85b6479e (patch)
treeb314b630800db6aa60f28ef0b115625e6ca176db /animism-align/frontend/views
parent85d4cb9addf9ca887d3440b2786665d67d9917c4 (diff)
refactor app using babel module-resolver
Diffstat (limited to 'animism-align/frontend/views')
-rw-r--r--animism-align/frontend/views/align/align.actions.js93
-rw-r--r--animism-align/frontend/views/align/align.container.js30
-rw-r--r--animism-align/frontend/views/align/align.css215
-rw-r--r--animism-align/frontend/views/align/align.reducer.js85
-rw-r--r--animism-align/frontend/views/align/align.util.js65
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotation.form.js183
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotation.index.js126
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.image.js27
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.video.js27
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationForms/index.js12
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.image.js33
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.text.js49
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.util.js28
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.video.js34
-rw-r--r--animism-align/frontend/views/align/components/annotations/annotationTypes/index.js22
-rw-r--r--animism-align/frontend/views/align/components/player/playButton.component.js31
-rw-r--r--animism-align/frontend/views/align/components/timeline/cursor.component.js26
-rw-r--r--animism-align/frontend/views/align/components/timeline/playCursor.component.js36
-rw-r--r--animism-align/frontend/views/align/components/timeline/ticks.component.js88
-rw-r--r--animism-align/frontend/views/align/components/timeline/waveform.component.js99
-rw-r--r--animism-align/frontend/views/align/constants.js34
-rw-r--r--animism-align/frontend/views/align/containers/annotations.container.js40
-rw-r--r--animism-align/frontend/views/align/containers/script.container.js34
-rw-r--r--animism-align/frontend/views/align/containers/timeline.container.js171
-rw-r--r--animism-align/frontend/views/annotation/annotation.reducer.js21
-rw-r--r--animism-align/frontend/views/audio/audio.actions.js40
-rw-r--r--animism-align/frontend/views/audio/audio.reducer.js30
-rw-r--r--animism-align/frontend/views/index.js4
-rw-r--r--animism-align/frontend/views/media/components/media.form.js272
-rw-r--r--animism-align/frontend/views/media/components/media.formImage.js172
-rw-r--r--animism-align/frontend/views/media/components/media.formImageSelection.js213
-rw-r--r--animism-align/frontend/views/media/components/media.formVideo.js111
-rw-r--r--animism-align/frontend/views/media/components/media.indexOptions.js65
-rw-r--r--animism-align/frontend/views/media/components/media.menu.js58
-rw-r--r--animism-align/frontend/views/media/containers/media.edit.js57
-rw-r--r--animism-align/frontend/views/media/containers/media.index.js115
-rw-r--r--animism-align/frontend/views/media/containers/media.new.js81
-rw-r--r--animism-align/frontend/views/media/media.actions.js9
-rw-r--r--animism-align/frontend/views/media/media.container.js38
-rw-r--r--animism-align/frontend/views/media/media.css70
-rw-r--r--animism-align/frontend/views/media/media.reducer.js22
-rw-r--r--animism-align/frontend/views/nav/header.component.js42
-rw-r--r--animism-align/frontend/views/nav/nav.css73
-rw-r--r--animism-align/frontend/views/paragraph/components/paragraph.form.js87
-rw-r--r--animism-align/frontend/views/paragraph/components/paragraphTypes/index.js22
-rw-r--r--animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.image.js17
-rw-r--r--animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js35
-rw-r--r--animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js19
-rw-r--r--animism-align/frontend/views/paragraph/containers/paragraphList.container.js206
-rw-r--r--animism-align/frontend/views/paragraph/paragraph.container.js70
-rw-r--r--animism-align/frontend/views/paragraph/paragraph.css93
-rw-r--r--animism-align/frontend/views/paragraph/paragraph.reducer.js20
-rw-r--r--animism-align/frontend/views/site/component.template.js28
-rw-r--r--animism-align/frontend/views/site/site.actions.js16
-rw-r--r--animism-align/frontend/views/site/site.reducer.js26
-rw-r--r--animism-align/frontend/views/upload/components/upload.form.js16
-rw-r--r--animism-align/frontend/views/upload/components/upload.index.js98
-rw-r--r--animism-align/frontend/views/upload/components/upload.indexOptions.js61
-rw-r--r--animism-align/frontend/views/upload/components/upload.menu.js18
-rw-r--r--animism-align/frontend/views/upload/components/upload.show.js69
-rw-r--r--animism-align/frontend/views/upload/upload.actions.js18
-rw-r--r--animism-align/frontend/views/upload/upload.container.js36
-rw-r--r--animism-align/frontend/views/upload/upload.css182
-rw-r--r--animism-align/frontend/views/upload/upload.reducer.js22
64 files changed, 0 insertions, 4240 deletions
diff --git a/animism-align/frontend/views/align/align.actions.js b/animism-align/frontend/views/align/align.actions.js
deleted file mode 100644
index 2ace824..0000000
--- a/animism-align/frontend/views/align/align.actions.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import * as types from '../../types'
-import { store, history, dispatch } from '../../store'
-import { api, post, pad, preloadImage } from '../../util'
-import actions from '../../actions'
-import { session } from '../../session'
-import throttle from 'lodash.throttle'
-import debounce from 'lodash.debounce'
-
-import { ZOOM_STEPS } from './constants'
-import { getFirstPunctuationMarkIndex, cutFirstSentence } from './align.util'
-
-export const setScrollPosition = start_ts => dispatch => (
- dispatch({ type: types.align.set_display_setting, key: 'start_ts', value: start_ts })
-)
-
-export const setZoom = zoom => dispatch => {
- if (0 <= zoom && zoom < ZOOM_STEPS.length) {
- dispatch({ type: types.align.set_display_setting, key: 'zoom', value: zoom })
- }
-}
-export const throttledSetZoom = throttle(zoom => dispatch => {
- setZoom(zoom)(dispatch)
-}, 250, { leading: true })
-
-export const setCursor = cursor_ts => dispatch => (
- dispatch({ type: types.align.set_display_setting, key: 'cursor_ts', value: cursor_ts })
-)
-
-export const setSelectedAnnotation = annotation => dispatch => {
- dispatch({ type: types.align.set_selected_annotation, data: annotation })
- debouncedUpdateAnnotation.flush()
-}
-export const clearSelectedAnnotation = () => dispatch => {
- dispatch({ type: types.align.clear_selected_annotation })
- debouncedUpdateAnnotation.flush()
-}
-export const updateSelectedAnnotation = annotation => dispatch => {
- dispatch({ type: types.align.set_selected_annotation, data: { ...annotation } })
- debouncedUpdateAnnotation(annotation)
-}
-export const debouncedUpdateAnnotation = debounce(annotation => {
- console.log('updating annotation', annotation)
- actions.annotation.update(annotation)
-}, 2000, { leading: false, trailing: true })
-
-
-export const setSelectedParagraph = paragraph_id => dispatch => {
- dispatch({ type: types.align.set_display_setting, key: 'selected_paragraph_id', value: paragraph_id })
-}
-export const clearSelectedParagraph = paragraph_id => dispatch => {
- dispatch({ type: types.align.set_display_setting, key: 'selected_paragraph_id', value: -1 })
-}
-
-export const showNewAnnotationForm = (start_ts, text) => dispatch => {
- let croppedText;
- if (store.getState().align.annotation.start_ts) {
- croppedText = store.getState().align.annotation.text
- } else {
- croppedText = cutFirstSentence(text)
- }
- // console.log(croppedText)
- dispatch({
- type: types.align.set_temporary_annotation,
- data: {
- id: 'new',
- start_ts,
- end_ts: 0.0,
- text: croppedText,
- type: 'sentence',
- settings: {},
- }
- })
-}
-export const showEditAnnotationForm = (annotation) => dispatch => {
- dispatch({
- type: types.align.set_temporary_annotation,
- data: annotation,
- })
-}
-
-export const updateAnnotationForm = (key, value) => dispatch => {
- dispatch({ type: types.align.update_temporary_annotation, key, value })
-}
-export const updateAnnotationSettings = (key, value) => dispatch => {
- dispatch({ type: types.align.update_temporary_annotation_settings, key, value })
-}
-
-export const hideAnnotationForm = () => dispatch => {
- dispatch({
- type: types.align.set_temporary_annotation,
- data: {}
- })
-}
diff --git a/animism-align/frontend/views/align/align.container.js b/animism-align/frontend/views/align/align.container.js
deleted file mode 100644
index 94036e1..0000000
--- a/animism-align/frontend/views/align/align.container.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React, { Component } from 'react'
-import { Route } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import './align.css'
-
-import Timeline from './containers/timeline.container.js'
-import Script from './containers/script.container.js'
-import actions from '../../actions'
-import { Header } from '../../common'
-
-class Container extends Component {
- componentDidMount() {
- document.body.scrollTo(0, 0)
- document.body.parentNode.scrollTo(0, 0)
- }
- render() {
- return (
- <div className='body'>
- <div className='row'>
- <Timeline />
- </div>
- <Script />
- </div>
- )
- }
-}
-
-export default Container
diff --git a/animism-align/frontend/views/align/align.css b/animism-align/frontend/views/align/align.css
deleted file mode 100644
index bbf3bc2..0000000
--- a/animism-align/frontend/views/align/align.css
+++ /dev/null
@@ -1,215 +0,0 @@
-* {
-
-}
-.body.loading > div {
- padding: 1rem;
-}
-.body {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- background: linear-gradient(
- 0deg,
- rgba(0, 0, 64, 0.5),
- rgba(64, 64, 128, 0.5)
- );
- padding: 0;
-}
-
-/* Timeline */
-
-canvas {
- display: block;
-}
-.timeline {
- display: flex;
- flex-direction: row;
- position: relative;
- width: 300px;
- cursor: crosshair;
-}
-.timelineColumn {
- position: relative;
-}
-.ticks .tick {
- position: absolute;
- right: 0;
- width: 4px;
- height: 1px;
- background: #ddd;
-}
-.ticks .tickLabel {
- position: absolute;
- right: 6px;
- font-size: 12px;
- width: 40px;
- margin-top: -7px;
- text-align: right;
- text-shadow: 0 0 2px #00f;
-}
-.timeline .cursor {
- width: 100%;
- position: absolute;
- left: 0;
- pointer-events: none;
-}
-.timeline .cursor .line {
- width: 100%;
- height: 1px;
- background: #00f;
-}
-.timeline .cursor.playCursor .line {
- background: #ddd;
-}
-.timeline .cursor .tickLabel {
- position: absolute;
- pointer-events: none;
- right: 6px;
- font-size: 12px;
- width: 40px;
- margin-top: -7px;
- text-align: right;
- text-shadow: 0 0 2px #000, 0 0 2px #000, 0 0 2px #000;
-}
-
-/* Audio player */
-
-.playButton {
- /*position: absolute;*/
- /*top: 0; left: 0;*/
- width: 3rem; height: 3rem;
- padding: 1rem;
- background: transparent;
- cursor: pointer;
- background-size: contain;
- background-repeat: no-repeat;
- background-position: center;
-}
-.playButton.playing {
- background-image: url('/static/img/icons_pause_white.svg');
-}
-.playButton.paused {
- background-image: url('/static/img/icons_play_white.svg');
-}
-
-/* Script */
-
-.script {
- height: calc(100vh - 3.15rem);
- z-index: 1;
-}
-
-/* Annotations */
-
-.annotations {
- position: relative;
- width: 450px;
-}
-
-/* Annotation form */
-
-.annotationForm {
- width: 401px;
- padding: 0.5rem;
- position: absolute;
- left: 0.25rem;
- background: #448;
- box-shadow: 0 0 2px #000, 0 0 4px #000;
- z-index: 10;
-}
-.annotationForm textarea {
- width: 100%;
-}
-.annotationForm .row {
- justify-content: space-between;
- align-items: center;
-}
-.annotationForm .row > div {
- display: flex;
- align-items: center;
-}
-.annotationForm .buttons {
- margin-bottom: 0.5rem;
-}
-.annotationForm .ts {
- color: #fff;
-}
-.annotationForm .select.media_id {
- width: 100%;
- margin-right: 0;
-}
-
-/* Annotation index */
-
-.annotationIndex {
- width: 800px;
-}
-.annotationIndex .annotation {
- position: absolute;
- left: 5px;
- max-width: 400px;
- padding: 0.25rem 0.375rem;
- box-shadow: 0px 0px 3px rgba(0,0,0,1.0);
- border: 1px solid transparent;
- border-radius: 2px;
- font-size: 12px;
- cursor: pointer;
- user-select: none;
- background-color: #768;
-}
-.annotation.selected {
- border-color: #bbf;
- box-shadow: 0px 0px 4px rgba(0,0,0,1.0), 0px 0px 2px rgba(0,0,0,1.0);
- z-index: 1;
- background-image: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.4));
-}
-.annotationIndex .annotation.media {
- left: calc(405px + 0.5rem);
-}
-.annotation.sentence.even {
- background-color: #83b;
-}
-.annotation.sentence.odd {
- background-color: #537;
-}
-.annotation.header {
- background-color: #838;
-}
-.annotation.paragraph_end {
- background-color: #003;
- border-top: 1px solid #888;
- width: 100%;
- padding: 1px;
-}
-
-/* Condensed layout (first lines) */
-
-.annotationIndex.condensed .annotation.sentence {
- z-index: 0;
- white-space: pre;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.annotationIndex.condensed .annotation.header {
- z-index: 1;
-}
-.annotationIndex.condensed .annotation.paragraph_end {
- border-top-color: #888;
-}
-
-/* Collapsed layout (borders) */
-
-.annotationIndex.collapsed .annotation.sentence {
- height: 2px; overflow: hidden; padding: 0; z-index: 0;
-}
-.annotationIndex.collapsed .annotation.sentence.selected {
- z-index: 1;
-}
-.annotationIndex.collapsed .annotation.header {
- z-index: 2;
-}
-.annotationIndex.collapsed .annotation.paragraph_end {
- border-top-color: #333;
-}
diff --git a/animism-align/frontend/views/align/align.reducer.js b/animism-align/frontend/views/align/align.reducer.js
deleted file mode 100644
index fc948e8..0000000
--- a/animism-align/frontend/views/align/align.reducer.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-const initialState = {
- timeline: {
- cursor_ts: -1,
- start_ts: 0,
- zoom: 1,
- duration: 0,
- selected_annotation_id: -1,
- selected_paragraph_id: -1,
- },
- annotation: {},
- selectedAnnotation: {},
- options: {
- }
-}
-
-export default function alignReducer(state = initialState, action) {
- // console.log(action.type, action)
- switch (action.type) {
- case types.peaks.loaded:
- console.log('peaks duration:', action.data.length / 10)
- return state
-
- case types.align.set_display_setting:
- return {
- ...state,
- timeline: {
- ...state.timeline,
- [action.key]: action.value,
- }
- }
-
- case types.align.set_selected_annotation:
- return {
- ...state,
- timeline: {
- ...state.timeline,
- selected_annotation_id: action.data.id,
- },
- selectedAnnotation: action.data,
- }
-
- case types.align.clear_selected_annotation:
- return {
- ...state,
- timeline: {
- ...state.timeline,
- selected_annotation_id: -1,
- },
- selectedAnnotation: {},
- }
-
- case types.align.set_temporary_annotation:
- return {
- ...state,
- annotation: action.data,
- }
-
- case types.align.update_temporary_annotation:
- return {
- ...state,
- annotation: {
- ...state.annotation,
- [action.key]: action.value,
- }
- }
-
- case types.align.update_temporary_annotation_settings:
- return {
- ...state,
- annotation: {
- ...state.annotation,
- settings: {
- ...state.annotation.settings,
- [action.key]: action.value,
- }
- }
- }
-
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/align/align.util.js b/animism-align/frontend/views/align/align.util.js
deleted file mode 100644
index 37d4181..0000000
--- a/animism-align/frontend/views/align/align.util.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import { ZOOM_STEPS } from './constants'
-import { clamp } from '../../util'
-import actions from '../../actions'
-
-import { HEADER_MARGIN, INNER_HEIGHT } from './constants'
-
-export const positionToTime = (y, { start_ts, zoom, duration }) => {
- y -= HEADER_MARGIN
- const secondsPerPixel = ZOOM_STEPS[zoom] * 0.1
- const widthTimeDuration = INNER_HEIGHT * secondsPerPixel
- const timeMin = start_ts
- const timeMax = Math.min(start_ts + widthTimeDuration, duration)
- const timeWidth = timeMax - timeMin
- return clamp(y * secondsPerPixel + start_ts, 0, timeMax)
-}
-
-export const timeToPosition = (ts, { start_ts, zoom, duration }) => {
- const secondsPerPixel = ZOOM_STEPS[zoom] * 0.1
- const widthTimeDuration = INNER_HEIGHT * secondsPerPixel
- const timeMin = start_ts
- const timeMax = Math.min(start_ts + widthTimeDuration, duration)
- const timeWidth = timeMax - timeMin
- const timeHalfHeight = INNER_HEIGHT * secondsPerPixel / 2
- if (ts < timeMin - timeHalfHeight) {
- return -9999
- }
- if (ts > timeMax) {
- return -9999
- }
- return (ts - timeMin) / timeWidth * INNER_HEIGHT
-}
-
-export const getFirstPunctuationMarkIndex = text => {
- const indexes = [
- text.indexOf('. '),
- text.indexOf('? '),
- text.indexOf('! '),
- text.indexOf('." '),
- text.indexOf('?" '),
- text.indexOf('!" '),
- text.indexOf('.” '),
- text.indexOf('?” '),
- text.indexOf('!” '),
- ]
-
- return indexes.reduce((a, b) => {
- if (b < 0) return a
- return Math.min(a, b)
- }, Infinity) + 1
-}
-
-export const cutFirstSentence = text => {
- const textToCrop = text.trim().replace("\n", " ").split("\n")[0]
- let cropIndex = getFirstPunctuationMarkIndex(textToCrop)
- if (!cropIndex) cropIndex = textToCrop.length
- const croppedText = textToCrop.substr(0, cropIndex).trim()
- const updatedText = text.trim().replace(croppedText, '').trim()
- actions.site.updateText(updatedText)
- return croppedText
-}
-
-export const thumbnailURL = data => {
- if (data.type === 'video') return data.settings.video.thumbnail_url
- if (data.type === 'image') return data.settings.thumbnail.url
-}
diff --git a/animism-align/frontend/views/align/components/annotations/annotation.form.js b/animism-align/frontend/views/align/components/annotations/annotation.form.js
deleted file mode 100644
index 01b1663..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotation.form.js
+++ /dev/null
@@ -1,183 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../../actions'
-// import * as alignActions from '../align.actions'
-
-import { ZOOM_STEPS } from '../../constants'
-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', 'image', 'image_carousel',
-].map(name => ({ name, label: capitalize(name.replace('_', ' ')) }))
-
-class AnnotationForm extends Component {
- constructor(props){
- super(props)
- this.handleChange = this.handleChange.bind(this)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleSettingsSelect = this.handleSettingsSelect.bind(this)
- this.handleKeyDown = this.handleKeyDown.bind(this)
- this.handleSubmit = this.handleSubmit.bind(this)
- this.handleDestroy = this.handleDestroy.bind(this)
- this.textareaRef = React.createRef()
- }
- componentDidMount() {
- if (this.textareaRef && this.textareaRef.current) {
- this.textareaRef.current.focus()
- }
- }
- handleKeyDown(e) {
- if (e.keyCode === 27) { // escape
- actions.align.hideAnnotationForm()
- return
- }
- // console.log(e.keyCode)
- if (!e.metaKey && !e.ctrlKey) return
- let { start_ts } = this.props.annotation
- switch (e.keyCode) {
- case 38: // up
- e.preventDefault()
- start_ts -= 0.1
- actions.align.updateAnnotationForm('start_ts', Math.max(0, start_ts))
- actions.audio.seek(start_ts)
- actions.align.setCursor(start_ts)
- break
- case 40: // down
- e.preventDefault()
- start_ts += 0.1
- actions.align.updateAnnotationForm('start_ts', Math.max(0, start_ts))
- actions.audio.seek(start_ts)
- actions.align.setCursor(start_ts)
- break
- case 83: // ctrl-S
- e.preventDefault()
- this.handleSubmit()
- default:
- break
- }
- }
- handleChange(e) {
- const { name, value } = e.target
- this.handleSelect(name, value)
- }
- handleSelect(name, value) {
- actions.align.updateAnnotationForm(name, value)
- }
- handleSettingsSelect(name, value) {
- if (name.indexOf('_id') !== -1) value = parseInt(value) || 0
- actions.align.updateAnnotationSettings(name, value)
- }
- handleSubmit() {
- const { annotation } = this.props
- if (annotation.type === 'paragraph_end') {
- annotation.text = ''
- }
- if (annotation.id === 'new') {
- delete annotation.id
- actions.annotation.create(annotation)
- .then(response => {
- console.log(response)
- actions.align.hideAnnotationForm()
- })
- } else {
- actions.annotation.update(annotation)
- .then(response => {
- console.log(response)
- actions.align.hideAnnotationForm()
- })
- }
- }
- handleDestroy() {
- const { annotation } = this.props
- if (annotation.id === 'new') {
- actions.align.hideAnnotationForm()
- } else {
- actions.annotation.destroy(annotation)
- .then(response => {
- console.log(response)
- actions.align.hideAnnotationForm()
- })
- }
- }
- render() {
- const { timeline, annotation, media } = this.props
- if (!annotation.start_ts) return <div></div>
- return (
- <div
- className='annotationForm'
- style={{
- top: timeToPosition(annotation.start_ts, timeline),
- }}
- >
- {this.renderButtons()}
- {annotation.type === 'sentence' && this.renderTextarea()}
- {annotation.type === 'header' && this.renderTextarea()}
- {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>
- )
- }
- renderButtons() {
- const { annotation } = this.props
- return (
- <div className='row buttons'>
- <div>
- <Select
- name='type'
- selected={annotation.type}
- options={ANNOTATION_TYPES}
- defaultOption='text'
- onChange={this.handleSelect}
- />
- <div className='ts'>{timestamp(annotation.start_ts, 1, true)}</div>
- </div>
- <div>
- {annotation.id !== 'new' && <button onClick={this.handleDestroy}>Delete</button>}
- <button onClick={this.handleSubmit}>Save</button>
- </div>
- </div>
- )
- }
- renderTextarea() {
- const { annotation } = this.props
- return (
- <div>
- <textarea
- name='text'
- value={annotation.text}
- onKeyDown={this.handleKeyDown}
- onChange={this.handleChange}
- ref={this.textareaRef}
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- annotation: state.align.annotation,
- timeline: state.align.timeline,
- media: state.media.index,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(AnnotationForm)
diff --git a/animism-align/frontend/views/align/components/annotations/annotation.index.js b/animism-align/frontend/views/align/components/annotations/annotation.index.js
deleted file mode 100644
index 30dc7c0..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotation.index.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import React, { Component } from 'react'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../../actions'
-
-import { ZOOM_STEPS, INNER_HEIGHT } from '../../constants'
-import { clamp } from '../../../../util'
-import { positionToTime, timeToPosition } from '../../align.util'
-
-import { AnnotationElementLookup } from './annotationTypes'
-
-class AnnotationIndex extends Component {
- state = {
- items: [],
- }
- constructor(props){
- super(props)
- this.handleClick = this.handleClick.bind(this)
- }
- componentDidUpdate(prevProps) {
- if (this.props.index.loading) return
- if (prevProps.timeline !== this.props.timeline || prevProps.index !== this.props.index) {
- this.update()
- }
- }
- update() {
- let { timeline, index } = this.props
- let { start_ts, zoom, duration } = this.props.timeline
- const { order, lookup } = index
-
- let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step
- let widthTimeDuration = INNER_HEIGHT * secondsPerPixel // secs per pixel
-
- let timeMin = start_ts - 50.0
- let timeMax = Math.min(start_ts + widthTimeDuration, duration)
-
- const items = order.filter(id => {
- const { start_ts: ts } = lookup[id]
- return (timeMin < ts && ts < timeMax)
- }).map(id => lookup[id]).reverse()
- this.setState({ items })
- }
- handleClick(e, annotation) {
- e.stopPropagation()
- if (e.shiftKey) {
- e.preventDefault()
- this.handleParagraphSelection(annotation, e.metaKey)
- }
- actions.audio.seek(annotation.start_ts)
- actions.align.setSelectedAnnotation(annotation)
- }
- handleParagraphSelection(annotation, shouldClear) {
- const { selected_paragraph_id } = this.props.timeline
- if (!selected_paragraph_id || selected_paragraph_id === -1 || shouldClear) {
- if (annotation.paragraph_id && !shouldClear) {
- actions.align.setSelectedParagraph(annotation.paragraph_id)
- } else {
- actions.paragraph.create({
- type: 'paragraph',
- start_ts: annotation.start_ts,
- }).then(data => {
- actions.align.setSelectedParagraph(data.res.id)
- annotation.paragraph_id = data.res.id
- actions.annotation.update(annotation)
- })
- }
- } else if (selected_paragraph_id !== annotation.paragraph_id) {
- annotation.paragraph_id = selected_paragraph_id
- actions.annotation.update(annotation)
- }
- }
- handleDoubleClick(e, annotation) {
- e.stopPropagation()
- actions.align.showEditAnnotationForm(annotation)
- }
- render() {
- const { timeline, media, annotationInForm, selectedAnnotation } = this.props
- const { start_ts, zoom, selected_annotation_id } = timeline
- const { items } = this.state
- const className = (zoom < 2)
- ? 'annotationIndex'
- : (zoom < 3)
- ? 'annotationIndex condensed'
- : 'annotationIndex collapsed'
- return (
- <div className={className}>
- {items.map(annotation => {
- if (annotationInForm && annotation.id === annotationInForm.id) {
- return null
- }
- if (annotation.id === selected_annotation_id) {
- annotation = selectedAnnotation
- }
- const { id, type, start_ts } = annotation
- const AnnotationElement = AnnotationElementLookup[type]
- const y = timeToPosition(start_ts, timeline)
- return (
- <AnnotationElement
- key={id}
- y={y}
- selected={annotation.id === selected_annotation_id}
- annotation={annotation}
- media={media}
- onClick={this.handleClick}
- onDoubleClick={this.handleDoubleClick}
- />
- )
- })}
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- timeline: state.align.timeline,
- annotationInForm: state.align.annotation,
- selectedAnnotation: state.align.selectedAnnotation,
- index: state.annotation.index,
- media: state.media.index.lookup,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(AnnotationIndex)
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
deleted file mode 100644
index e2df98b..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.image.js
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index 9302ba4..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationForms/annotationForm.video.js
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index 1411efc..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationForms/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-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
deleted file mode 100644
index c3e0c22..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.image.js
+++ /dev/null
@@ -1,33 +0,0 @@
-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
deleted file mode 100644
index be4674f..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.text.js
+++ /dev/null
@@ -1,49 +0,0 @@
-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
deleted file mode 100644
index 17abebd..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.util.js
+++ /dev/null
@@ -1,28 +0,0 @@
-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
deleted file mode 100644
index dc4f469..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationTypes/annotationTypes.video.js
+++ /dev/null
@@ -1,34 +0,0 @@
-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
deleted file mode 100644
index 560063b..0000000
--- a/animism-align/frontend/views/align/components/annotations/annotationTypes/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-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/align/components/player/playButton.component.js b/animism-align/frontend/views/align/components/player/playButton.component.js
deleted file mode 100644
index 486eaee..0000000
--- a/animism-align/frontend/views/align/components/player/playButton.component.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../../actions'
-// import * as alignActions from '../align.actions'
-
-import { ZOOM_STEPS } from '../../constants'
-import { clamp } from '../../../../util'
-
-const PlayButton = ({ audio }) => {
- return (
- <div
- className={audio.playing ? 'playButton playing' : 'playButton paused'}
- onClick={() => {
- audio.playing ? actions.audio.pause() : actions.audio.play()
- }}
- />
- )
-}
-
-const mapStateToProps = state => ({
- audio: state.audio,
-})
-
-const mapDispatchToProps = dispatch => ({
- // alignActions: bindActionCreators({ ...alignActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(PlayButton)
diff --git a/animism-align/frontend/views/align/components/timeline/cursor.component.js b/animism-align/frontend/views/align/components/timeline/cursor.component.js
deleted file mode 100644
index f621b37..0000000
--- a/animism-align/frontend/views/align/components/timeline/cursor.component.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { Component } from 'react'
-
-import { ZOOM_STEPS } from '../../constants'
-import { timestamp } from '../../../../util'
-
-const Cursor = ({ timeline, annotation }) => {
- const { start_ts, zoom, cursor_ts, duration } = timeline
- const ts = annotation.start_ts || cursor_ts
- const secondsPerPixel = ZOOM_STEPS[zoom] * 0.1
- const y = (ts - start_ts) / secondsPerPixel
- return (
- <div
- className='cursor'
- style={{
- top: y,
- }}
- >
- <div className='line' />
- <div className='tickLabel'>
- {timestamp(ts, 1)}
- </div>
- </div>
- )
-}
-
-export default Cursor \ No newline at end of file
diff --git a/animism-align/frontend/views/align/components/timeline/playCursor.component.js b/animism-align/frontend/views/align/components/timeline/playCursor.component.js
deleted file mode 100644
index e03d212..0000000
--- a/animism-align/frontend/views/align/components/timeline/playCursor.component.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import { ZOOM_STEPS } from '../../constants'
-import { timestamp } from '../../../../util'
-
-const PlayCursor = ({ timeline, audio }) => {
- const { start_ts, zoom, duration } = timeline
- const { play_ts } = audio
- const secondsPerPixel = ZOOM_STEPS[zoom] * 0.1
- const y = (play_ts - start_ts) / secondsPerPixel
- // console.log(play_ts, y)
- return (
- <div
- className='cursor playCursor'
- style={{
- top: y,
- }}
- >
- <div className='line' />
- </div>
- )
-}
-
-const mapStateToProps = state => ({
- timeline: state.align.timeline,
- audio: state.audio,
-})
-
-const mapDispatchToProps = dispatch => ({
- // alignActions: bindActionCreators({ ...alignActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(PlayCursor)
diff --git a/animism-align/frontend/views/align/components/timeline/ticks.component.js b/animism-align/frontend/views/align/components/timeline/ticks.component.js
deleted file mode 100644
index 747fb7a..0000000
--- a/animism-align/frontend/views/align/components/timeline/ticks.component.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import React, { Component } from 'react'
-
-import { ZOOM_STEPS, ZOOM_LABEL_STEPS, ZOOM_TICK_STEPS, INNER_HEIGHT } from '../../constants'
-import { timestamp } from '../../../../util'
-
-export default class Ticks extends Component {
- render() {
- let { start_ts, zoom, duration } = this.props.timeline
-
- let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step
-
- let widthTimeDuration = INNER_HEIGHT * secondsPerPixel // secs per pixel
-
- let timeMin = start_ts
- let timeMax = Math.min(start_ts + widthTimeDuration, duration)
- let timeWidth = timeMax - timeMin
-
- let pixelMin = timeMin / secondsPerPixel
-
- let secondsPerLabel = ZOOM_LABEL_STEPS[zoom] // secs
- let pixelsPerLabel = secondsPerLabel / secondsPerPixel
- let secondsPerTick = ZOOM_TICK_STEPS[zoom]
- let pixelsPerTick = secondsPerTick / secondsPerPixel
-
- let startOffset = pixelsPerLabel - (pixelMin % pixelsPerLabel)
- let startTiming = (pixelMin + startOffset) * secondsPerPixel
-
- let labelCount = Math.ceil(INNER_HEIGHT / pixelsPerLabel) + 1
- let offset, timing, tickLabels = [], ticks = []
- for (var i = -1; i < labelCount; i++) {
- offset = i * pixelsPerLabel + startOffset
- if (offset > INNER_HEIGHT) continue
- timing = i * secondsPerLabel + startTiming
- if (timing > duration) {
- break
- }
- tickLabels.push(
- <div className='tickLabel' key={"tickLabel_" + i}
- style={{
- top: Math.floor(offset)
- }}>
- {timestamp(timing)}
- </div>
- )
- }
-
- let durationOffset = duration / secondsPerPixel - pixelMin
- if (timing > duration) {
- tickLabels.push(
- <div className='tickLabel tickLabelTotal' key={"tickLabel_total"}
- style={{
- top: durationOffset
- }}>
- {timestamp(duration, 1)}
- </div>
- )
- ticks.push(
- <div className='tick' key={"tick_total"}
- style={{
- top: Math.floor(durationOffset),
- }}
- />
- )
- }
- let tickCount = Math.ceil(INNER_HEIGHT / pixelsPerTick) + 6
- for (var i = 0; i < tickCount; i += 1) {
- offset = i * pixelsPerTick + startOffset - pixelsPerLabel
- if (offset > durationOffset) {
- break
- }
- ticks.push(
- <div className='tick' key={"tick_" + i}
- style={{
- top: Math.floor(offset),
- }}
- />
- )
- }
- // console.log(ticks.length)
-
- return (
- <div className='ticks'>
- {ticks}
- {tickLabels}
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/align/components/timeline/waveform.component.js b/animism-align/frontend/views/align/components/timeline/waveform.component.js
deleted file mode 100644
index 16ceaf6..0000000
--- a/animism-align/frontend/views/align/components/timeline/waveform.component.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-// import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../../actions'
-// import * as uploadActions from './upload.actions'
-
-import { WAVEFORM_SIZE, ZOOM_STEPS, ZOOM_LABEL_STEPS, ZOOM_TICK_STEPS, INNER_HEIGHT } from '../../constants'
-
-class Waveform extends Component {
- constructor(props){
- super(props)
- this.canvasRef = React.createRef()
- }
- componentDidMount() {
- this.resize()
- this.draw()
- }
- componentDidUpdate() {
- this.draw()
- }
- resize() {
- const canvas = this.canvasRef.current
- canvas.width = WAVEFORM_SIZE
- canvas.height = INNER_HEIGHT
- }
- draw() {
- const canvas = this.canvasRef.current
- const ctx = canvas.getContext('2d')
- const h = INNER_HEIGHT
- this.clearCanvas(ctx, h)
- this.drawCurve(ctx, h)
- }
- clearCanvas(ctx, h) {
- const w = WAVEFORM_SIZE
- ctx.clearRect(0, 0, w, h)
- ctx.fillStyle = 'rgba(0,0,0,0.5)'
- ctx.fillRect(0, 0, w, h)
- ctx.fillStyle = 'rgba(64,128,192,0.5)'
- }
- drawCurve(ctx, h) {
- let { peaks, timeline } = this.props
- let { start_ts, zoom, duration } = timeline
-
- let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step
- let stepsPerPixel = ZOOM_STEPS[zoom] // 0.1 sec / step
-
- let widthTimeDuration = h * secondsPerPixel // secs per pixel
-
- let timeMin = Math.round(start_ts / secondsPerPixel) * secondsPerPixel
- let timeMax = Math.min(timeMin + widthTimeDuration, duration)
- let timeWidth = timeMax - timeMin
-
- let stepMin = Math.floor(timeMin * 10)
- let pixelWidth = Math.ceil(timeWidth / secondsPerPixel)
-
- let i = 0
- let step = stepMin
- let waveformPeak = WAVEFORM_SIZE / 2
- let origin = (1 - peaks[step]) * waveformPeak
- let y
- let peak
- // console.log(stepMin, pixelWidth * stepsPerPixel + stepMin)
- ctx.beginPath()
- ctx.moveTo(origin, 0)
- for (i = 0; i < pixelWidth; i++) {
- step = i * stepsPerPixel + stepMin
- peak = peaks[step]
- y = (1 - peak) * waveformPeak
- ctx.lineTo(y, i)
- }
- for (i = pixelWidth - 1; i > 0; i--) {
- step = i * stepsPerPixel + stepMin
- peak = peaks[step]
- y = (1 + peak) * waveformPeak
- ctx.lineTo(y, i)
- }
- ctx.lineTo(origin, 0)
- ctx.fillStyle = 'rgba(255,255,255,0.8)'
- ctx.fill()
- }
- render() {
- return (
- <canvas ref={this.canvasRef} onClick={this.props.onClick} />
- )
- }
-}
-
-const mapStateToProps = state => ({
- timeline: state.align.timeline,
- peaks: state.site.peaks,
-})
-
-const mapDispatchToProps = dispatch => ({
- // uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Waveform)
diff --git a/animism-align/frontend/views/align/constants.js b/animism-align/frontend/views/align/constants.js
deleted file mode 100644
index cf504d3..0000000
--- a/animism-align/frontend/views/align/constants.js
+++ /dev/null
@@ -1,34 +0,0 @@
-export const WAVEFORM_SIZE = 300
-
-export const ZOOM_STEPS = [
- 1,
- 2,
- 3,
- 10,
- 20,
- 30,
- 60,
-]
-
-export const ZOOM_LABEL_STEPS = [
- 20,
- 60,
- 60,
- 300,
- 600,
- 600,
- 1200,
-]
-
-export const ZOOM_TICK_STEPS = [
- 5,
- 10,
- 30,
- 60,
- 60,
- 60,
- 600,
-]
-
-export const HEADER_MARGIN = 50
-export const INNER_HEIGHT = window.innerHeight - HEADER_MARGIN
diff --git a/animism-align/frontend/views/align/containers/annotations.container.js b/animism-align/frontend/views/align/containers/annotations.container.js
deleted file mode 100644
index b6cdace..0000000
--- a/animism-align/frontend/views/align/containers/annotations.container.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-// import * as alignActions from '../align.actions'
-
-import { ZOOM_STEPS } from '../constants'
-import { clamp } from '../../../util'
-import { positionToTime } from '../align.util'
-
-import AnnotationForm from '../components/annotations/annotation.form'
-import AnnotationIndex from '../components/annotations/annotation.index'
-
-class Annotations extends Component {
- constructor(props){
- super(props)
- }
- render() {
- return (
- <div className='annotations'>
- <AnnotationIndex />
- {this.props.annotation.start_ts &&
- <AnnotationForm />
- }
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- timeline: state.align.timeline,
- annotation: state.align.annotation,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Annotations)
diff --git a/animism-align/frontend/views/align/containers/script.container.js b/animism-align/frontend/views/align/containers/script.container.js
deleted file mode 100644
index ce3dee8..0000000
--- a/animism-align/frontend/views/align/containers/script.container.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-// import * as alignActions from '../align.actions'
-
-class Timeline extends Component {
- constructor(props){
- super(props)
- }
- render() {
- if (this.props.text.loading) return <div />
- return (
- <textarea
- className='script'
- onChange={e => actions.site.updateText(e.target.value)}
- value={this.props.text}
- />
- )
- }
-}
-
-
-const mapStateToProps = state => ({
- text: state.site.text,
-})
-
-const mapDispatchToProps = dispatch => ({
- // alignActions: bindActionCreators({ ...alignActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Timeline)
diff --git a/animism-align/frontend/views/align/containers/timeline.container.js b/animism-align/frontend/views/align/containers/timeline.container.js
deleted file mode 100644
index a924eaf..0000000
--- a/animism-align/frontend/views/align/containers/timeline.container.js
+++ /dev/null
@@ -1,171 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-// import * as alignActions from '../align.actions'
-
-import Annotations from '../containers/annotations.container'
-import Waveform from '../components/timeline/waveform.component'
-import Ticks from '../components/timeline/ticks.component'
-import Cursor from '../components/timeline/cursor.component'
-import PlayButton from '../components/player/playButton.component'
-import PlayCursor from '../components/timeline/playCursor.component'
-
-import { WAVEFORM_SIZE, ZOOM_STEPS, INNER_HEIGHT } from '../constants'
-import { clamp } from '../../../util'
-import { positionToTime } from '../align.util'
-
-class Timeline extends Component {
- constructor(props){
- super(props)
- this.handleKeydown = this.handleKeydown.bind(this)
- this.handleMouseMove = this.handleMouseMove.bind(this)
- this.handleWheel = this.handleWheel.bind(this)
- this.handleContainerClick = this.handleContainerClick.bind(this)
- this.handleTimelineClick = this.handleTimelineClick.bind(this)
- }
- componentDidMount() {
- this.bind()
- }
- componentWillUnmount() {
- this.unbind()
- }
- shouldComponentUpdate(nextProps) {
- return (
- nextProps.timeline !== this.props.timeline ||
- nextProps.annotation !== this.props.annotation
- )
- }
- bind() {
- document.addEventListener('keydown', this.handleKeydown)
- }
- unbind() {
- document.removeEventListener('keydown', this.handleKeydown)
- }
- handleKeydown(e) {
- if (document.activeElement !== document.body) {
- return
- }
- // console.log(e.keyCode)
- if (e.metaKey && this.props.selectedAnnotation.id) {
- const { selectedAnnotation } = this.props
- switch (e.keyCode) {
- case 38: // up
- e.preventDefault()
- selectedAnnotation.start_ts = Math.max(selectedAnnotation.start_ts - (e.shiftKey ? 1 : 0.1), 0)
- actions.align.updateSelectedAnnotation(selectedAnnotation)
- actions.audio.seek(selectedAnnotation.start_ts)
- actions.align.setCursor(selectedAnnotation.start_ts)
- break
- case 40: // down
- e.preventDefault()
- selectedAnnotation.start_ts += e.shiftKey ? 1 : 0.1
- actions.align.updateSelectedAnnotation(selectedAnnotation)
- actions.audio.seek(selectedAnnotation.start_ts)
- actions.align.setCursor(selectedAnnotation.start_ts)
- break
- }
- return
- }
- if (e.shiftKey) {
- switch (e.keyCode) {
- case 187: // plus
- actions.align.setZoom(this.props.timeline.zoom - 1)
- break
- case 189: // minus
- actions.align.setZoom(this.props.timeline.zoom + 1)
- break
- }
- } else {
- // console.log(e.keyCode)
- switch (e.keyCode) {
- case 27: // escape
- actions.align.hideAnnotationForm()
- break
- case 65: // A - add
- e.preventDefault()
- actions.align.showNewAnnotationForm(this.props.audio.play_ts, this.props.text)
- break
- case 32: // spacebar
- actions.audio.toggle()
- break
- case 38: // up
- actions.audio.jump(- ZOOM_STEPS[this.props.timeline.zoom] * 0.1)
- break
- case 40: // down
- actions.audio.jump(ZOOM_STEPS[this.props.timeline.zoom] * 0.1)
- break
- }
- }
- }
- handleWheel(e) {
- let { start_ts, zoom, duration } = this.props.timeline
- let { deltaY } = e
- let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step
- let widthTimeDuration = INNER_HEIGHT * secondsPerPixel // secs per pixel
- start_ts += Math.round((deltaY) * ZOOM_STEPS[zoom])
- start_ts = clamp(start_ts, 0, Math.max(0, duration - widthTimeDuration / 2))
- if (e.shiftKey) {
- if (Math.abs(deltaY) < 2) return
- if (e.deltaY > 0) {
- actions.align.throttledSetZoom(this.props.timeline.zoom + 1)
- } else {
- actions.align.throttledSetZoom(this.props.timeline.zoom - 1)
- }
- } else if (e.altKey) {
- actions.audio.jump(e.deltaY * ZOOM_STEPS[zoom])
- } else {
- actions.align.setScrollPosition(start_ts)
- }
- }
- handleMouseMove(e) {
- const cursor_ts = positionToTime(e.pageY, this.props.timeline)
- actions.align.setCursor(cursor_ts)
- }
- handleContainerClick(e) {
- actions.align.clearSelectedAnnotation()
- actions.align.clearSelectedParagraph()
- }
- handleTimelineClick(e) {
- const play_ts = positionToTime(e.pageY, this.props.timeline)
- if (e.pageX < WAVEFORM_SIZE * 0.67) {
- actions.audio.seek(play_ts)
- } else {
- actions.align.showNewAnnotationForm(play_ts, this.props.text)
- }
- }
- render() {
- return (
- <div
- className='timeline'
- onClick={this.handleContainerClick}
- onWheel={this.handleWheel}
- onMouseMove={this.handleMouseMove}
- >
- <div className='timelineColumn'>
- <Waveform onClick={this.handleTimelineClick} />
- <Ticks timeline={this.props.timeline} />
- <Cursor timeline={this.props.timeline} annotation={this.props.annotation} />
- </div>
- <Annotations timeline={this.props.timeline} />
- <PlayCursor />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- timeline: state.align.timeline,
- annotation: state.align.annotation,
- selectedAnnotation: state.align.selectedAnnotation,
- audio: state.audio,
- text: state.site.text,
-})
-
-const mapDispatchToProps = dispatch => ({
- // alignActions: bindActionCreators({ ...alignActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Timeline)
diff --git a/animism-align/frontend/views/annotation/annotation.reducer.js b/animism-align/frontend/views/annotation/annotation.reducer.js
deleted file mode 100644
index 98b785e..0000000
--- a/animism-align/frontend/views/annotation/annotation.reducer.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-import { crudState, crudReducer } from '../../api/crud.reducer'
-
-const initialState = crudState('annotation', {
- options: {
- sort: 'start_ts asc',
- }
-})
-
-const reducer = crudReducer('annotation')
-
-export default function annotationReducer(state = initialState, action) {
- // console.log(action.type, action)
- state = reducer(state, action)
- switch (action.type) {
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/audio/audio.actions.js b/animism-align/frontend/views/audio/audio.actions.js
deleted file mode 100644
index 64c8215..0000000
--- a/animism-align/frontend/views/audio/audio.actions.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import * as types from '../../types'
-import { store, history, dispatch } from '../../store'
-import actions from '../../actions'
-import { session } from '../../session'
-
-const audioPlayer = document.createElement('audio')
-audioPlayer.src = '/static/data_store/peaks/animismA080720.mp3'
-audioPlayer.addEventListener('loadedmetadata', () => {
- console.log('audio duration:', audioPlayer.duration)
- dispatch({ type: types.align.set_display_setting, key: 'duration', value: audioPlayer.duration })
-})
-audioPlayer.addEventListener('play', () => {
- dispatch({ type: types.audio.play })
-})
-audioPlayer.addEventListener('pause', () => {
- dispatch({ type: types.audio.pause })
-})
-audioPlayer.addEventListener('timeupdate', () => {
- dispatch({ type: types.audio.update_time, play_ts: audioPlayer.currentTime })
-})
-
-export const play = () => dispatch => {
- audioPlayer.play()
-}
-export const pause = () => dispatch => {
- audioPlayer.pause()
-}
-export const seek = play_ts => dispatch => {
- audioPlayer.currentTime = play_ts
-}
-export const jump = delta_ts => dispatch => {
- audioPlayer.currentTime += delta_ts
-}
-export const toggle = () => dispatch => {
- if (store.getState().audio.playing) {
- pause()(dispatch)
- } else {
- play()(dispatch)
- }
-}
diff --git a/animism-align/frontend/views/audio/audio.reducer.js b/animism-align/frontend/views/audio/audio.reducer.js
deleted file mode 100644
index e37933d..0000000
--- a/animism-align/frontend/views/audio/audio.reducer.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-const initialState = {
- playing: false,
- play_ts: 0,
-}
-
-export default function alignReducer(state = initialState, action) {
- // console.log(action.type, action)
- switch (action.type) {
- case types.audio.play:
- return {
- ...state,
- playing: true,
- }
- case types.audio.pause:
- return {
- ...state,
- playing: false,
- }
- case types.audio.update_time:
- return {
- ...state,
- play_ts: action.play_ts,
- }
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/index.js b/animism-align/frontend/views/index.js
deleted file mode 100644
index 2c9ee78..0000000
--- a/animism-align/frontend/views/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export { default as align } from './align/align.container'
-export { default as paragraph } from './paragraph/paragraph.container'
-export { default as upload } from './upload/upload.container'
-export { default as media } from './media/media.container'
diff --git a/animism-align/frontend/views/media/components/media.form.js b/animism-align/frontend/views/media/components/media.form.js
deleted file mode 100644
index 1463041..0000000
--- a/animism-align/frontend/views/media/components/media.form.js
+++ /dev/null
@@ -1,272 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-
-import { session } from '../../../session'
-import { capitalize } from '../../../util'
-
-import { TextInput, LabelDescription, Select, TextArea, Checkbox, SubmitButton, Loader } from '../../../common'
-
-import MediaImageForm from './media.formImage'
-import MediaVideoForm from './media.formVideo'
-
-const newMedia = () => ({
- type: 'image',
- tag: 'media',
- url: '',
- title: '',
- author: '',
- pre_title: '',
- post_title: '',
- translated_title: '',
- date: '',
- source: '',
- medium: '',
- start_ts: 0,
- settings: {},
-})
-
-const MEDIA_TYPES = [
- 'image', 'video'
-].map(name => ({ name, label: capitalize(name) }))
-
-export default class MediaForm extends Component {
- state = {
- title: "",
- submitTitle: "",
- data: { ...newMedia() },
- errorFields: new Set([]),
- }
-
- constructor(props) {
- super(props)
- this.handleKeyDown = this.handleKeyDown.bind(this)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleChange = this.handleChange.bind(this)
- this.handleSettingsChange = this.handleSettingsChange.bind(this)
- this.handleSettingsChangeEvent = this.handleSettingsChangeEvent.bind(this)
- this.handleSubmit = this.handleSubmit.bind(this)
- }
-
- componentDidMount() {
- const { data, isNew } = this.props
- const title = isNew ? 'New media' : 'Editing ' + data.title
- const submitTitle = isNew ? "Add Media" : "Save Changes"
- this.setState({
- title,
- submitTitle,
- errorFields: new Set([]),
- data: {
- ...newMedia(),
- ...data
- },
- })
- window.addEventListener('keydown', this.handleKeyDown)
- }
-
- componentWillUnmount() {
- window.removeEventListener('keydown', this.handleKeyDown)
- }
-
- handleKeyDown(e) {
- // console.log(e, e.keyCode)
- if ((e.ctrlKey || e.metaKey) && e.keyCode === 83) {
- if (e) {
- e.preventDefault()
- }
- this.handleSubmit()
- }
- }
-
- handleChange(e) {
- const { name, value } = e.target
- this.handleSelect(name, value)
- }
-
- handleSelect(name, value) {
- const { errorFields } = this.state
- if (errorFields.has(name)) {
- errorFields.delete(name)
- }
- this.setState({
- errorFields,
- data: {
- ...this.state.data,
- [name]: value,
- }
- })
- }
-
- handleSettingsChangeEvent(e) {
- const { name, value } = e.target
- this.handleSettingsChange(name, value)
- }
-
- handleSettingsChange(name, value) {
- console.log(name, value)
- if (name !== 'multiple') {
- value = { [name]: value }
- }
- this.setState({
- data: {
- ...this.state.data,
- settings: {
- ...this.state.data.settings,
- ...value,
- }
- }
- })
- }
-
- handleSubmit(e) {
- if (e) {
- e.preventDefault()
- }
- const { isNew, onSubmit } = this.props
- const { data } = this.state
- const requiredKeys = "author title date".split(" ")
- const validKeys = "type tag url title author pre_title post_title translated_title date source medium start_ts settings".split(" ")
- const validData = validKeys.reduce((a,b) => { a[b] = data[b]; return a }, {})
- const errorFields = requiredKeys.filter(key => !validData[key])
- if (errorFields.length) {
- console.log('error', errorFields, validData)
- this.setState({ errorFields: new Set(errorFields) })
- } else {
- if (isNew) {
- // side effect: set username if we're creating a new media
- // session.set('username', data.username)
- } else {
- validData.id = data.id
- }
- console.log('submit', validData)
- onSubmit(validData)
- }
- }
-
- render() {
- const { isNew } = this.props
- const { title, submitTitle, errorFields, data } = this.state
- // console.log(data)
- return (
- <div className='form'>
- <h1>{title}</h1>
- <form onSubmit={this.handleSubmit}>
- <Select
- title='Media Type'
- name='type'
- selected={data.type}
- options={MEDIA_TYPES}
- onChange={this.handleSelect}
- />
-
- {data.type === 'image' &&
- <MediaImageForm
- data={data}
- onChange={this.handleSelect}
- onSettingsChange={this.handleSettingsChange}
- />
- }
-
- {data.type === 'video' &&
- <MediaVideoForm
- data={data}
- onChange={this.handleSelect}
- onSettingsChange={this.handleSettingsChange}
- />
- }
-
- <TextInput
- title="Author"
- name="author"
- required
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Title"
- name="title"
- required
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Title Prefix"
- name="pre_title"
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Title Suffix"
- name="post_title"
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Translated Title"
- name="translated_title"
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Date"
- name="date"
- required
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextInput
- title="Medium"
- name="medium"
- required
- data={data}
- onChange={this.handleChange}
- />
- <TextInput
- title="Source"
- name="source"
- placeholder="Courtesy of / Copyright"
- required
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
- <TextArea
- title="Citation"
- name="bibliography"
- placeholder="Use if special HTML formatting needed"
- data={data.settings}
- onChange={this.handleSettingsChangeEvent}
- />
- <Checkbox
- label="Hide in list of works"
- name="hide_in_bibliography"
- checked={data.settings.hide_in_bibliography}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <TextArea
- title="Description"
- name="description"
- data={data}
- onChange={this.handleChange}
- />
- <SubmitButton
- title={submitTitle}
- onClick={this.handleSubmit}
- />
- {!!errorFields.size &&
- <label>
- <span></span>
- <span>Please complete the required fields</span>
- </label>
- }
- </form>
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/media/components/media.formImage.js b/animism-align/frontend/views/media/components/media.formImage.js
deleted file mode 100644
index 4a97112..0000000
--- a/animism-align/frontend/views/media/components/media.formImage.js
+++ /dev/null
@@ -1,172 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-
-import { session } from '../../../session'
-import actions from '../../../actions'
-import { capitalize, preloadImage, cropImage } from '../../../util'
-
-import { TextInput, LabelDescription, UploadImage, Select, TextArea, Checkbox, SubmitButton, Loader } from '../../../common'
-import { renderThumbnail } from '../../../common/upload.helpers'
-
-import ImageSelection from './media.formImageSelection'
-
-const DISPLAY_SIZE = 1024
-const DISPLAY_QUALITY= 80
-const THUMBNAIL_SIZE = 320
-const THUMBNAIL_QUALITY = 80
-
-export default class MediaImageForm extends Component {
- state = {
- img: null,
- }
-
- constructor(props) {
- super(props)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleChange = this.handleChange.bind(this)
- this.handleSettingsChange = this.handleSettingsChange.bind(this)
- this.handleUpload = this.handleUpload.bind(this)
- this.handleCrop = this.handleCrop.bind(this)
- this.replaceTaggedSize = this.replaceTaggedSize.bind(this)
- this.uploadTaggedSize = this.uploadTaggedSize.bind(this)
- }
-
- componentDidMount() {
- // this.setState({ })
- if (this.props.data.settings.fullsize) {
- preloadImage(this.props.data.settings.fullsize.url)
- .then(img => this.setState({ img }))
- }
- }
-
- handleChange(e) {
- const { name, value } = e.target
- this.handleSelect(name, value)
- }
-
- handleSelect(name, value) {
- this.props.onSelect(name, value)
- }
-
- handleSettingsChange(name, value) {
- this.props.onSettingsChange(name, value)
- }
-
- handleUpload({ file, img, canvas, blob }) {
- // sizes: fullsize, display, thumbnail
- this.replaceTaggedSize(file, 'fullsize')
- .then(data => {
- this.setState({ img })
- this.props.onSettingsChange('multiple', {
- fullsize: data,
- crop: {},
- })
- return this.replaceTaggedSize(blob, 'display', file.name)
- }).then(data => {
- this.props.onSettingsChange('multiple', {
- display: data,
- })
- this.uploadThumbnail(img)
- })
- }
-
- uploadThumbnail(img) {
- const { fn } = this.props.data.settings.fullsize
- const thumbnailCanvas = renderThumbnail(img, { maxSide: THUMBNAIL_SIZE })
- thumbnailCanvas.toBlob(thumbnail => {
- this.replaceTaggedSize(thumbnail, 'thumbnail', fn).then(data => {
- this.props.onSettingsChange('multiple', {
- thumbnail: data,
- })
- })
- }, 'image/jpeg', THUMBNAIL_QUALITY)
- }
-
- replaceTaggedSize(image, tag, fn) {
- // when we upload an image, if the image already exists in this "position"
- // on the record, we should also delete it
- if (this.props.data.settings[tag] && this.props.data.settings[tag].id) {
- return new Promise((resolve, reject) => {
- actions.upload.destroy(this.props.data.settings[tag])
- .then(() => {
- console.log('destroy successful')
- this.uploadTaggedSize(image, tag, fn).then(data => resolve(data))
- })
- .catch(() => {
- console.log('error deleting the image')
- this.uploadTaggedSize(image, tag, fn).then(data => resolve(data))
- })
- })
- }
- return this.uploadTaggedSize(image, tag, fn)
- }
-
- uploadTaggedSize(image, tag, fn) {
- console.log('uploading size', tag)
- const uploadData = {
- image,
- tag,
- username: 'animism',
- }
- if (fn) {
- uploadData['__image_filename'] = fn
- }
- // console.log(uploadData)
- return actions.upload.upload(uploadData).then(data => {
- // console.log(data)
- return data.res
- })
- }
-
- handleCrop(crop) {
- // when cropping an image, re-upload the display image and thumbnail
- // console.log(crop)
- cropImage(this.state.img, crop, DISPLAY_SIZE)
- .then(canvas => {
- canvas.toBlob(blob => {
- // console.log(canvas, canvas.width, canvas.height, blob)
- this.replaceTaggedSize(blob, 'display', this.props.data.settings.fullsize.fn)
- .then(data => {
- this.props.onSettingsChange('multiple', {
- crop,
- display: data,
- })
- this.uploadThumbnail(canvas)
- })
- }, 'image/jpeg', DISPLAY_QUALITY)
- })
- }
-
- render() {
- const { data } = this.props
- // console.log(data)
- return (
- <div className='imageForm'>
- {!data.url &&
- <label className={'text fileInput'}>
- <span>{"Upload image"}</span>
- <div className="row">
- <button>
- {"Choose image"}
- </button>
- <UploadImage
- onUpload={this.handleUpload}
- maxSide={DISPLAY_SIZE}
- quality={DISPLAY_QUALITY}
- />
- </div>
- </label>
- }
- {data.settings.fullsize &&
- <div>
- <ImageSelection
- url={data.settings.fullsize.url}
- crop={data.settings.crop}
- onCrop={this.handleCrop}
- />
- </div>
- }
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/media/components/media.formImageSelection.js b/animism-align/frontend/views/media/components/media.formImageSelection.js
deleted file mode 100644
index 5572793..0000000
--- a/animism-align/frontend/views/media/components/media.formImageSelection.js
+++ /dev/null
@@ -1,213 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-import toBlob from 'data-uri-to-blob'
-
-import { clamp } from '../../../util'
-import { Loader } from '../../../common'
-
-const defaultState = {
- dragging: false,
- draggingBox: false,
- bounds: null,
- mouseX: 0,
- mouseY: 0,
- box: {
- x: 0,
- y: 0,
- w: 0,
- h: 0,
- }
-}
-
-export default class ImageSelection extends Component {
- state = {
- ...defaultState
- }
-
- constructor() {
- super()
- // bind these events in the constructor, so we can remove event listeners later
- this.handleMouseDown = this.handleMouseDown.bind(this)
- this.handleMouseDownOnBox = this.handleMouseDownOnBox.bind(this)
- this.handleMouseMove = this.handleMouseMove.bind(this)
- this.handleMouseUp = this.handleMouseUp.bind(this)
- this.handleWindowResize = this.handleWindowResize.bind(this)
- }
-
- componentDidMount() {
- document.body.addEventListener('mousemove', this.handleMouseMove)
- document.body.addEventListener('mouseup', this.handleMouseUp)
- window.addEventListener('resize', this.handleWindowResize)
- }
-
- componentDidUpdate(prevProps) {
- if (this.state.bounds && this.props.url !== prevProps.url) {
- this.setState({
- ...defaultState,
- bounds: this.getBoundingClientRect(),
- box: this.props.crop || defaultState.box,
- })
- }
- }
-
- componentWillUnmount() {
- document.body.removeEventListener('mousemove', this.handleMouseMove)
- document.body.removeEventListener('mouseup', this.handleMouseUp)
- window.removeEventListener('resize', this.handleWindowResize)
- }
-
- getBoundingClientRect() {
- if (!this.imgRef) return null
- const rect = this.imgRef.getBoundingClientRect()
- const scrollTop = document.body.scrollTop || document.body.parentNode.scrollTop
- const scrollLeft = document.body.scrollLeft || document.body.parentNode.scrollLeft
- const bounds = {
- top: rect.top + scrollTop,
- left: rect.left + scrollLeft,
- width: rect.width,
- height: rect.height,
- }
- return bounds
- }
-
- handleLoad() {
- const bounds = this.getBoundingClientRect()
- const box = this.props.crop || defaultState.box
- this.setState({ bounds, box })
- }
-
- handleWindowResize() {
- if (!this.imgRef) return
- const bounds = this.getBoundingClientRect()
- this.setState({ bounds })
- }
-
- handleMouseDown(e) {
- e.preventDefault()
- const bounds = this.getBoundingClientRect()
- const mouseX = e.pageX
- const mouseY = e.pageY
- const x = (mouseX - bounds.left) / bounds.width
- const y = (mouseY - bounds.top) / bounds.height
- const w = 1 / bounds.width
- const h = 1 / bounds.height
- this.setState({
- dragging: true,
- bounds,
- mouseX,
- mouseY,
- box: {
- x, y, w, h,
- }
- })
- }
-
- handleMouseDownOnBox(e) {
- const bounds = this.getBoundingClientRect()
- const mouseX = e.pageX
- const mouseY = e.pageY
- this.setState({
- draggingBox: true,
- bounds,
- mouseX,
- mouseY,
- initialBox: {
- ...this.state.box
- },
- box: {
- ...this.state.box
- }
- })
- }
-
- handleMouseMove(e) {
- const {
- dragging, draggingBox,
- bounds, mouseX, mouseY, initialBox, box
- } = this.state
- if (dragging) {
- e.preventDefault()
- let { x, y } = box
- let dx = (e.pageX - mouseX) / bounds.width
- let dy = (e.pageY - mouseY) / bounds.height
- let w = clamp(dx, 0.0, 1.0 - x)
- let h = clamp(dy, 0.0, 1.0 - y)
- this.setState({
- box: {
- x, y, w, h,
- }
- })
- } else if (draggingBox) {
- e.preventDefault()
- let { x, y, w, h } = initialBox
- let dx = (e.pageX - mouseX) / bounds.width
- let dy = (e.pageY - mouseY) / bounds.height
- this.setState({
- box: {
- x: clamp(x + dx, 0, 1.0 - w),
- y: clamp(y + dy, 0, 1.0 - h),
- w,
- h,
- }
- })
- }
- }
-
- handleMouseUp(e) {
- const { onCrop } = this.props
- const { dragging, draggingBox, bounds, box } = this.state
- if (!dragging && !draggingBox) return
- e.preventDefault()
- const { x, y, w, h } = box
- let url = window.location.pathname
- this.setState({
- dragging: false,
- draggingBox: false,
- })
- if (w < 10 / bounds.width || h < 10 / bounds.height) {
- this.setState({ box: { ...defaultState.box }})
- onCrop({})
- } else {
- // pass the box dimensions up - do the search again
- onCrop(box)
- }
- }
-
- render() {
- const { url } = this.props
- const { bounds, box } = this.state
- const { x, y, w, h } = box
- return (
- <div className="imageSelection">
- <img
- src={url}
- ref={ref => this.imgRef = ref}
- onMouseDown={this.handleMouseDown}
- onLoad={this.handleLoad.bind(this)}
- crossOrigin='anonymous'
- />
- {!!w &&
- <div
- className="box"
- style={{
- left: x * bounds.width,
- top: y * bounds.height,
- width: w * bounds.width,
- height: h * bounds.height,
- }}
- onMouseDown={this.handleMouseDownOnBox}
- />
- }
- </div>
- )
- }
-}
-
-const boxToFixed = ({ x, y, w, h }) => ({
- x: x.toFixed(3),
- y: y.toFixed(3),
- w: w.toFixed(3),
- h: h.toFixed(3),
-})
diff --git a/animism-align/frontend/views/media/components/media.formVideo.js b/animism-align/frontend/views/media/components/media.formVideo.js
deleted file mode 100644
index 89954b9..0000000
--- a/animism-align/frontend/views/media/components/media.formVideo.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import VimeoPlayer from '@u-wave/react-vimeo'
-
-import { capitalize } from '../../../util'
-import { TextInput, LabelDescription, Select, TextArea, Checkbox, SubmitButton, Loader } from '../../../common'
-
-import { getVimeoMetadata } from '../media.actions'
-
-export default class MediaVideoForm extends Component {
- state = {
- }
-
- constructor(props) {
- super(props)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleChange = this.handleChange.bind(this)
- this.handleSettingsChange = this.handleSettingsChange.bind(this)
- }
-
- handleChange(e) {
- let { name, value } = e.target
- return this.handleSelect(name, value)
- }
-
- handleSelect(name, value) {
- value = value.trim()
- if (name === 'url') {
- getVimeoMetadata(value)
- .then(data => {
- console.log('video metadata', data)
- this.props.onChange(name, value)
- setTimeout(() => {
- this.props.onSettingsChange('video', {
- thumbnail_url: data.thumbnail_url,
- duration: data.duration,
- video_id: data.video_id,
- })
- }, 20)
- })
- } else {
- this.props.onChange(name, value)
- }
- }
-
- handleSettingsChange(e) {
- let { name, value } = e.target
- this.props.onSettingsChange(name, value)
- }
-
- handleSettingsSelect(name, value) {
- this.props.onSettingsChange(name, value)
- }
-
- render() {
- const { data } = this.props
- return (
- <div className='videoForm'>
- <TextInput
- title="Video URL"
- name="url"
- required
- data={data}
- onChange={this.handleChange}
- autoComplete="off"
- />
-
- {data.url &&
- <div>
- <LabelDescription className='video'>
- <VimeoPlayer video={data.url} />
- </LabelDescription>
-
- {data.settings.video && data.settings.video.thumbnail &&
- <LabelDescription className='thumbnail'>
- <img src={data.settings.video.thumbnail} />
- </LabelDescription>
- }
-
- <TextInput
- title="Start time"
- name="video_start_time"
- data={data.settings}
- placeholder="0:00"
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
-
- <TextInput
- title="End time"
- name="video_end_time"
- data={data.settings}
- placeholder="0:00"
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
-
- <TextInput
- title="Original duration"
- name="original_duration"
- data={data.settings}
- placeholder="0:00"
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- </div>
- }
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/media/components/media.indexOptions.js b/animism-align/frontend/views/media/components/media.indexOptions.js
deleted file mode 100644
index 5dbc415..0000000
--- a/animism-align/frontend/views/media/components/media.indexOptions.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-
-import { Select, Checkbox } from '../../../common'
-
-const thumbnailOptions = [
- { name: 'th', label: 'Thumbnails', },
- { name: 'sm', label: 'Small', },
- { name: 'md', label: 'Medium', },
- { name: 'lg', label: 'Large', },
- { name: 'orig', label: 'Original', },
-]
-
-const sortOptions = [
- { name: 'id-asc', label: 'Most recent' },
- { name: 'id-desc', label: 'Oldest first' },
- { name: 'username-asc', label: 'Username (A-Z)' },
- { name: 'username-desc', label: 'Username (Z-A)' },
- { name: 'author-asc', label: 'Author (A-Z)' },
- { name: 'author-desc', label: 'Author (Z-A)' },
- { name: 'title-asc', label: 'Title (A-Z)' },
- { name: 'title-desc', label: 'Title (Z-A)' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
-]
-
-class IndexOptions extends Component {
- render() {
- const { options } = this.props
- return (
- <div className='row menubar'>
- <div />
- <Select
- name={'sort'}
- options={sortOptions}
- selected={options.sort}
- onChange={actions.upload.updateOption}
- />
- <Select
- name={'thumbnailSize'}
- options={thumbnailOptions}
- selected={options.thumbnailSize}
- onChange={actions.upload.updateOption}
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- options: state.upload.options,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(IndexOptions)
diff --git a/animism-align/frontend/views/media/components/media.menu.js b/animism-align/frontend/views/media/components/media.menu.js
deleted file mode 100644
index 153a5c1..0000000
--- a/animism-align/frontend/views/media/components/media.menu.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React, { Component } from 'react'
-import { Route, Link } from 'react-router-dom'
-import { connect } from 'react-redux'
-
-import { history } from '../../../store'
-import actions from '../../../actions'
-import { MenuButton, FileInput } from '../../../common'
-
-const mapStateToProps = state => ({
- media: state.media,
-})
-
-export default class MediaMenu extends Component {
- render() {
- return (
- <div className='menuButtons'>
- <Route exact path='/media/:id/show/' component={MediaShowMenu} />
- <Route exact path='/media/:id/edit/' component={MediaEditMenu} />
- <Route exact path='/media/new/' component={MediaNewMenu} />
- <Route exact path='/media/' component={MediaIndexMenu} />
- </div>
- )
- }
-}
-
-const MediaIndexMenu = () => ([
- <MenuButton key='new' name="new" href="/media/new/" />,
-])
-
-const MediaShowMenu = connect(mapStateToProps)((props) => ([
- <MenuButton key='back' name="back" href="/media/" />,
- <MenuButton key='edit' name="edit" href={"/media/" + props.match.params.id + "/edit/"} />,
- <MenuButton key='delete' name="delete" onClick={() => {
- const { res: media } = props.media.show
- if (confirm("Really delete this media?")) {
- actions.media.destroy(media).then(() => {
- history.push('/media/')
- })
- }
- }} />,
-]))
-
-const MediaNewMenu = (props) => ([
- <MenuButton key='back' name="back" href="/media/" />,
-])
-
-const MediaEditMenu = connect(mapStateToProps)((props) => ([
- <MenuButton key='back' name="back" href="/media/" />,
- <MenuButton key='copy' name="copy" href={"/media/" + props.match.params.id + '/copy/'} label="Make a copy" />,
- <MenuButton key='delete' name="delete" onClick={() => {
- const { res: media } = props.media.show
- if (confirm("Really delete this media?")) {
- actions.media.destroy(media).then(() => {
- history.push('/media/')
- })
- }
- }} />,
-]))
diff --git a/animism-align/frontend/views/media/containers/media.edit.js b/animism-align/frontend/views/media/containers/media.edit.js
deleted file mode 100644
index 143cdfe..0000000
--- a/animism-align/frontend/views/media/containers/media.edit.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { connect } from 'react-redux'
-
-import { history } from '../../../store'
-import actions from '../../../actions'
-
-import { Loader } from '../../../common'
-
-import MediaForm from '../components/media.form'
-import MediaMenu from '../components/media.menu'
-
-class MediaEdit extends Component {
- componentDidMount() {
- console.log(this.props.match.params.id)
- actions.media.show(this.props.match.params.id)
- }
-
- handleSubmit(data) {
- actions.media.update(data)
- .then(response => {
- // response
- console.log(response)
- history.push('/media/')
- })
- }
-
- render() {
- const { show } = this.props.media
- if (show.loading || !show.res) {
- return (
- <div className='form'>
- <Loader />
- </div>
- )
- }
- return (
- <div className='row formContainer'>
- <MediaMenu mediaActions={this.props.mediaActions} />
- <MediaForm
- data={show.res}
- onSubmit={this.handleSubmit.bind(this)}
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- media: state.media,
-})
-
-const mapDispatchToProps = dispatch => ({
- // mediaActions: bindActionCreators({ ...mediaActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(MediaEdit)
diff --git a/animism-align/frontend/views/media/containers/media.index.js b/animism-align/frontend/views/media/containers/media.index.js
deleted file mode 100644
index a865522..0000000
--- a/animism-align/frontend/views/media/containers/media.index.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import { formatDateTime } from '../../../util'
-import { MenuButton, SmallMenuButton, Loader } from '../../../common'
-import actions from '../../../actions'
-
-import { thumbnailURL } from '../../align/align.util'
-
-import MediaIndexOptions from '../components/media.indexOptions'
-import MediaMenu from '../components/media.menu'
-
-// const { result, collectionLookup } = this.props
-
-class MediaIndex extends Component {
- componentDidMount() {
- // this.fetch(false)
- }
-
- componentDidUpdate(prevProps) {
- if (this.props.media.options.sort !== prevProps.media.options.sort) {
- this.fetch(false)
- }
- }
-
- fetch(load_more) {
- const { options, index } = this.props.media
- const { order: index_order } = index
- const [ sort, order ] = options.sort.split(' ')
- actions.media.index({
- sort, order, limit: 5000, // offset: load_more ? index_order.length : 0,
- }, load_more)
- }
-
- render() {
- const { mediaActions } = this.props
- const { options } = this.props.media
- const { loading, lookup, order } = this.props.media.index
- if (loading) {
- return (
- <section>
- <MediaIndexOptions />
- <div className="row">
- {order && !!order.length &&
- <div className={'results ' + options.thumbnailSize}>
- {order.map(id => <MediaItem key={id} data={lookup[id]} />)}
- </div>
- }
- </div>
- <Loader />
- </section>
- )
- }
- if (!lookup || !order.length) {
- return (
- <section>
- <MediaIndexOptions />
- <div className="row">
- <MediaMenu />
- <p className='gray'>
- {"No media"}
- </p>
- </div>
- </section>
- )
- }
- return (
- <section>
- <MediaIndexOptions />
- <div className="row">
- <MediaMenu />
- <div className={'results ' + options.thumbnailSize}>
- <h2>Images</h2>
- {order.filter(id => lookup[id].type === 'image').map(id => <MediaItem key={id} data={lookup[id]} />)}
- <h2>Video</h2>
- {order.filter(id => lookup[id].type === 'video').map(id => <MediaItem key={id} data={lookup[id]} />)}
- </div>
- </div>
- {order.length >= 50 && <button className='loadMore' onClick={() => this.fetch(true)}>Load More</button>}
- </section>
- )
- }
-}
-
-const MediaItem = ({ data }) => {
- // console.log(data)
- return (
- <div className='cell'>
- <div className='img'>
- <Link to={"/media/" + data.id + "/edit/"}>
- <img src={thumbnailURL(data)} alt={data.title} />
- </Link>
- </div>
- <div className='meta center'>
- <div>
- <i>{data.title}</i><br />
- {data.author}<br />
- {data.date}
- </div>
- </div>
- </div>
- )
-}
-
-const mapStateToProps = state => ({
- media: state.media,
-})
-
-const mapDispatchToProps = dispatch => ({
- // uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(MediaIndex)
diff --git a/animism-align/frontend/views/media/containers/media.new.js b/animism-align/frontend/views/media/containers/media.new.js
deleted file mode 100644
index 80879cb..0000000
--- a/animism-align/frontend/views/media/containers/media.new.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { connect } from 'react-redux'
-
-import { history } from '../../../store'
-import actions from '../../../actions'
-
-import MediaForm from '../components/media.form'
-import MediaMenu from '../components/media.menu'
-
-class MediaNew extends Component {
- state = {
- loading: true,
- initialData: {},
- }
-
- componentDidMount() {
- // console.log(this.props.match.params.id)
- if (this.props.match.params && this.props.match.params.id) {
- actions.media.show(this.props.match.params.id)
- .then(data => {
- const { id, ...initialData } = data.res
- delete initialData.settings.video
- delete initialData.settings.crop
- delete initialData.settings.display
- delete initialData.settings.fullsize
- delete initialData.settings.thumbnail
- delete initialData.settings.bibliography
- console.log("copying", id)
- this.setState({
- loading: false,
- initialData,
- })
- })
- } else {
- this.setState({ loading: false })
- }
- }
-
- handleSubmit(data) {
- console.log(data)
- actions.media.create(data)
- .then(res => {
- console.log(res)
- if (res.res && res.res.id) {
- history.push('/media/')
- }
- })
- .catch(err => {
- console.error('error')
- })
- }
-
- render() {
- if (this.state.loading) {
- return (
- <div className='row formContainer' />
- )
- }
- return (
- <div className='row formContainer'>
- <MediaMenu />
- <MediaForm
- isNew
- data={this.state.initialData}
- onSubmit={this.handleSubmit.bind(this)}
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- media: state.media,
-})
-
-const mapDispatchToProps = dispatch => ({
- // uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(MediaNew)
diff --git a/animism-align/frontend/views/media/media.actions.js b/animism-align/frontend/views/media/media.actions.js
deleted file mode 100644
index 1f1ab01..0000000
--- a/animism-align/frontend/views/media/media.actions.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import * as types from '../../types'
-import { capitalize, api } from '../../util'
-
-export const getVimeoMetadata = url => {
- return api(() => {}, types.vimeo, 'vimeo', 'https://vimeo.com/api/oembed.json', { url })
- .then(data => {
- return data
- })
-}
diff --git a/animism-align/frontend/views/media/media.container.js b/animism-align/frontend/views/media/media.container.js
deleted file mode 100644
index 97a5b08..0000000
--- a/animism-align/frontend/views/media/media.container.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, { Component } from 'react'
-import { Route, Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import './media.css'
-
-import actions from '../../actions'
-
-import MediaIndex from './containers/media.index'
-// import MediaShow from './containers/media.show'
-import MediaNew from './containers/media.new'
-import MediaEdit from './containers/media.edit'
-
-class Container extends Component {
- render() {
- return (
- <div className='media'>
- <Route exact path='/media/:id/copy/' component={MediaNew} />
- <Route exact path='/media/:id/edit/' component={MediaEdit} />
- <Route exact path='/media/new/' component={MediaNew} />
- <Route exact path='/media/' component={MediaIndex} />
- </div>
- )
- }
-}
-/*
- <Route exact path='/media/:id/show/' component={MediaShow} />
-*/
-const mapStateToProps = state => ({
- media: state.media,
-})
-
-const mapDispatchToProps = dispatch => ({
- // uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Container)
diff --git a/animism-align/frontend/views/media/media.css b/animism-align/frontend/views/media/media.css
deleted file mode 100644
index a2d95c8..0000000
--- a/animism-align/frontend/views/media/media.css
+++ /dev/null
@@ -1,70 +0,0 @@
-.app > .media {
- width: 100%;
- height: calc(100% - 3.125rem);
- overflow: scroll;
-}
-
-.results .cell {
- margin-bottom: 1rem;
- margin-right: 1rem;
-}
-.results h2 {
- display: block;
- width: 100%;
-}
-.media .results .meta > div {
- max-width: 100%;
-}
-
-/* new / edit media forms */
-
-.formContainer {
- padding-top: 1rem;
-}
-
-.imageForm,
-.videoForm {
- padding: 1rem 1rem 0.5rem 1rem;
- margin: 1rem 0;
- position: relative;
- left: -1rem;
- border-radius: 10px;
-}
-
-/* image form */
-
-.imageForm {
- background: #315;
-}
-.imageForm .fileInput .row {
- position: relative;
-}
-
-/* video form */
-
-.videoForm {
- background: #314;
-}
-.videoForm .thumbnail img {
- max-height: 200px;
-}
-
-/* image crop */
-
-.imageSelection {
- width: 30rem;
- position: relative;
-}
-.imageSelection img {
- display: block;
- max-width: 100%;
- max-height: 20rem;
-}
-.imageSelection img.loading {
- opacity: 0.5;
-}
-.imageSelection .box {
- position: absolute;
- background: rgba(255,32,64,0.05);
- border: 1px solid #f24;
-}
diff --git a/animism-align/frontend/views/media/media.reducer.js b/animism-align/frontend/views/media/media.reducer.js
deleted file mode 100644
index cb9b91d..0000000
--- a/animism-align/frontend/views/media/media.reducer.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-import { crudState, crudReducer } from '../../api/crud.reducer'
-
-const initialState = crudState('media', {
- options: {
- sort: 'author asc',
- thumbnailSize: getDefault('upload.thumbnailSize', 'small'),
- }
-})
-
-const reducer = crudReducer('media')
-
-export default function mediaReducer(state = initialState, action) {
- // console.log(action.type, action)
- state = reducer(state, action)
- switch (action.type) {
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/nav/header.component.js b/animism-align/frontend/views/nav/header.component.js
deleted file mode 100644
index efbaf08..0000000
--- a/animism-align/frontend/views/nav/header.component.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react'
-// import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-import { Link } from 'react-router-dom'
-
-import PlayButton from '../align/components/player/playButton.component'
-
-import './nav.css'
-
-function Header(props) {
- return (
- <header>
- <PlayButton />
- <div>
- <Link to="/align">Align</Link>
- <Link to="/paragraph">Transcript</Link>
- <Link to="/media">Media</Link>
- </div>
- </header>
- )
-}
-
-// const changeUsername = () => {
-// const username = prompt("Please enter your username:", session('username'))
-// if (username && username.length) {
-// session.set('username', username)
-// document.querySelector('Header div span').innerText = ' → ' + username // very naughty
-// }
-// }
-
-
-const mapStateToProps = (state) => ({
- // auth: state.auth,
- site: state.site,
- // username: session.get('username'),
- // isAuthenticated: state.auth.isAuthenticated,
-})
-
-const mapDispatchToProps = (dispatch) => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Header)
diff --git a/animism-align/frontend/views/nav/nav.css b/animism-align/frontend/views/nav/nav.css
deleted file mode 100644
index 485ace2..0000000
--- a/animism-align/frontend/views/nav/nav.css
+++ /dev/null
@@ -1,73 +0,0 @@
-/* header */
-
-header {
- height: 3.125rem;
- font-size: 0.875rem;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- background: rgba(32,16,64,0.8);
- color: white;
- z-index: 50;
- position: relative;
-}
-header b {
- font-weight: 900;
-}
-header a {
- color: rgba(255,255,255,0.95);
- text-decoration: none;
- font-size: 0.875rem;
- font-weight: 500;
-}
-header > div:first-child {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- padding-left: 1.5rem;
-}
-header > div:last-child {
- padding-right: 1.5rem;
-}
-header > div > button {
- padding: 0.25rem;
- margin: 0 0 0 0.5rem;
- background: #000;
- border-color: #888;
- color: #888;
-}
-header > div > button:hover {
- border-color: #fff;
- color: #fff;
-}
-header > div:last-child a {
- padding: 0.5rem;
-}
-header .btn-link:focus,
-header .btn-link:hover,
-header .btn-link:active,
-header a:focus,
-header a:hover,
-header a:active {
- text-decoration: none;
- color: white;
-}
-header a:focus,
-header a:hover,
-header a:active {
- color: white;
-}
-.menuToggle {
- width: 1.625rem;
- height: 1.625rem;
- cursor: pointer;
- line-height: 1;
-}
-header a.navbar-brand {
- font-size: .8rem;
-}
-
-header .username {
- cursor: pointer;
-} \ No newline at end of file
diff --git a/animism-align/frontend/views/paragraph/components/paragraph.form.js b/animism-align/frontend/views/paragraph/components/paragraph.form.js
deleted file mode 100644
index de3114c..0000000
--- a/animism-align/frontend/views/paragraph/components/paragraph.form.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-
-import { clamp, timestamp, capitalize } from '../../../util'
-import { Select } from '../../../common'
-
-const PARAGRAPH_TYPES = [
- 'paragraph', 'blockquote', 'hidden',
-].map(name => ({ name, label: capitalize(name.replace('_', ' ')) }))
-
-class ParagraphForm extends Component {
- constructor(props){
- super(props)
- this.handleChange = this.handleChange.bind(this)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleSubmit = this.handleSubmit.bind(this)
- }
- componentDidMount() {
- if (this.textareaRef && this.textareaRef.current) {
- this.textareaRef.current.focus()
- }
- }
- handleChange(e) {
- const { name, value } = e.target
- this.handleSelect(name, value)
- }
- handleSelect(name, value) {
- const { onUpdate, paragraph } = this.props
- onUpdate({
- ...paragraph,
- [name]: value,
- })
- }
- handleSubmit() {
- const { paragraph, onClose } = this.props
- actions.paragraph.update(paragraph)
- .then(response => {
- console.log(response)
- onClose()
- })
- }
- render() {
- const { paragraph, y } = this.props
- return (
- <div
- className='paragraphForm'
- style={{
- top: y,
- }}
- >
- {this.renderButtons()}
- </div>
- )
- }
- renderButtons() {
- const { paragraph } = this.props
- return (
- <div className='row buttons'>
- <div className='row'>
- <Select
- name='type'
- selected={paragraph.type}
- options={PARAGRAPH_TYPES}
- defaultOption='text'
- onChange={this.handleSelect}
- />
- <div className='ts'>{timestamp(paragraph.start_ts, 1, true)}</div>
- </div>
- <div>
- <button onClick={this.handleSubmit}>Save</button>
- </div>
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(ParagraphForm)
diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js
deleted file mode 100644
index 62b4a49..0000000
--- a/animism-align/frontend/views/paragraph/components/paragraphTypes/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react'
-
-import {
- Paragraph, ParagraphHeader
-} from './paragraphTypes.text'
-
-import {
- MediaVideo
-} from './paragraphTypes.video'
-
-import {
- MediaImage
-} from './paragraphTypes.image'
-
-export const paragraphElementLookup = {
- paragraph: React.memo(Paragraph),
- hidden: React.memo(Paragraph),
- blockquote: React.memo(Paragraph),
- header: React.memo(ParagraphHeader),
- video: React.memo(MediaVideo),
- image: React.memo(MediaImage),
-}
diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.image.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.image.js
deleted file mode 100644
index 36c72e9..0000000
--- a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.image.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React, { Component } from 'react'
-
-export const MediaImage = ({ paragraph, media, currentParagraph, currentAnnotation, onAnnotationClick, onDoubleClick }) => {
- if (!media.lookup) return <div />
- const className = currentParagraph ? 'media image current' : 'media image'
- 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)}
- >
- <img src={item.settings.display.url} />
- </div>
- )
-}
diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js
deleted file mode 100644
index c2ebcd7..0000000
--- a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.text.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, { Component } from 'react'
-
-export const Paragraph = ({ paragraph, currentParagraph, currentAnnotation, onAnnotationClick, onDoubleClick }) => {
- let className = paragraph.type
- if (className !== 'paragraph') className += ' paragraph'
- if (currentParagraph) className += ' current'
- return (
- <div
- className={className}
- onDoubleClick={e => onDoubleClick(e, paragraph)}
- >
- {paragraph.annotations.map(annotation => (
- <span
- key={annotation.id}
- className={annotation.id === currentAnnotation ? 'current' : ''}
- onClick={e => onAnnotationClick(e, paragraph, annotation)}
- dangerouslySetInnerHTML={{ __html: ' ' + annotation.text + ' ' }}
- />
- ))}
- </div>
- )
-}
-
-export const ParagraphHeader = ({ paragraph, currentParagraph, currentAnnotation, onAnnotationClick, onDoubleClick }) => {
- let className = currentParagraph ? 'header current' : 'header'
- const text = paragraph.annotations.map(annotation => annotation.text).join(' ')
- return (
- <div
- className={className}
- onDoubleClick={e => onDoubleClick(e, paragraph)}
- >
- {text}
- </div>
- )
-}
diff --git a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js b/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js
deleted file mode 100644
index 423864b..0000000
--- a/animism-align/frontend/views/paragraph/components/paragraphTypes/paragraphTypes.video.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React, { Component } from 'react'
-
-import VimeoPlayer from '@u-wave/react-vimeo'
-
-export const MediaVideo = ({ paragraph, media, currentParagraph, currentAnnotation, onAnnotationClick, onDoubleClick }) => {
- if (!media.lookup) return <div />
- const className = currentParagraph ? 'media current' : '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} 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
deleted file mode 100644
index 4c54808..0000000
--- a/animism-align/frontend/views/paragraph/containers/paragraphList.container.js
+++ /dev/null
@@ -1,206 +0,0 @@
-import React, { Component } from 'react'
-import { Route } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-import ParagraphForm from '../components/paragraph.form'
-
-const floatLT = (a,b) => ((a*10|0) < (b*10|0))
-const floatLTE = (a,b) => ((a*10|0) === (b*10|0) || floatLT(a,b))
-
-const MEDIA_TYPES = new Set(['image', 'gallery', 'vitrine', 'video'])
-
-class ParagraphList extends Component {
- state = {
- paragraphs: [],
- currentParagraph: -1,
- currentAnnotation: -1,
- selectedParagraph: null,
- selectedParagraphOffset: 0,
- }
-
- constructor(props) {
- super(props)
- this.handleAnnotationClick = this.handleAnnotationClick.bind(this)
- this.handleParagraphDoubleClick = this.handleParagraphDoubleClick.bind(this)
- this.handleCloseParagraphForm = this.handleCloseParagraphForm.bind(this)
- this.updateSelectedParagraph = this.updateSelectedParagraph.bind(this)
- }
-
- componentDidMount() {
- this.build()
- }
-
- componentDidUpdate(prevProps) {
- if (this.props.paragraph !== prevProps.paragraph) {
- this.build()
- }
- if (this.props.audio.play_ts === prevProps.audio.play_ts) return
- this.setCurrentParagraph()
- }
-
- setCurrentParagraph() {
- const { play_ts } = this.props.audio
- const insideParagraph = this.state.paragraphs.some(paragraph => {
- if (floatLTE(paragraph.start_ts, play_ts) && floatLT(play_ts, paragraph.end_ts)) {
- this.setCurrentAnnotation(paragraph, play_ts)
- return true
- }
- return false
- })
- if (!insideParagraph) {
- this.setState({
- currentParagraph: -1,
- currentAnnotation: -1,
- })
- }
- }
-
- setCurrentAnnotation(paragraph, play_ts) {
- const { id: currentParagraph, annotations } = paragraph
- let currentAnnotation
- let annotation
- let i = 0
- let len = annotations.length
- for (let i = 0; i < len - 1; i++) {
- if (floatLT(play_ts, annotations[i+1].start_ts)) {
- currentAnnotation = annotations[i].id
- break
- }
- }
- if (!currentAnnotation) {
- currentAnnotation = annotations[len-1].id
- }
- this.setState({ currentParagraph, currentAnnotation })
- }
-
- build() {
- const { order: annotationOrder, lookup: annotationLookup } = this.props.annotation
- const { lookup: paragraphLookup } = this.props.paragraph
- let currentParagraph = {}
- const paragraphs = []
- // loop over the annotations in time order
- annotationOrder.forEach((annotation_id, i) => {
- const annotation = annotationLookup[annotation_id]
- const paragraph = paragraphLookup[annotation.paragraph_id]
- // if this annotation is media, insert it after the current paragraph
- if (MEDIA_TYPES.has(annotation.type)) {
- paragraphs.push({
- id: ('index_' + i),
- type: annotation.type,
- start_ts: annotation.start_ts,
- end_ts: 0,
- annotations: [annotation],
- })
- return
- }
- // if this annotation is from a different paragraph, make a new paragraph
- if (annotation.paragraph_id !== currentParagraph.id) {
- const paragraph_type = getParagraphType(annotation, paragraph)
- currentParagraph = {
- id: annotation.paragraph_id || ('index_' + i),
- type: paragraph_type,
- start_ts: annotation.start_ts,
- end_ts: 0,
- annotations: [],
- }
- paragraphs.push(currentParagraph)
- }
- // if this annotation is a paragraph_end, set the end timestamp
- if (annotation.type === 'paragraph_end') {
- currentParagraph.end_ts = annotation.start_ts
- }
- // otherwise, just append this annotation to the paragraph
- else {
- currentParagraph.annotations.push(annotation)
- }
- })
- for (let i = 0; i < (paragraphs.length - 1); i++) {
- if (!paragraphs[i].end_ts) {
- paragraphs[i].end_ts = paragraphs[i+1].start_ts - 0.1
- }
- }
- this.setState({ paragraphs })
- }
-
- handleAnnotationClick(e, paragraph, annotation){
- actions.audio.seek(annotation.start_ts)
- }
- handleParagraphDoubleClick(e, paragraph) {
- console.log(e.target.parentNode)
- let paragraphNode = e.target
- if (!paragraphNode.classList.contains('paragraph')) {
- paragraphNode = paragraphNode.parentNode
- }
- this.setState({
- selectedParagraph: { ...paragraph },
- selectedParagraphOffset: paragraphNode.offsetTop
- })
- }
- updateSelectedParagraph(selectedParagraph) {
- this.setState({ selectedParagraph })
- }
- handleCloseParagraphForm() {
- this.setState({ selectedParagraph: null })
- }
-
- render() {
- const { media, paragraphElementLookup } = this.props
- const { paragraphs, selectedParagraph, selectedParagraphOffset, currentParagraph, currentAnnotation } = this.state
- return (
- <div className='paragraphs'>
- <div className='content'>
- {paragraphs.map(paragraph => {
- if (selectedParagraph && selectedParagraph.id === paragraph.id) {
- paragraph = selectedParagraph
- }
- if (paragraph.type in paragraphElementLookup) {
- const ParagraphElement = paragraphElementLookup[paragraph.type]
- return (
- <ParagraphElement
- key={paragraph.id}
- paragraph={paragraph}
- media={media}
- currentParagraph={paragraph.id === currentParagraph}
- currentAnnotation={paragraph.id === currentParagraph && currentAnnotation}
- onAnnotationClick={this.handleAnnotationClick}
- onDoubleClick={this.handleParagraphDoubleClick}
- />
- )
- } else {
- return <div key={paragraph.id}>{'(waiting to implement' + paragraph.type + ')'}</div>
- }
- })}
- {selectedParagraph &&
- <ParagraphForm
- paragraph={selectedParagraph}
- onUpdate={this.updateSelectedParagraph}
- onClose={this.handleCloseParagraphForm}
- y={selectedParagraphOffset}
- />
- }
- </div>
- </div>
- )
- }
-}
-
-const getParagraphType = (annotation, paragraph) => {
- if (!paragraph) {
- return annotation.type
- }
- return paragraph.type
-}
-
-const mapStateToProps = state => ({
- paragraph: state.paragraph.index,
- annotation: state.annotation.index,
- audio: state.audio,
- media: state.media.index,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(ParagraphList)
diff --git a/animism-align/frontend/views/paragraph/paragraph.container.js b/animism-align/frontend/views/paragraph/paragraph.container.js
deleted file mode 100644
index 6035be8..0000000
--- a/animism-align/frontend/views/paragraph/paragraph.container.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { Component } from 'react'
-import { Route } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import './paragraph.css'
-
-import actions from '../../actions'
-import { Loader } from '../../common'
-
-import ParagraphList from './containers/paragraphList.container'
-import { paragraphElementLookup } from '../components/paragraphTypes'
-
-class ParagraphContainer extends Component {
- componentDidMount() {
- this.bind()
- }
- componentWillUnmount() {
- this.unbind()
- }
- bind() {
- document.addEventListener('keydown', this.handleKeydown)
- }
- unbind() {
- document.removeEventListener('keydown', this.handleKeydown)
- }
- handleKeydown(e) {
- if (document.activeElement !== document.body) {
- return
- }
- // console.log(e.keyCode)
- switch (e.keyCode) {
- case 32: // spacebar
- e.preventDefault()
- actions.audio.toggle()
- break
- case 37: // left
- case 38: // up
- e.preventDefault()
- actions.audio.jump(-5.0)
- break
- case 39: // right
- case 40: // down
- e.preventDefault()
- actions.audio.jump(5.0)
- break
- }
- }
- render() {
- if (!this.props.annotation.lookup || !this.props.paragraph.lookup) {
- return <div className='body loading'><Loader /></div>
- }
- return (
- <div className='body'>
- <ParagraphList paragraphElementLookup={paragraphElementLookup} />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- paragraph: state.paragraph.index,
- annotation: state.annotation.index,
-})
-
-const mapDispatchToProps = dispatch => ({
- // alignActions: bindActionCreators({ ...alignActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(ParagraphContainer)
diff --git a/animism-align/frontend/views/paragraph/paragraph.css b/animism-align/frontend/views/paragraph/paragraph.css
deleted file mode 100644
index 8cd502c..0000000
--- a/animism-align/frontend/views/paragraph/paragraph.css
+++ /dev/null
@@ -1,93 +0,0 @@
-.paragraphs {
- width: 100%;
- height: calc(100% - 3.125rem);
- overflow: scroll;
- background: white;
- color: black;
- padding: 1rem;
-}
-
-/* general paragraph styles */
-
-.paragraphs .content {
- font-family: 'Georgia', serif;
- width: 650px;
- margin: 0 auto;
- padding-bottom: 6rem;
- position: relative;
-}
-
-.paragraphs .content > div {
- margin-bottom: 16px;
-}
-
-/* paragraph subtypes */
-
-.paragraphs .header {
- font-size: 32px;
-}
-
-.paragraphs .paragraph {
- font-size: 16px;
- line-height: 24px;
-}
-
-.paragraphs .blockquote {
- padding-left: 3rem;
-}
-
-.paragraphs .hidden {
- opacity: 0.5;
-}
-
-/* media image */
-
-.paragraphs .media.image img {
- width: 100%;
-}
-
-/* current paragraph */
-
-.paragraphs .paragraph.current {
- background: rgba(0,0,0,0.0);
-}
-
-/* sentences */
-
-.paragraphs span {
- margin-right: 4px;
- cursor: pointer;
-}
-
-.paragraphs .paragraph .current {
- box-shadow: -2px -3px 0 #fff,
- 2px -3px 0 #fff,
- -2px 3px 0 #fff,
- 2px 3px 0 #fff;
- box-decoration-break: clone;
- background: black;
- color: white;
-}
-
-/* paragraph form */
-
-.paragraphForm {
- position: absolute;
- right: -305px;
- width: 300px;
- padding: 0.5rem;
- background: #ddd;
- box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
-}
-.paragraphForm .select div {
- color: #ddd;
- font-family: 'Roboto', sans-serif;
-}
-.paragraphForm .row {
- justify-content: space-between;
- align-items: center;
-}
-.paragraphForm .row > div {
- display: flex;
- align-items: center;
-}
diff --git a/animism-align/frontend/views/paragraph/paragraph.reducer.js b/animism-align/frontend/views/paragraph/paragraph.reducer.js
deleted file mode 100644
index 263aa07..0000000
--- a/animism-align/frontend/views/paragraph/paragraph.reducer.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-import { crudState, crudReducer } from '../../api/crud.reducer'
-
-const initialState = crudState('paragraph', {
- options: {
- }
-})
-
-const reducer = crudReducer('paragraph')
-
-export default function paragraphReducer(state = initialState, action) {
- // console.log(action.type, action)
- state = reducer(state, action)
- switch (action.type) {
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/site/component.template.js b/animism-align/frontend/views/site/component.template.js
deleted file mode 100644
index a22d582..0000000
--- a/animism-align/frontend/views/site/component.template.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React, { Component } from 'react'
-// import { Link } from 'react-router-dom'
-// import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-// import * as uploadActions from './upload.actions'
-
-class ComponentTemplate extends Component {
- componentDidMount() {
- }
- render() {
- const { } = this.props
- return (
- <div className="">
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
-})
-
-const mapDispatchToProps = dispatch => ({
- // uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(ComponentTemplate)
diff --git a/animism-align/frontend/views/site/site.actions.js b/animism-align/frontend/views/site/site.actions.js
deleted file mode 100644
index c7c228e..0000000
--- a/animism-align/frontend/views/site/site.actions.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as types from '../../types'
-// import actions from '../../actions'
-// import { session } from '../../session'
-import { api, post, pad, preloadImage } from '../../util'
-
-export const loadPeaks = (asdf) => dispatch => {
- api(dispatch, types.peaks, 'peaks', '/static/data_store/peaks/peaks.json')
-}
-
-export const loadText = (asdf) => dispatch => {
- api(dispatch, types.text, 'text', '/static/data_store/peaks/text.txt')
-}
-
-export const updateText = text => dispatch => {
- dispatch({ type: types.text.loaded, data: text })
-} \ No newline at end of file
diff --git a/animism-align/frontend/views/site/site.reducer.js b/animism-align/frontend/views/site/site.reducer.js
deleted file mode 100644
index e80033f..0000000
--- a/animism-align/frontend/views/site/site.reducer.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as types from '../../types'
-// import { session, getDefault, getDefaultInt } from '../../session'
-
-const initialState = {
- peaks: { loading: true },
- text: { loading: true },
-}
-
-export default function siteReducer(state = initialState, action) {
- // console.log(action.type, action)
- // console.log(action.data)
- switch (action.type) {
- case types.peaks.loaded:
- return {
- ...state,
- peaks: action.data,
- }
- case types.text.loaded:
- return {
- ...state,
- text: action.data,
- }
- default:
- return state
- }
-}
diff --git a/animism-align/frontend/views/upload/components/upload.form.js b/animism-align/frontend/views/upload/components/upload.form.js
deleted file mode 100644
index 2010088..0000000
--- a/animism-align/frontend/views/upload/components/upload.form.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-
-import { MenuButton, FileInput } from '../../../common'
-
-export default class UploadForm extends Component {
- render() {
- return (
- <div className='uploadForm'>
- <MenuButton name="upload" label={false}>
- <FileInput onChange={this.props.uploadActions.upload} />
- </MenuButton>
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/upload/components/upload.index.js b/animism-align/frontend/views/upload/components/upload.index.js
deleted file mode 100644
index 3a7ae4b..0000000
--- a/animism-align/frontend/views/upload/components/upload.index.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-
-import { uploadUri, formatDateTime } from '../../../util'
-import { MenuButton, SmallMenuButton, Loader } from '../../../common'
-import actions from '../../../actions'
-
-import UploadIndexOptions from './upload.indexOptions'
-import UploadMenu from './upload.menu'
-
-// const { result, collectionLookup } = this.props
-
-export default class UploadIndex extends Component {
- componentDidMount() {
- this.fetch(false)
- }
-
- componentDidUpdate(prevProps) {
- if (this.props.upload.options.sort !== prevProps.upload.options.sort) {
- this.fetch(false)
- }
- }
-
- fetch(load_more) {
- const { options, index } = this.props.upload
- const { order: index_order } = index
- const [ sort, order ] = options.sort.split('-')
- actions.upload.index({
- sort, order, limit: 50, offset: load_more ? index_order.length : 0,
- }, load_more)
- }
-
- render() {
- const { uploadActions } = this.props
- const { options } = this.props.upload
- const { loading, lookup, order } = this.props.upload.index
- if (loading) {
- return (
- <section>
- <UploadIndexOptions />
- <div className="row">
- {order && !!order.length &&
- <div className={'results ' + options.thumbnailSize}>
- {order.map(id => <UploadItem key={id} data={lookup[id]} />)}
- </div>
- }
- </div>
- <Loader />
- </section>
- )
- }
- if (!lookup || !order.length) {
- return (
- <section>
- <UploadIndexOptions />
- <div className="row">
- <UploadMenu uploadActions={uploadActions} />
- <p className='gray'>
- {"No uploads"}
- </p>
- </div>
- </section>
- )
- }
- return (
- <section>
- <UploadIndexOptions />
- <div className="row">
- <UploadMenu uploadActions={uploadActions} />
- <div className={'results ' + options.thumbnailSize}>
- {order.map(id => <UploadItem key={id} data={lookup[id]} />)}
- </div>
- </div>
- {order.length >= 50 && <button className='loadMore' onClick={() => this.fetch(true)}>Load More</button>}
- </section>
- )
- }
-}
-
-const UploadItem = ({ data }) => {
- // console.log(data)
- // const imageUri = uploadUri(data)
- return (
- <div className='cell'>
- <div className='img'>
- <Link to={"/upload/" + data.id + "/show/"}>
- <img src={data.url} alt={"Uploaded image"} />
- </Link>
- </div>
- <div className='meta center'>
- <div>
- {formatDateTime(data.created_at)}
- </div>
- </div>
- </div>
- )
-}
-
diff --git a/animism-align/frontend/views/upload/components/upload.indexOptions.js b/animism-align/frontend/views/upload/components/upload.indexOptions.js
deleted file mode 100644
index 774bf22..0000000
--- a/animism-align/frontend/views/upload/components/upload.indexOptions.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-
-import { Select, Checkbox } from '../../../common'
-
-const thumbnailOptions = [
- { name: 'th', label: 'Thumbnails', },
- { name: 'sm', label: 'Small', },
- { name: 'md', label: 'Medium', },
- { name: 'lg', label: 'Large', },
- { name: 'orig', label: 'Original', },
-]
-
-const sortOptions = [
- { name: 'id-asc', label: 'Most recent' },
- { name: 'id-desc', label: 'Oldest first' },
- { name: 'username-asc', label: 'Username (A-Z)' },
- { name: 'username-desc', label: 'Username (Z-A)' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
- // { name: '-asc', label: '' },
- // { name: '-desc', label: '' },
-]
-
-class IndexOptions extends Component {
- render() {
- const { options } = this.props
- return (
- <div className='row menubar'>
- <div />
- <Select
- name={'sort'}
- options={sortOptions}
- selected={options.sort}
- onChange={actions.upload.updateOption}
- />
- <Select
- name={'thumbnailSize'}
- options={thumbnailOptions}
- selected={options.thumbnailSize}
- onChange={actions.upload.updateOption}
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- options: state.upload.options,
-})
-
-const mapDispatchToProps = dispatch => ({
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(IndexOptions)
diff --git a/animism-align/frontend/views/upload/components/upload.menu.js b/animism-align/frontend/views/upload/components/upload.menu.js
deleted file mode 100644
index 37c7f0b..0000000
--- a/animism-align/frontend/views/upload/components/upload.menu.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-
-import { MenuButton, FileInput } from '../../../common'
-
-import actions from '../../../actions'
-
-export default class UploadMenu extends Component {
- render() {
- return (
- <div className='menuButtons'>
- <MenuButton name="upload">
- <FileInput onChange={this.props.uploadActions.upload} />
- </MenuButton>
- </div>
- )
- }
-}
diff --git a/animism-align/frontend/views/upload/components/upload.show.js b/animism-align/frontend/views/upload/components/upload.show.js
deleted file mode 100644
index 352caf3..0000000
--- a/animism-align/frontend/views/upload/components/upload.show.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { Component } from 'react'
-import { Link } from 'react-router-dom'
-import { connect } from 'react-redux'
-
-import actions from '../../../actions'
-import { formatDate, formatTime, formatAge, uploadUri } from '../../../util'
-import { history } from '../../../store'
-import { Loader, MenuButton } from '../../../common'
-
-class UploadShow extends Component {
- componentDidMount() {
- actions.upload.show(this.props.match.params.id)
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.match.params.id !== this.props.match.params.id) {
- actions.upload.show(this.props.match.params.id)
- }
- }
-
- handleDestroy() {
- const { res: data } = this.props.upload.show
- if (confirm("Really delete this upload?")) {
- actions.upload.destroy(data).then(() => {
- history.push('/upload/')
- })
- }
- }
-
- render() {
- const { show, destroy } = this.props.upload
- if (show.loading || destroy.loading) {
- return <Loader />
- }
- if (!show.loading && !show.res || show.not_found) {
- return <div className='gray'>Upload {this.props.match.params.id} not found</div>
- }
- const { res: data } = show
- return (
- <section className="row uploadShow">
- <div className="menuButtons">
- <MenuButton name="delete" onClick={this.handleDestroy.bind(this)} />
- </div>
- <div>
- <img src={data.url} />
- <div className='byline'>
- {'Uploaded by '}
- {data.username}
- {' on '}
- {formatDate(data.created_at)}
- {' at '}
- {formatTime(data.created_at)}
- {'. '}
- </div>
- </div>
- </section>
- )
- }
-}
-
-const mapStateToProps = state => ({
- upload: state.upload,
-})
-
-const mapDispatchToProps = dispatch => ({
- // searchActions: bindActionCreators({ ...searchActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(UploadShow)
diff --git a/animism-align/frontend/views/upload/upload.actions.js b/animism-align/frontend/views/upload/upload.actions.js
deleted file mode 100644
index c5d12e3..0000000
--- a/animism-align/frontend/views/upload/upload.actions.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import * as types from '../../types'
-import { store, history } from '../../store'
-import { api, post, pad, preloadImage } from '../../util'
-import actions from '../../actions'
-import { session } from '../../session'
-
-export const upload = (image, tag='upload') => dispatch => {
- const formData = {
- image,
- tag,
- username: 'animism', // session('username'),
- }
- // console.log(formData)
- return actions.upload.upload(formData).then(data => {
- // console.log(data.res)
- return data.res
- })
-}
diff --git a/animism-align/frontend/views/upload/upload.container.js b/animism-align/frontend/views/upload/upload.container.js
deleted file mode 100644
index 0ad76c9..0000000
--- a/animism-align/frontend/views/upload/upload.container.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, { Component } from 'react'
-import { Route, Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import './upload.css'
-
-import actions from '../../actions'
-import * as uploadActions from './upload.actions'
-
-import UploadMenu from './components/upload.menu'
-import UploadIndex from './components/upload.index'
-import UploadShow from './components/upload.show'
-
-class Container extends Component {
- render() {
- return (
- <div className='row upload'>
- <div>
- <Route exact path='/upload/:id/show/' component={UploadShow} />
- <UploadIndex {...this.props} />
- </div>
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- upload: state.upload,
-})
-
-const mapDispatchToProps = dispatch => ({
- uploadActions: bindActionCreators({ ...uploadActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Container)
diff --git a/animism-align/frontend/views/upload/upload.css b/animism-align/frontend/views/upload/upload.css
deleted file mode 100644
index 28ce33d..0000000
--- a/animism-align/frontend/views/upload/upload.css
+++ /dev/null
@@ -1,182 +0,0 @@
-.uploadShow {
- margin-top: 1rem;
-}
-.uploadShow img {
- max-width: 30rem;
- max-height: 20rem;
-}
-.upload {
- height: 100%;
-}
-.upload > div:last-child {
- flex: 1;
- width: 100%;
-}
-
-/* results */
-
-.resultsContainer {
-}
-.results {
- display: flex;
- flex-flow: row wrap;
- justify-content: flex-start;
- align-items: flex-end;
-}
-.results .result {
- display: inline-block;
- margin-right: 1.125rem;
- margin-bottom: 1.125rem;
-}
-.result > a {
- display: block;
-}
-.result > a > div {
- position: relative;
-}
-.result img {
- max-width: 100%;
- display: block;
- cursor: pointer;
-}
-.result > a {
- border: 2px solid transparent;
-}
-.results .active img,
-.desktop .result > a:hover {
- border-color: #11f;
-}
-.results.th .result {
- max-width: 10rem;
-}
-.results.sm .result {
- max-width: 20rem;
-}
-.results.md .result {
- max-width: 40rem;
-}
-.results.lg .result {
- max-width: 80rem;
-}
-.results.orig .result {
- max-width: 100%;
-}
-.results.th img {
- max-height: 120px;
-}
-.results.sm img {
- max-height: 160px;
-}
-.results.md img {
- max-height: 480px;
-}
-.results.lg img {
- max-height: 960px;
-}
-.results.orig img {
- max-width: none;
- max-height: none;
-}
-.results .img {
- width: 100%;
-}
-.results .img > a {
- display: inline-block;
- position: relative;
-}
-.results .meta {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: baseline;
- font-size: 0.75rem;
- color: #888;
- padding: 0.125rem;
-}
-.results .meta.center,
-.row.center {
- align-items: center;
-}
-.results .meta > div {
- overflow: hidden;
- max-width: 75%;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.results .meta > span {
- padding-right: 0.125rem;
-}
-.results .meta .buttons {
-}
-.score.good {
- color: #11f;
- font-weight: bold;
-}
-.score.ok {
- color: #44d;
- font-weight: bold;
-}
-.score.poor {
- color: #66b;
-}
-.score {
- color: #888;
-}
-.resultGroup {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- position: relative;
- border: 2px solid #888;
- max-width: 20rem;
- margin-right: 1.5rem;
- margin-bottom: 1.5rem;
- background: #fff;
- box-shadow: 0 2px 4px #888;
-}
-.resultGroup .sha256 {
- position: absolute;
- background: white;
- padding: 0.25rem 0.25rem 0rem 0.25rem;
- left: 0.25rem;
- top: -0.75rem;
- font-size: 0.75rem;
- color: #333;
- text-transform: uppercase;
- max-width: 95%;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.results.grouped {
- background: #fff;
-}
-.results.grouped.sm,
-.results.grouped.md,
-.results.grouped.lg,
-.results.grouped.orig {
- flex-flow: column nowrap;
-}
-.results.th .resultGroup {
- max-width: 33.5rem;
-}
-.results.sm .resultGroup {
- max-width: 56rem;
-}
-.results.md .resultGroup {
- max-width: 79rem;
-}
-.results.lg .resultGroup {
- max-width: 100%;
-}
-.results.orig .resultGroup {
- max-width: 100%;
-}
-.results .resultGroup .result {
- margin: 0.5rem;
-}
-.loadMore {
- width: 100%;
-}
-.loadMore button {
- width: 100%;
-}
diff --git a/animism-align/frontend/views/upload/upload.reducer.js b/animism-align/frontend/views/upload/upload.reducer.js
deleted file mode 100644
index db12819..0000000
--- a/animism-align/frontend/views/upload/upload.reducer.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as types from '../../types'
-import { session, getDefault, getDefaultInt } from '../../session'
-
-import { crudState, crudReducer } from '../../api/crud.reducer'
-
-const initialState = crudState('upload', {
- options: {
- sort: getDefault('upload.sort', 'id-desc'),
- thumbnailSize: getDefault('upload.thumbnailSize', 'small'),
- }
-})
-
-const reducer = crudReducer('upload')
-
-export default function uploadReducer(state = initialState, action) {
- // console.log(action.type, action)
- state = reducer(state, action)
- switch (action.type) {
- default:
- return state
- }
-}