diff --git a/static/images/play_button.svg b/static/images/play_button.svg new file mode 100644 index 0000000..541085c --- /dev/null +++ b/static/images/play_button.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/static/src/interface/About.js b/static/src/interface/About.js new file mode 100644 index 0000000..ac6042e --- /dev/null +++ b/static/src/interface/About.js @@ -0,0 +1,118 @@ +/** + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'style/about.css' +import YouTubeIframeLoader from 'youtube-iframe' +import events from 'events' + +const magentaLink = 'https://github.com/tensorflow/magenta' +const sourceCode = 'https://github.com/googlecreativelab/aiexperiments-ai-duet' +const toneLink = 'https://github.com/Tonejs/Tone.js' + +const blurbCopy = `Built by Yotam Mann with friends on the Magenta and Creative Lab teams at Google. + It uses Tone.js and tools + from the Magenta project. + The open-source code is available here.` + +export class About extends events.EventEmitter{ + constructor(container){ + + super() + + this._container = document.createElement('div') + this._container.id = 'about' + container.appendChild(this._container) + + this._toggleButton = document.createElement('div') + this._toggleButton.id = 'aboutButton' + this._toggleButton.classList.add('open') + container.appendChild(this._toggleButton) + this._toggleButton.addEventListener('click', (e) => { + e.preventDefault() + if (this.isOpen()){ + this.close() + } else { + this.open() + } + }) + + const content = document.createElement('div') + content.id = 'content' + this._container.appendChild(content) + + const title = document.createElement('div') + title.id = 'title' + title.textContent = 'A.I. Duet' + content.appendChild(title) + + const video = document.createElement('div') + video.id = 'video' + //vid YT0k99hCY5I + video.innerHTML = `` + content.appendChild(video) + + this._ytplayer = null + + this._playButton = document.createElement('div') + this._playButton.id = 'playButton' + this._playButton.classList.add('visible') + video.appendChild(this._playButton) + + YouTubeIframeLoader.load((YT) => { + this._ytplayer = new YT.Player('youtube-iframe', { + events : { + onStateChange : (state) => { + this._playButton.classList.remove('visible') + } + } + }) + }) + + const blurb = document.createElement('div') + blurb.id = 'blurb' + content.appendChild(blurb) + blurb.innerHTML = blurbCopy + + } + close(){ + this._toggleButton.classList.remove('close') + this._toggleButton.classList.add('open') + + this._container.classList.remove('visible') + + if (this._ytplayer){ + this._ytplayer.stopVideo() + } + this.emit('close') + if (window.ga){ + ga('send', 'event', 'AI-Duet', 'Click', 'About - Close') + } + } + open(){ + this._toggleButton.classList.add('close') + this._toggleButton.classList.remove('open') + + this._playButton.classList.add('visible') + this._container.classList.add('visible') + this.emit('open') + if (window.ga){ + ga('send', 'event', 'AI-Duet', 'Click', 'About - Open') + } + } + isOpen(){ + return this._container.classList.contains('visible') + } +} \ No newline at end of file diff --git a/static/app/interface/Splash.js b/static/src/interface/Splash.js similarity index 71% rename from static/app/interface/Splash.js rename to static/src/interface/Splash.js index 8649099..6ed7123 100644 --- a/static/app/interface/Splash.js +++ b/static/src/interface/Splash.js @@ -23,7 +23,7 @@ class Splash extends events.EventEmitter{ constructor(container){ super() - const splash = document.createElement('div') + const splash = this._splash = document.createElement('div') splash.id = 'splash' container.appendChild(splash) @@ -42,26 +42,39 @@ class Splash extends events.EventEmitter{ titleContainer.appendChild(subTitle) subTitle.textContent = 'Trade melodies with a neural network.' - const loader = new Loader(titleContainer) + this._clicked = false + const loader = this._loader = new Loader(titleContainer) loader.on('click', () => { splash.classList.add('disappear') + this._clicked = true this.emit('click') }) + const magenta = document.createElement('div') + magenta.id = 'magentaLink' + titleContainer.appendChild(magenta) + magenta.innerHTML = 'Built using Magenta' + + const badges = document.createElement('div') + badges.id = 'badges' + splash.appendChild(badges) + const aiExperiments = document.createElement('a') aiExperiments.id = 'aiExperiments' aiExperiments.href = 'https://aiexperiments.withgoogle.com' aiExperiments.target = '_blank' - splash.appendChild(aiExperiments) + aiExperiments.classList.add('badge') + badges.appendChild(aiExperiments) // break const badgeBreak = document.createElement('div') badgeBreak.id = 'badgeBreak' - splash.appendChild(badgeBreak) + badges.appendChild(badgeBreak) const googleFriends = document.createElement('a') googleFriends.id = 'googleFriends' - splash.appendChild(googleFriends) + googleFriends.classList.add('badge') + badges.appendChild(googleFriends) const privacyAndTerms = document.createElement('div') privacyAndTerms.id = 'privacyAndTerms' @@ -69,6 +82,22 @@ class Splash extends events.EventEmitter{ splash.appendChild(privacyAndTerms) } + + get loaded(){ + return this._loader.loaded + } + + isOpen(){ + return !this._clicked + } + + show(){ + this._splash.classList.remove('disappear') + } + + hide(){ + this._splash.classList.add('disappear') + } } export {Splash} \ No newline at end of file diff --git a/static/style/about.css b/static/style/about.css new file mode 100644 index 0000000..72b3af3 --- /dev/null +++ b/static/style/about.css @@ -0,0 +1,155 @@ +/** + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'common.scss'; + +#aboutButton { + $closeSize : 30px; + position: absolute; + top: 15px; + right: 15px; + width: $closeSize; + height: $closeSize; + cursor: pointer; + z-index: 1000; + transition: transform 0.1s; + text-align: center; + + &:hover { + transform: scale(1.1); + } + + &:before{ + font-family: $font-family; + font-weight: bold; + width: 100%; + height: 100%; + position: absolute; + top: 0px; + right: 0px; + line-height: $closeSize; + } + + &.close:before{ + content: "✕"; + font-size: 25px; + color: white; + background-color: transparent; + + } + &.open:before{ + content: "?"; + background-color: white; + border-radius: 50%; + + } +} + +#about { + width: 100%; + height: 100%; + z-index: 10; + top: 0px; + left: 0px; + position: absolute; + overflow-y: auto; + display: none; + + &.visible { + display: initial; + } + + #content { + width: 90%; + margin: 50px auto 30px auto; + min-width: 300px; + max-width: 800px; + height: auto; + position: relative; + color: white; + font-family: $font-family; + position: relative; + + #title { + font-family: $font-family; + font-size: 40px; + line-height: 30px; + margin: 20px 0px 30px 0px; + position: relative; + } + + $smallScreen : 450px; + $mediumScreen : 700px; + + #video { + width: 100%; + cursor: pointer; + position: relative; + + @media (max-width: $smallScreen) { + height: 200px; + } + + @media (min-width: $smallScreen) and (max-width: $mediumScreen) { + height: 380px; + } + + @media (min-width: $mediumScreen){ + height: 450px; + } + + iframe { + width: 100%; + height: 100%; + } + + #playButton { + pointer-events: none; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100px; + height: 100px; + background-image: url(../images/play_button.svg); + background-size: 100% 100%; + display: none; + + &.visible { + display: initial; + } + } + + &:hover #playButton svg{ + fill: blue; + } + } + + #blurb { + + position: relative; + text-transform: none; + margin-top: 30px; + font-size: 16px; + line-height: 25px; + + a { + color: $orange; + } + } + + } +} \ No newline at end of file diff --git a/static/style/splash.css b/static/style/splash.css index ffe10d9..e145519 100644 --- a/static/style/splash.css +++ b/static/style/splash.css @@ -1,6 +1,6 @@ @import 'common.scss'; -$topMargin: 50px; +$topMargin: 40px; #splash { position: absolute; @@ -9,7 +9,7 @@ $topMargin: 50px; top: 0px; left: 0px; z-index: 100; - font-family: 'Quicksand', sans-serif; + font-family: $font-family; font-weight: bold; color: white; transition: opacity 0.2s; @@ -54,6 +54,30 @@ $topMargin: 50px; font-weight: normal; } + #magentaLink { + margin-top: $topMargin * 0.8; + letter-spacing: 0.8px; + line-height: 30px; + font-size: 20px; + width: 100%; + margin-left: auto; + margin-right: auto; + text-align: center; + font-weight: normal; + color: #aaa; + font-size: 14px; + + a { + color: $orange; + text-decoration: underline; + cursor: pointer; + &:hover:active { + color: white; + } + } + + } + $loaderWidth: 200px; $loaderHeight: 60px; @@ -144,50 +168,78 @@ $topMargin: 50px; margin-top: $topMargin; } - $badgeWidth : 80px; - $badgeHeight: 50px; + $badgeWidth : 110px; + $badgeHeight: 60px; $badgeMargin : 20px; $badegOpacity: 0.7; - #aiExperiments, #googleFriends { - width: $badgeWidth; - height: $badgeHeight; + $smallScreen : 500px; + $smallBadgeWidth : 70px; + $smallBadgeHeight: 40px; + + #badges { + position: absolute; + display: inline-block; bottom: $badgeMargin; - opacity: $badegOpacity; - background-repeat: no-repeat; - background-size: 100% 100%; - } - - #aiExperiments { left: $badgeMargin; - background-image: url(../images/badgeAI_master.svg); - &:hover { - opacity: 1; + @media (max-width: $smallScreen) { + // bottom: $badgeMargin * 0.5; + } - &:active { - opacity: 0.3; + .badge { + display: inline-block; + position: relative; + margin-right: $badgeMargin; + width: $badgeWidth; + height: $badgeHeight; + background-repeat: no-repeat; + background-size: 100% 100%; + opacity: $badegOpacity; + + @media (max-width: $smallScreen) { + width: $smallBadgeWidth; + height: $smallBadgeHeight; + } + } + + #aiExperiments { + background-image: url(../images/badgeAI_master.svg); + &:hover { + opacity: 1; + &:active { + opacity: 0.3; + } + } + } + + #googleFriends { + cursor: initial; + background-image: url(../images/badgeFriends_master.svg); + } + + #badgeBreak{ + display: inline-block; + position: relative; + margin-right: $badgeMargin; + + $breakScale : 0.95; + + $breakHeight: $badgeHeight * $breakScale; + height: $breakHeight; + background-color: white; + opacity: $badegOpacity / 2; + width: 1px; + + @media (max-width: $smallScreen) { + $smallBreakHeight: $smallBadgeHeight * $breakScale; + height: $smallBreakHeight; } } } - #googleFriends { - cursor: initial; - left: $badgeWidth + $badgeMargin * 3; - background-image: url(../images/badgeFriends_master.svg); - } - #badgeBreak{ - $breakHeight: $badgeHeight * 0.8; - height: $breakHeight; - left: $badgeWidth + $badgeMargin * 1.8; - background-color: white; - opacity: $badegOpacity / 2; - position: absolute; - width: 1px; - bottom: $badgeMargin + ($badgeHeight - $breakHeight) / 2; - } #privacyAndTerms { position: absolute; @@ -199,7 +251,7 @@ $topMargin: 50px; * { height: 14px; line-height: 14px; - font-size: 14px; + font-size: 10px; color: white; display: inline; opacity: $badegOpacity;