From b8e8c187788987176b54711aa02d8efeb11cd144 Mon Sep 17 00:00:00 2001 From: johnshaughnessy <johnfshaughnessy@gmail.com> Date: Wed, 1 Aug 2018 17:35:34 -0700 Subject: [PATCH] Add the ability to upload files via the create object dialog. --- src/assets/stylesheets/info-dialog.scss | 126 +++++++++++++++---- src/react-components/create-object-dialog.js | 114 +++++++++++------ 2 files changed, 175 insertions(+), 65 deletions(-) diff --git a/src/assets/stylesheets/info-dialog.scss b/src/assets/stylesheets/info-dialog.scss index 7b55cdab8..556b78524 100644 --- a/src/assets/stylesheets/info-dialog.scss +++ b/src/assets/stylesheets/info-dialog.scss @@ -75,6 +75,106 @@ } } +.input-border { + margin: 2% 1% 2% 1%; + display: flex; + width: 100%; + justify-content: space-between; + background:white; + @extend %rounded-border; + @extend %default-font; +} + +.small-button { + width: 8%; + padding-right: 2%; + padding-left: 2%; +} + +.url-input { + border: none; + padding-left: 2%; + flex-grow: 1; + text-align: center; + background:transparent; + color:black; + font-size: 1.1em; +} + +.file-name { + text-align: center; + flex-grow: 1; + align-self: center; + color: black; +} + +.form { + width: 80%; +} + +.hide-file-input { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; +} + +#upload-svg { + fill: #222222; +} + +#upload-svg.unhover { + animation-name: upload-button-unhover; + animation-duration: 0.5s; + animation-timing-function: ease-in; + animation-fill-mode: forwards; +} + +#upload-svg.hover{ + animation-name: upload-button-hover; + animation-duration: 0.2s; + animation-timing-function: ease-out; + animation-fill-mode: forwards; +} + +#cancel-svg { + fill: #FF9E9D; +} + +#cancel-svg.unhover{ + animation-name: cancel-button-unhover; + animation-duration: 0.5s; + animation-timing-function: ease-in; + animation-fill-mode: forwards; +} + +#cancel-svg.hover{ + animation-name: cancel-button-hover; + animation-duration: 0.2s; + animation-timing-function: ease-out; + animation-fill-mode: forwards; +} + +@keyframes upload-button-hover { + from { fill : #222222;} + to {fill : #c431bd;} +} +@keyframes upload-button-unhover { + from {fill : #c431bd;} + to { fill : #222222;} +} + +@keyframes cancel-button-hover { + from { fill : #FF9E9D;} + to {fill : #FF3D7F;} +} +@keyframes cancel-button-unhover { + from {fill : #FF3D7F;} + to { fill : #FF9E9D;} +} + .invite-form, .add-media-form, .custom-scene-form { display: flex; flex-direction: column; @@ -82,32 +182,6 @@ text-align: center; margin: 0; - &__input_fields { - position: relative; - } - - &__file { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; - } - - &__file_label { - font-size: 1.25em; - font-weight: 700; - color: white; - background-color: black; - display: inline-block; - top: 19px; - right: 24px; - bottom: 19px; - position: absolute; - line-height: 30px; - } - &__buttons { display: flex; flex-direction: row; diff --git a/src/react-components/create-object-dialog.js b/src/react-components/create-object-dialog.js index a7223d468..6b5d7a9cc 100644 --- a/src/react-components/create-object-dialog.js +++ b/src/react-components/create-object-dialog.js @@ -8,6 +8,17 @@ const attributionHostnames = { }; const DEFAULT_OBJECT_URL = "https://asset-bundles-prod.reticulum.io/interactables/Ducky/DuckyMesh-438ff8e022.gltf"; +const isMobile = AFRAME.utils.device.isMobile(); +const instructions = "Paste a URL or upload a file"; +const desktopTips = "Tip: You can paste links directly into Hubs with Ctrl+V"; +const mobileInstructions = <div>{instructions}</div>; +const desktopInstructions = ( + <div> + {instructions} + <br /> + {desktopTips} + </div> +); let lastUrl = ""; @@ -15,7 +26,7 @@ export default class CreateObjectDialog extends Component { state = { url: "", file: null, - text: "" + fileName: "" }; static propTypes = { @@ -24,9 +35,7 @@ export default class CreateObjectDialog extends Component { }; componentDidMount() { - this.setState({ url: lastUrl }, () => { - this.onUrlChange({ target: this.input }); - }); + this.setState({ url: lastUrl }); } componentWillUnmount() { @@ -34,23 +43,25 @@ export default class CreateObjectDialog extends Component { } onUrlChange = e => { - if (e && e.target.value && e.target.value !== "") { - this.setState({ - url: e.target.value, - text: e.target.value, - attributionImage: e.target.validity.valid && attributionHostnames[new URL(e.target.value).hostname] - }); - } else { + let url; + try { + url = new URL(e.target.value); + } catch (_) { this.setState({ - text: "" + url: e.target && e.target.value }); + return; } + this.setState({ + url: e.target && e.target.value, + attributionImage: e.target && e.target.value && e.target.validity.valid && attributionHostnames[url.hostname] + }); }; - onFileChange = (e) =>{ + onFileChange = e => { this.setState({ file: e.target.files[0], - text: e.target.files[0].name + fileName: e.target.files[0].name }); }; @@ -59,36 +70,61 @@ export default class CreateObjectDialog extends Component { this.props.onCloseDialog(); }; + reset = e => { + e.preventDefault(); + this.setState({ + url: "", + file: null, + fileName: "" + }); + }; + + onHover = e => { + e.currentTarget.children[0].classList.add("hover"); + e.currentTarget.children[0].classList.remove("unhover"); + }; + + onHoverExit = e => { + e.currentTarget.children[0].classList.remove("hover"); + e.currentTarget.children[0].classList.add("unhover"); + }; + render() { + const withContent = ( + <label className="small-button" onClick={this.reset} onMouseEnter={this.onHover} onMouseLeave={this.onHoverExit}> + <svg id="cancel-svg" viewBox="0 0 512 512"> + /* font awesome : times-circle-regular*/ + <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z" /> + </svg> + </label> + ); + const withoutContent = ( + <label htmlFor="file-input" className="small-button" onMouseEnter={this.onHover} onMouseLeave={this.onHoverExit}> + <svg id="upload-svg" viewBox="0 0 512 512"> + /* font awesome : upload-solid*/ + <path d="M296 384h-80c-13.3 0-24-10.7-24-24V192h-87.7c-17.8 0-26.7-21.5-14.1-34.1L242.3 5.7c7.5-7.5 19.8-7.5 27.3 0l152.2 152.2c12.6 12.6 3.7 34.1-14.1 34.1H320v168c0 13.3-10.7 24-24 24zm216-8v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h136v8c0 30.9 25.1 56 56 56h80c30.9 0 56-25.1 56-56v-8h136c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z" /> + </svg> + </label> + ); + const fileName = <label className="file-name">{this.state.fileName}</label>; + const urlInput = ( + <input + className="url-input" + placeholder="Image/Video/glTF URL" + onChange={this.onUrlChange} + value={this.state.url} + /> + ); + return ( <div> - {!AFRAME.utils.device.isMobile() ? ( - <div> - Paste a URL from the web to create an object in the room. - <br /> - Tip: You can paste directly into Hubs using Ctrl+V - </div> - ) : ( - <div>Paste a URL from the web to create an object in the room.</div> - )} - + {isMobile ? mobileInstructions : desktopInstructions} <form onSubmit={this.onCreateClicked}> <div className="add-media-form"> - <div className="add-media-form__input_fields"> - <input - ref={el => (this.input = el)} - type={this.state.file ? "text" : "url"} - placeholder="Image, Video, or GLTF URL" - className="add-media-form__link_field" - value={this.state.text} - onChange={this.onUrlChange} - /> - <input className="add-media-form__file" - id="file" - type="file" - onChange={this.onFileChange} - /> - <label className="add-media-form__file_label" htmlFor="file">Choose a file</label> + <input id="file-input" className="hide-file-input" type="file" onChange={this.onFileChange} /> + <div className="input-border"> + {this.state.file ? fileName : urlInput} + {this.state.url || this.state.fileName ? withContent : withoutContent} </div> <div className="add-media-form__buttons"> <button className="add-media-form__action-button"> -- GitLab