diff options
Diffstat (limited to 'animism-align')
| -rw-r--r-- | animism-align/cli/app/settings/app_cfg.py | 10 | ||||
| -rw-r--r-- | animism-align/environment.yml | 1 | ||||
| -rw-r--r-- | animism-align/frontend/common/form.component.js | 7 | ||||
| -rw-r--r-- | animism-align/frontend/types.js | 1 | ||||
| -rw-r--r-- | animism-align/frontend/util/index.js | 33 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/components/media.form.js | 13 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/components/media.formImage.js | 64 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/components/media.formImageSelection.js | 213 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/components/media.formVideo.js | 89 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/containers/media.index.js | 12 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/containers/media.new.js | 2 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/media.actions.js | 10 | ||||
| -rw-r--r-- | animism-align/frontend/views/media/media.css | 54 | ||||
| -rw-r--r-- | animism-align/package-lock.json | 184 | ||||
| -rw-r--r-- | animism-align/package.json | 2 |
15 files changed, 653 insertions, 42 deletions
diff --git a/animism-align/cli/app/settings/app_cfg.py b/animism-align/cli/app/settings/app_cfg.py index 0a33b50..6fb3e3e 100644 --- a/animism-align/cli/app/settings/app_cfg.py +++ b/animism-align/cli/app/settings/app_cfg.py @@ -87,4 +87,12 @@ HTTP_EXTERNAL_HOST = os.getenv('HTTP_EXTERNAL_HOST') or f"http://{SERVER_NAME}" # ----------------------------------------------------------------------------- UCODE_OK = u"\u2714" # check ok -UCODE_NOK = u'\u2718' # x no ok
\ No newline at end of file +UCODE_NOK = u'\u2718' # x no ok + +# ----------------------------------------------------------------------------- +# Vimeo API +# ----------------------------------------------------------------------------- + +VIMEO_ACCESS_TOKEN = "9dc32c0a13b05e59527661cf0c69ad5d0896d99b" +VIMEO_CLIENT_ID = "qJgeYR1j7uu92BOdt+Kwp3hyeaGZbG8HUrGIqAAN0Lv79rsxzdQu7F/WyO2SgCXNHiz4tB6NAC0IQkV0XerWn9fiHurhO9DC/39uhF6I4T3o5TH0LJOWx5GKPLVryruM" +VIMEO_CLIENT_SECRET = "588aa1d15488d5b32d499ea76a03d9de" diff --git a/animism-align/environment.yml b/animism-align/environment.yml index 3a28790..92fb95c 100644 --- a/animism-align/environment.yml +++ b/animism-align/environment.yml @@ -87,6 +87,7 @@ dependencies: - urllib3==1.25.3 - validators==0.13.0 - vine==1.3.0 + - PyVimeo==1.0.11 - werkzeug==0.15.5 - wtforms==2.2.1 - wtforms-alchemy==0.16.9 diff --git a/animism-align/frontend/common/form.component.js b/animism-align/frontend/common/form.component.js index f3775a2..2f9162e 100644 --- a/animism-align/frontend/common/form.component.js +++ b/animism-align/frontend/common/form.component.js @@ -8,8 +8,9 @@ export const TextInput = props => ( type="text" required={props.required} onChange={props.onChange} + onBlur={props.onBlur} name={props.name} - value={props.data[props.name]} + value={props.data[props.name] || ""} placeholder={props.placeholder} autoComplete={props.autoComplete} /> @@ -17,7 +18,7 @@ export const TextInput = props => ( ) export const LabelDescription = props => ( - <label className={'text description'}> + <label className={props.className ? 'text description ' + props.className : 'text description'}> <span>{props.title}</span> <span>{props.children}</span> </label> @@ -160,7 +161,7 @@ export class FileInputField extends Component { <span>{title}</span> <div className="row"> <button> - {label || "Choose files"} + {label || (multiple ? "Choose files" : "Choose file")} <FileInput mime={mime} multiple={multiple} diff --git a/animism-align/frontend/types.js b/animism-align/frontend/types.js index f92f70b..3c460a9 100644 --- a/animism-align/frontend/types.js +++ b/animism-align/frontend/types.js @@ -8,6 +8,7 @@ export const peaks = crud_type('peaks', []) export const text = crud_type('text', []) export const annotation = crud_type('annotation', []) export const paragraph = crud_type('paragraph', []) +export const vimeo = crud_type('vimeo', []) export const align = crud_type('align', [ 'set_display_setting', 'set_temporary_annotation', diff --git a/animism-align/frontend/util/index.js b/animism-align/frontend/util/index.js index d723910..a50bccb 100644 --- a/animism-align/frontend/util/index.js +++ b/animism-align/frontend/util/index.js @@ -128,7 +128,7 @@ export const preloadImage = url => ( }) ) -export const cropImage = (url, crop) => { +export const cropImage = (url, crop, maxSide) => { return new Promise((resolve, reject) => { let { x, y, w, h } = crop const image = new Image() @@ -143,8 +143,22 @@ export const cropImage = (url, crop) => { image.onload = null const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') - const width = image.naturalWidth - const height = image.naturalHeight + const { naturalWidth, naturalHeight } = image + let height, width + + if (maxSide > 0) { + if (naturalWidth > naturalHeight) { + width = Math.min(maxSide, naturalWidth) + height = naturalHeight * canvas.width / naturalWidth + } else { + height = Math.min(maxSide, naturalHeight) + width = naturalWidth * canvas.height / naturalHeight + } + } else { + width = naturalWidth + height = naturalHeight + } + canvas.width = w * width canvas.height = h * height ctx.drawImage( @@ -242,11 +256,14 @@ export const api = (dispatch, type=api_type, tag, url, data) => { } else { req = req.then(res => res.json()) } - req = req.then(res => dispatch({ - type: type.loaded, - tag, - data: res, - })) + req = req.then(res => { + dispatch({ + type: type.loaded, + tag, + data: res, + }) + return res + }) .catch(err => dispatch({ type: type.error, tag, diff --git a/animism-align/frontend/views/media/components/media.form.js b/animism-align/frontend/views/media/components/media.form.js index 94968df..c82b384 100644 --- a/animism-align/frontend/views/media/components/media.form.js +++ b/animism-align/frontend/views/media/components/media.form.js @@ -84,7 +84,7 @@ export default class MediaForm extends Component { ...this.state.data, settings: { ...this.state.data.settings, - [name]: [value], + [name]: value, } } }) @@ -94,8 +94,8 @@ export default class MediaForm extends Component { e.preventDefault() const { isNew, onSubmit } = this.props const { data } = this.state - const requiredKeys = "title".split(" ") - const validKeys = "title".split(" ") + const requiredKeys = "author title date".split(" ") + const validKeys = "type tag url title author pre_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) { @@ -116,12 +116,7 @@ export default class MediaForm extends Component { render() { const { isNew } = this.props const { title, submitTitle, errorFields, data } = this.state - /* - type: '', - tag: '', - url: '', - */ - console.log(data) + // console.log(data) return ( <div className='form'> <h1>{title}</h1> diff --git a/animism-align/frontend/views/media/components/media.formImage.js b/animism-align/frontend/views/media/components/media.formImage.js index b3d227e..c757d03 100644 --- a/animism-align/frontend/views/media/components/media.formImage.js +++ b/animism-align/frontend/views/media/components/media.formImage.js @@ -4,7 +4,9 @@ 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 { TextInput, LabelDescription, FileInputField, Select, TextArea, Checkbox, SubmitButton, Loader } from '../../../common' + +import { ImageSelection } from './media.formImageSelection' export default class MediaImageForm extends Component { state = { @@ -15,9 +17,7 @@ export default class MediaImageForm extends Component { this.handleSelect = this.handleSelect.bind(this) this.handleChange = this.handleChange.bind(this) this.handleSettingsChange = this.handleSettingsChange.bind(this) - } - - componentDidMount() { + this.handleUpload = this.handleUpload.bind(this) } handleChange(e) { @@ -33,11 +33,67 @@ export default class MediaImageForm extends Component { this.props.onSettingsChange(name, value) } + handleUpload(image) { + // upload fullsize + this.uploadFullSize(image) + .then(res => { + this.props.onSettingsChange('fullsize', data.res) + setTimeout(() => { + }) + }) + } + + uploadFullSize(image) { + actions.upload.upload({ + image, + tag: 'fullsize', + username: 'animism', + }).then(data => { + console.log(data.res) + return data.res + }) + } + + uploadThumbnail(image) { + actions.upload.upload({ + image, + tag: 'thumbnail', + username: 'animism', + }).then(data => { + console.log(data.res) + }) + } + + uploadCrop(image) { + actions.upload.upload({ + image, + tag: 'crop', + username: 'animism', + }).then(data => { + console.log(data.res) + this.props.onSelect('url', data.res.url) + }) + } + render() { const { data } = this.props console.log(data) return ( <div className='imageForm'> + {!data.url && + <FileInputField + title='Upload image' + onChange={this.handleUpload} + /> + } + {data.settings.fullsize && + <div> + <ImageSelection + url={data.settings.fullsize.url} + crop={data.settings.crop} + /> + </div> + } </div> ) } diff --git a/animism-align/frontend/views/media/components/media.formImageSelection.js b/animism-align/frontend/views/media/components/media.formImageSelection.js new file mode 100644 index 0000000..142525b --- /dev/null +++ b/animism-align/frontend/views/media/components/media.formImageSelection.js @@ -0,0 +1,213 @@ +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, + } +} + +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 index 16c1fbb..89954b9 100644 --- a/animism-align/frontend/views/media/components/media.formVideo.js +++ b/animism-align/frontend/views/media/components/media.formVideo.js @@ -1,11 +1,12 @@ import React, { Component } from 'react' import { Link } from 'react-router-dom' +import VimeoPlayer from '@u-wave/react-vimeo' -import { session } from '../../../session' 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 = { } @@ -17,27 +18,93 @@ export default class MediaVideoForm extends Component { this.handleSettingsChange = this.handleSettingsChange.bind(this) } - componentDidMount() { - } - handleChange(e) { - const { name, value } = e.target - this.handleSelect(name, value) + let { name, value } = e.target + return this.handleSelect(name, value) } handleSelect(name, value) { - this.props.onSelect(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) } - handleSettingsChange(name, value) { + handleSettingsSelect(name, value) { this.props.onSettingsChange(name, value) } render() { const { data } = this.props - console.log(data) return ( - <div className='imageForm'> + <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/containers/media.index.js b/animism-align/frontend/views/media/containers/media.index.js index 09ef6ca..7797fd7 100644 --- a/animism-align/frontend/views/media/containers/media.index.js +++ b/animism-align/frontend/views/media/containers/media.index.js @@ -79,19 +79,23 @@ class MediaIndex extends Component { } } +const thumbnailURL = data => { + if (data.type === 'video') return data.settings.video.thumbnail_url +} const MediaItem = ({ data }) => { // console.log(data) return ( <div className='cell'> <div className='img'> - <Link to={"/media/" + data.id + "/show/"}> - <img src={data.thumb_url} alt={data.title} /> + <Link to={"/media/" + data.id + "/edit/"}> + <img src={thumbnailURL(data)} alt={data.title} /> </Link> </div> <div className='meta center'> <div> - {data.title}<br /> - {data.author} + <i>{data.title}</i><br /> + {data.author}<br /> + {data.date} </div> </div> </div> diff --git a/animism-align/frontend/views/media/containers/media.new.js b/animism-align/frontend/views/media/containers/media.new.js index 88bf467..e740c0c 100644 --- a/animism-align/frontend/views/media/containers/media.new.js +++ b/animism-align/frontend/views/media/containers/media.new.js @@ -42,7 +42,7 @@ const mapStateToProps = state => ({ }) const mapDispatchToProps = dispatch => ({ - // searchActions: bindActionCreators({ ...searchActions }, 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 new file mode 100644 index 0000000..e33746e --- /dev/null +++ b/animism-align/frontend/views/media/media.actions.js @@ -0,0 +1,10 @@ +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 + }) + // const id = url.match(/\d+/i)[0]; +} diff --git a/animism-align/frontend/views/media/media.css b/animism-align/frontend/views/media/media.css index 2f3ca0d..251afd6 100644 --- a/animism-align/frontend/views/media/media.css +++ b/animism-align/frontend/views/media/media.css @@ -1,3 +1,55 @@ +.app > .media { + width: 100%; + height: calc(100% - 3.125rem); + overflow: scroll; +} + +/* new / edit media forms */ + .formContainer { padding-top: 1rem; -}
\ No newline at end of file +} + +.imageForm, +.videoForm { + padding: 1rem 1rem 0.5rem 1rem; + margin: 1rem 0; + position: relative; + left: -1rem; + border-radius: 10px; +} + +/* image form */ + +.imageForm { + background: #315; +} + +/* 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/package-lock.json b/animism-align/package-lock.json index 1fab790..78b4c6b 100644 --- a/animism-align/package-lock.json +++ b/animism-align/package-lock.json @@ -3287,11 +3287,50 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/react": { + "version": "16.9.41", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.41.tgz", + "integrity": "sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug==", + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, "@types/sortablejs": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.10.4.tgz", "integrity": "sha512-iXdJUEM09Hc0RacStDvkEi5BBdHuuwdys0L5/GtsRiEht69Df4hapA3FwFIeXn2STicqJjBAkowyD1OA3jGgwA==" }, + "@types/vimeo__player": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@types/vimeo__player/-/vimeo__player-2.9.0.tgz", + "integrity": "sha512-KLcx6GR+iXfLKnP2ecnK808rX6uf+y/aPOzOw4+lQBc8SqlMn4xv6cX6eXgKBaZgau8qNbNLzbS4RyW5ojrJhg==" + }, + "@u-wave/react-vimeo": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@u-wave/react-vimeo/-/react-vimeo-0.9.0.tgz", + "integrity": "sha512-xGE0WQtQEkfCdMsrGwzNvGjMARdU2pMQ3xdtmR1ruIYnImIJyUG/XrbLtOy+F9f8c4fVEtiyPrJIa15B7kCayA==", + "requires": { + "@types/react": "^16.9.32", + "@types/vimeo__player": "^2.9.0", + "@vimeo/player": "^2.10.0", + "prop-types": "^15.7.2" + } + }, + "@vimeo/player": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@vimeo/player/-/player-2.12.0.tgz", + "integrity": "sha512-SrlwZxeZvoFBEdbxrEg7eheevaMey7bYbip+IoTvRVsmW7JC98ulL1qDAcwAOHMWfTvFtAG6oLl6/spccJiI6w==", + "requires": { + "native-promise-only": "0.8.1", + "weakmap-polyfill": "2.0.1" + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -4907,6 +4946,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "combine-errors": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/combine-errors/-/combine-errors-3.0.3.tgz", + "integrity": "sha1-9N9nQAg+VwOjGBEQwrEFUfAD2oY=", + "requires": { + "custom-error-instance": "2.1.1", + "lodash.uniqby": "4.5.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -5219,11 +5267,21 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, + "csstype": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz", + "integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==" + }, "csv-stringify": { "version": "5.3.6", "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.3.6.tgz", "integrity": "sha512-kPcRbMvo5NLLD71TAqW5K+g9kbM2HpIZJLAzm73Du8U+5TXmDp9YtXKCBLyxEh0q3Jbg8QhNFBz3b5VJzjZ/jw==" }, + "custom-error-instance": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", + "integrity": "sha1-PPY5FIemYppiR+sMoM4ACBt+Nho=" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -7602,6 +7660,11 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, + "js-base64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz", + "integrity": "sha512-1hgLrLIrmCgZG+ID3VoLNLOSwjGnoZa8tyrUdEteMeIzsT6PH7PMLyUvbDwzNE56P3PNxyvuIOx4Uh2E5rzQIw==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7780,6 +7843,46 @@ "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=" }, + "lodash._baseiteratee": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz", + "integrity": "sha1-NKm1VDVycnw9sueO2uPA6eZr0QI=", + "requires": { + "lodash._stringtopath": "~4.8.0" + } + }, + "lodash._basetostring": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz", + "integrity": "sha1-kyfJ3FFYhmt/pLnUL0Y45XZt2d8=" + }, + "lodash._baseuniq": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", + "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", + "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + }, + "lodash._stringtopath": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz", + "integrity": "sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ=", + "requires": { + "lodash._basetostring": "~4.12.0" + } + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -7829,6 +7932,15 @@ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" }, + "lodash.uniqby": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz", + "integrity": "sha1-o6F7v2LutiQPSRhG6XwcTipeHiE=", + "requires": { + "lodash._baseiteratee": "~4.7.0", + "lodash._baseuniq": "~4.6.0" + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8148,6 +8260,11 @@ } } }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8855,6 +8972,15 @@ "react-is": "^16.8.1" } }, + "proper-lockfile": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz", + "integrity": "sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=", + "requires": { + "graceful-fs": "^4.1.2", + "retry": "^0.10.0" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -8934,6 +9060,11 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + }, "ramda": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", @@ -9608,6 +9739,11 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -9683,6 +9819,11 @@ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -10780,6 +10921,27 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" }, + "tus-js-client": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/tus-js-client/-/tus-js-client-1.8.0.tgz", + "integrity": "sha512-qPX3TywqzxocTxUZtcS8X7Aik72SVMa0jKi4hWyfvRV+s9raVzzYGaP4MoJGaF0yOgm2+b6jXaVEHogxcJ8LGw==", + "requires": { + "buffer-from": "^0.1.1", + "combine-errors": "^3.0.3", + "extend": "^3.0.2", + "js-base64": "^2.4.9", + "lodash.throttle": "^4.1.1", + "proper-lockfile": "^2.0.1", + "url-parse": "^1.4.3" + }, + "dependencies": { + "buffer-from": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", + "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==" + } + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -11000,6 +11162,15 @@ "querystring": "0.2.0" } }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -11074,6 +11245,14 @@ "unist-util-stringify-position": "^1.1.1" } }, + "vimeo": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/vimeo/-/vimeo-2.1.1.tgz", + "integrity": "sha512-6aBlIOdnCgGSigkH54DHsb1n+mW0NIAgxmh+AVEC5hwjfy6zaUtkSIrlMJbYSOwwEfkjpIBR7L8gfWDRmLaEmw==", + "requires": { + "tus-js-client": "^1.5.1" + } + }, "vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -11089,6 +11268,11 @@ "neo-async": "^2.5.0" } }, + "weakmap-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/weakmap-polyfill/-/weakmap-polyfill-2.0.1.tgz", + "integrity": "sha512-Jy177Lvb1LCrPQDWJsXyyqf4eOhcdvQHFGoCqSv921kVF5i42MVbr4e2WEwetuTLBn1NX0IhPzTmMu0N3cURqQ==" + }, "webpack": { "version": "4.42.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", diff --git a/animism-align/package.json b/animism-align/package.json index e1686aa..846bd81 100644 --- a/animism-align/package.json +++ b/animism-align/package.json @@ -19,6 +19,7 @@ "@babel/preset-env": "^7.8.6", "@babel/preset-react": "^7.8.3", "@babel/runtime": "^7.8.4", + "@u-wave/react-vimeo": "^0.9.0", "aws-sdk": "^2.631.0", "babel-eslint": "^10.1.0", "babel-loader": "^8.0.6", @@ -65,6 +66,7 @@ "style-loader": "^1.1.3", "terser-webpack-plugin": "^2.3.5", "uuid": "^7.0.1", + "vimeo": "^2.1.1", "webpack": "^4.42.0", "webpack-cli": "^3.3.11" }, |
