From 5b50d1b1e7ad3cdf454ec96b25dda803fd4863ca Mon Sep 17 00:00:00 2001 From: Aram Zadikian Date: Fri, 21 Apr 2017 14:06:20 -0700 Subject: [PATCH 1/3] Add video --- .../communication/video-chat/component.js | 64 +++++++++++++++++++ .../communication/video-chat/styles.styl | 2 + .../communication/video-chat/template.hbs | 8 +++ app/index.html | 2 + app/routes/session.js | 10 ++- app/templates/session.hbs | 2 + .../video-chat/component-test.js | 25 ++++++++ 7 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 app/components/communication/video-chat/component.js create mode 100644 app/components/communication/video-chat/styles.styl create mode 100644 app/components/communication/video-chat/template.hbs create mode 100644 tests/integration/components/communication/video-chat/component-test.js diff --git a/app/components/communication/video-chat/component.js b/app/components/communication/video-chat/component.js new file mode 100644 index 0000000..5d50bfd --- /dev/null +++ b/app/components/communication/video-chat/component.js @@ -0,0 +1,64 @@ +import Ember from 'ember'; + +const Video = Twilio.Video; + +export default Ember.Component.extend({ + didInsertElement() { + const { token, identity } = this.get("twilioData"); + + console.log(token, identity); + + Video.connect(token, {name: "my-room"}) + .then(room => { + + this.attachTracks(room.localParticipant.tracks, this.$(".me:first")[0]); + + room.participants.forEach(::this.participantConnected); + room.on('participantConnected', ::this.participantConnected); + + room.on('participantDisconnected', ::this.participantDisconnected); + room.once('disconnected', error => room.participants.forEach(::this.participantDisconnected)); + }, e => { + console.log(e); + }) + }, + + attachTracks(tracks, container) { + tracks.forEach(track => { + container.appendChild(track.attach()) + }); + }, + + participantConnected(participant) { + this.attachTracks(participant.tracks, this.$(".others:first")[0]) + // console.log('Participant "%s" connected', participant.identity); + // + // const div = document.createElement('div'); + // div.id = participant.sid; + // div.innerText = participant.identity; + // + // participant.on('trackAdded', track => trackAdded(div, track)); + // participant.tracks.forEach(track => trackAdded(div, track)); + // participant.on('trackRemoved', trackRemoved); + // + // document.body.appendChild(div); + }, + + participantDisconnected(participant) { + console.log("Dis", participant); + // console.log('Participant "%s" disconnected', participant.identity); + // + // participant.tracks.forEach(trackRemoved); + // document.getElementById(participant.sid).remove(); + }, + + trackAdded(div, track) { + console.log("track added"); + // div.appendChild(track.attach()); + }, + + trackRemoved(track) { + console.log("trackRemoved"); + // track.detach().forEach(element => element.remove()); + } +}); diff --git a/app/components/communication/video-chat/styles.styl b/app/components/communication/video-chat/styles.styl new file mode 100644 index 0000000..2879549 --- /dev/null +++ b/app/components/communication/video-chat/styles.styl @@ -0,0 +1,2 @@ +div + max-width: 2em diff --git a/app/components/communication/video-chat/template.hbs b/app/components/communication/video-chat/template.hbs new file mode 100644 index 0000000..b398bf6 --- /dev/null +++ b/app/components/communication/video-chat/template.hbs @@ -0,0 +1,8 @@ +
+
+ +
+
+ +
+
diff --git a/app/index.html b/app/index.html index e4d8a79..e2b628a 100644 --- a/app/index.html +++ b/app/index.html @@ -14,6 +14,8 @@ + + {{content-for "head-footer"}} diff --git a/app/routes/session.js b/app/routes/session.js index 0e6f2bb..32f927f 100644 --- a/app/routes/session.js +++ b/app/routes/session.js @@ -5,15 +5,19 @@ import moment from 'moment'; export default Ember.Route.extend({ setupController(controller, model) { - const { record, sessionId } = model; + const { record, sessionId, twilioData } = model; controller.set('session', record); + controller.set('twilioData', twilioData); controller.set('sessionId', sessionId); this._super(...arguments); }, async model(params) { + const twilioDataRes = await fetch("https://wt-brancusi-gmail_com-0.run.webtask.io/create-twilio-token"); + const twilioData = await twilioDataRes.json(); + const record = await this.store.findRecord('lesson', params.id) .catch(() => { return this.store @@ -23,6 +27,7 @@ export default Ember.Route.extend({ return { record, + twilioData, sessionId: params.id } }, @@ -31,9 +36,8 @@ export default Ember.Route.extend({ onAudioCreated(model, blob) { const app = firebase.app(); var storageRef = app.storage().ref(); - const id = uuid(); - const path = `audio/${id}.wav`; + const path = `audio/${uuid()}.wav`; var audioRef = storageRef.child(path); audioRef.put(blob).then(() => { diff --git a/app/templates/session.hbs b/app/templates/session.hbs index c17aa02..3e24ee2 100644 --- a/app/templates/session.hbs +++ b/app/templates/session.hbs @@ -18,3 +18,5 @@

No flash cards yet. Why not create one?

{{/if}} + +{{communication/video-chat twilioData=twilioData}} diff --git a/tests/integration/components/communication/video-chat/component-test.js b/tests/integration/components/communication/video-chat/component-test.js new file mode 100644 index 0000000..cd0028e --- /dev/null +++ b/tests/integration/components/communication/video-chat/component-test.js @@ -0,0 +1,25 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('communication/video-chat', 'Integration | Component | communication/video chat', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{communication/video-chat}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#communication/video-chat}} + template block text + {{/communication/video-chat}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); From 18aed9b2b2c0cb82b44a837467203f743eeae557 Mon Sep 17 00:00:00 2001 From: Aram Zadikian Date: Fri, 21 Apr 2017 15:32:53 -0700 Subject: [PATCH 2/3] wip --- .../communication/video-chat/styles.styl | 18 ++++++++++-- .../conversation-group/component.js | 11 ++++++++ .../conversation-group/template.hbs | 14 ++++++++++ app/components/flash-card-group/component.js | 4 +++ app/components/flash-card-group/template.hbs | 16 +++++++++++ app/components/flash-card/template.hbs | 2 +- app/components/navs/lesson-nav/component.js | 5 ++++ app/components/navs/lesson-nav/template.hbs | 2 +- app/controllers/.gitkeep | 0 app/controllers/session.js | 20 ------------- app/models/conversation.js | 12 ++++++++ app/models/flash-card.js | 5 ++-- app/models/lesson.js | 2 +- app/router.js | 2 +- app/routes/index.js | 4 +-- app/routes/{session.js => lesson.js} | 28 +++++++++++++------ app/templates/index.hbs | 2 +- app/templates/lesson.hbs | 13 +++++++++ app/templates/session.hbs | 22 --------------- .../conversation-group/component-test.js | 25 +++++++++++++++++ .../flash-card-group/component-test.js | 25 +++++++++++++++++ .../{session-test.js => lesson-test.js} | 2 +- tests/unit/models/conversation-test.js | 12 ++++++++ .../{session-test.js => lesson-test.js} | 2 +- 24 files changed, 185 insertions(+), 63 deletions(-) create mode 100644 app/components/conversation-group/component.js create mode 100644 app/components/conversation-group/template.hbs create mode 100644 app/components/flash-card-group/component.js create mode 100644 app/components/flash-card-group/template.hbs delete mode 100644 app/controllers/.gitkeep delete mode 100644 app/controllers/session.js create mode 100644 app/models/conversation.js rename app/routes/{session.js => lesson.js} (69%) create mode 100644 app/templates/lesson.hbs delete mode 100644 app/templates/session.hbs create mode 100644 tests/integration/components/conversation-group/component-test.js create mode 100644 tests/integration/components/flash-card-group/component-test.js rename tests/unit/controllers/{session-test.js => lesson-test.js} (81%) create mode 100644 tests/unit/models/conversation-test.js rename tests/unit/routes/{session-test.js => lesson-test.js} (81%) diff --git a/app/components/communication/video-chat/styles.styl b/app/components/communication/video-chat/styles.styl index 2879549..6d00b90 100644 --- a/app/components/communication/video-chat/styles.styl +++ b/app/components/communication/video-chat/styles.styl @@ -1,2 +1,16 @@ -div - max-width: 2em +& + position: fixed + bottom: 0 + right: 0 + +.previews + height: 75px + +video + border: 0 + margin: 0 + padding: 0 + width: 100px + +.vsc-controller + display: none diff --git a/app/components/conversation-group/component.js b/app/components/conversation-group/component.js new file mode 100644 index 0000000..473ed4e --- /dev/null +++ b/app/components/conversation-group/component.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; +import computed from 'ember-computed-decorators'; + +const { isPresent, computed: { alias, sort, gt } } = Ember; + +export default Ember.Component.extend({ + sortAsc: ["position:asc"], + sortedConversations: sort('model', 'sortAsc'), + conversationCount: alias("sortedConversations.length"), + hasConversations: gt("conversationCount", 0) +}); diff --git a/app/components/conversation-group/template.hbs b/app/components/conversation-group/template.hbs new file mode 100644 index 0000000..82fdcf4 --- /dev/null +++ b/app/components/conversation-group/template.hbs @@ -0,0 +1,14 @@ +
+ {{#if hasConversations}} + {{#each sortedConversations as |conversation index|}} + {{flash-card-group + model=conversation + onAudioCreated=onAudioCreated + createFlashCard=createFlashCard + destroyFlashCard=destroyFlashCard + saveModel=saveModel}} + {{/each}} + {{else}} +

No conversations yet. Why not start one?

+ {{/if}} +
diff --git a/app/components/flash-card-group/component.js b/app/components/flash-card-group/component.js new file mode 100644 index 0000000..926b613 --- /dev/null +++ b/app/components/flash-card-group/component.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); diff --git a/app/components/flash-card-group/template.hbs b/app/components/flash-card-group/template.hbs new file mode 100644 index 0000000..9e0522b --- /dev/null +++ b/app/components/flash-card-group/template.hbs @@ -0,0 +1,16 @@ +
+ {{#each model.flashCards as |flashCard|}} + {{flash-card + model=flashCard + total=cardCount + index=index + onAudioCreated=onAudioCreated + destroyFlashCard=(action destroyFlashCard model) + saveModel=saveModel}} + {{/each}} +
+ +{{ui/icon-button + label="Create" + leftIcon="add" + click=(action createFlashCard model)}} diff --git a/app/components/flash-card/template.hbs b/app/components/flash-card/template.hbs index e37c5c2..5fddfb6 100644 --- a/app/components/flash-card/template.hbs +++ b/app/components/flash-card/template.hbs @@ -8,7 +8,7 @@
{{ui/icon-button label="X" - click=destroyModel}} + click=(action destroyFlashCard model)}}
diff --git a/app/components/navs/lesson-nav/component.js b/app/components/navs/lesson-nav/component.js index 926b613..0449065 100644 --- a/app/components/navs/lesson-nav/component.js +++ b/app/components/navs/lesson-nav/component.js @@ -1,4 +1,9 @@ import Ember from 'ember'; +import computed from 'ember-computed-decorators'; export default Ember.Component.extend({ + @computed('lessonId') + shareLink(lessonId) { + return `https://pin.else.run/lesson/${lessonId}`; + } }); diff --git a/app/components/navs/lesson-nav/template.hbs b/app/components/navs/lesson-nav/template.hbs index 22ed534..85dc1d6 100644 --- a/app/components/navs/lesson-nav/template.hbs +++ b/app/components/navs/lesson-nav/template.hbs @@ -16,5 +16,5 @@ {{ui/icon-button label="Create Flashcard" rightIcon="plus" - click=createFlashCard}} + click=createConversation}} diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/app/controllers/session.js b/app/controllers/session.js deleted file mode 100644 index 68eeacc..0000000 --- a/app/controllers/session.js +++ /dev/null @@ -1,20 +0,0 @@ -import Ember from 'ember'; -import computed from 'ember-computed-decorators'; - -const { isPresent, computed: { alias, sort } } = Ember; - -export default Ember.Controller.extend({ - timestampSorting: ['ts:desc'], - sortedFlashCards: sort('session.flashCards', 'timestampSorting'), - cardCount: alias("sortedFlashCards.length"), - - @computed("sortedFlashCards") - hasFlashCards(collection) { - return isPresent(collection); - }, - - @computed('sessionId') - shareLink(sessionId) { - return `https://pin.else.run/session/${sessionId}`; - } -}); diff --git a/app/models/conversation.js b/app/models/conversation.js new file mode 100644 index 0000000..01ea3a7 --- /dev/null +++ b/app/models/conversation.js @@ -0,0 +1,12 @@ +import DS from 'ember-data'; + +const { empty } = Ember.computed; + +export default DS.Model.extend({ + title: DS.attr('string'), + lesson: DS.belongsTo('lesson'), + position: DS.attr('number'), + flashCards: DS.hasMany('flash-card'), + + isEmpty: empty("flashCards") +}); diff --git a/app/models/flash-card.js b/app/models/flash-card.js index 074817b..561cd4c 100644 --- a/app/models/flash-card.js +++ b/app/models/flash-card.js @@ -6,6 +6,7 @@ export default DS.Model.extend({ english: DS.attr('string'), audioUrl: DS.attr('string'), ts: DS.attr('number'), - - lesson: DS.belongsTo('lesson') + position: DS.attr('number'), + + conversation: DS.belongsTo('conversation') }); diff --git a/app/models/lesson.js b/app/models/lesson.js index 0c798b7..60df22c 100644 --- a/app/models/lesson.js +++ b/app/models/lesson.js @@ -1,6 +1,6 @@ import DS from 'ember-data'; export default DS.Model.extend({ - flashCards: DS.hasMany('flash-card'), + conversations: DS.hasMany('conversation'), date: DS.attr('date') }); diff --git a/app/router.js b/app/router.js index e51855c..46d8eb6 100644 --- a/app/router.js +++ b/app/router.js @@ -7,7 +7,7 @@ const Router = Ember.Router.extend({ }); Router.map(function() { - this.route('session', {path:'/session/:id'}); + this.route('lesson', {path:'/lesson/:id'}); }); export default Router; diff --git a/app/routes/index.js b/app/routes/index.js index 885764a..c59b264 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -3,8 +3,8 @@ import { v4 as uuid} from 'uuid'; export default Ember.Route.extend({ actions: { - createSession() { - this.transitionTo(`/session/${uuid()}`) + createLesson() { + this.transitionTo(`/lesson/${uuid()}`) } } }); diff --git a/app/routes/session.js b/app/routes/lesson.js similarity index 69% rename from app/routes/session.js rename to app/routes/lesson.js index 32f927f..a508600 100644 --- a/app/routes/session.js +++ b/app/routes/lesson.js @@ -5,11 +5,11 @@ import moment from 'moment'; export default Ember.Route.extend({ setupController(controller, model) { - const { record, sessionId, twilioData } = model; + const { record, lessonId, twilioData } = model; - controller.set('session', record); + controller.set('lesson', record); controller.set('twilioData', twilioData); - controller.set('sessionId', sessionId); + controller.set('lessonId', lessonId); this._super(...arguments); }, @@ -28,7 +28,7 @@ export default Ember.Route.extend({ return { record, twilioData, - sessionId: params.id + lessonId: params.id } }, @@ -55,20 +55,32 @@ export default Ember.Route.extend({ }, // @TODO: Not sure why this is failing. - async destroyModel(flashCard, lesson) { + async destroyFlashCard(conversation, flashCard) { await flashCard .destroyRecord() .catch(() => {}); - await lesson.save(); + if(conversation.get("isEmpty")) { + conversation.deleteRecord(); + } + + await conversation.save(); }, - async createFlashCard(lesson) { + async createConversation(lesson) { await this.store - .createRecord('flash-card', { lesson, ts:moment().valueOf() }) + .createRecord('conversation', { lesson }) .save(); await lesson.save(); + }, + + async createFlashCard(conversation) { + await this.store + .createRecord('flash-card', { conversation }) + .save(); + + await conversation.save(); } } }); diff --git a/app/templates/index.hbs b/app/templates/index.hbs index 5783c3e..6b9535d 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -8,7 +8,7 @@
{{ui/icon-button label="Start Lesson" - click=(route-action "createSession") + click=(route-action "createLesson") leftIcon="plus"}}
diff --git a/app/templates/lesson.hbs b/app/templates/lesson.hbs new file mode 100644 index 0000000..c52c91c --- /dev/null +++ b/app/templates/lesson.hbs @@ -0,0 +1,13 @@ +{{navs/lesson-nav + lessonId=lessonId + navigateHome=(route-action "navigateHome") + createConversation=(route-action "createConversation" lesson)}} + +{{conversation-group + onAudioCreated=(route-action 'onAudioCreated') + createFlashCard=(route-action 'createFlashCard') + saveModel=(route-action 'saveModel') + destroyFlashCard=(route-action 'destroyFlashCard') + model=lesson.conversations}} + +{{communication/video-chat twilioData=twilioData}} diff --git a/app/templates/session.hbs b/app/templates/session.hbs deleted file mode 100644 index 3e24ee2..0000000 --- a/app/templates/session.hbs +++ /dev/null @@ -1,22 +0,0 @@ -{{navs/lesson-nav - shareLink=shareLink - navigateHome=(route-action "navigateHome") - createFlashCard=(route-action "createFlashCard" session)}} - -
- {{#if hasFlashCards}} - {{#each sortedFlashCards as |flashCard index|}} - {{flash-card - model=flashCard - total=cardCount - index=index - onAudioCreated=(route-action 'onAudioCreated' flashCard) - destroyModel=(route-action 'destroyModel' flashCard session) - saveModel=(route-action 'saveModel')}} - {{/each}} - {{else}} -

No flash cards yet. Why not create one?

- {{/if}} -
- -{{communication/video-chat twilioData=twilioData}} diff --git a/tests/integration/components/conversation-group/component-test.js b/tests/integration/components/conversation-group/component-test.js new file mode 100644 index 0000000..54fd555 --- /dev/null +++ b/tests/integration/components/conversation-group/component-test.js @@ -0,0 +1,25 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('conversation-group', 'Integration | Component | conversation group', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{conversation-group}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#conversation-group}} + template block text + {{/conversation-group}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); diff --git a/tests/integration/components/flash-card-group/component-test.js b/tests/integration/components/flash-card-group/component-test.js new file mode 100644 index 0000000..ce1651e --- /dev/null +++ b/tests/integration/components/flash-card-group/component-test.js @@ -0,0 +1,25 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('flash-card-group', 'Integration | Component | flash card group', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{flash-card-group}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#flash-card-group}} + template block text + {{/flash-card-group}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); diff --git a/tests/unit/controllers/session-test.js b/tests/unit/controllers/lesson-test.js similarity index 81% rename from tests/unit/controllers/session-test.js rename to tests/unit/controllers/lesson-test.js index f26028e..00f3651 100644 --- a/tests/unit/controllers/session-test.js +++ b/tests/unit/controllers/lesson-test.js @@ -1,6 +1,6 @@ import { moduleFor, test } from 'ember-qunit'; -moduleFor('controller:session', 'Unit | Controller | session', { +moduleFor('controller:lesson', 'Unit | Controller | lesson', { // Specify the other units that are required for this test. // needs: ['controller:foo'] }); diff --git a/tests/unit/models/conversation-test.js b/tests/unit/models/conversation-test.js new file mode 100644 index 0000000..f2d0aeb --- /dev/null +++ b/tests/unit/models/conversation-test.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('conversation', 'Unit | Model | conversation', { + // Specify the other units that are required for this test. + needs: ['model:lesson', 'model:flash-card'] +}); + +test('it exists', function(assert) { + let model = this.subject(); + // let store = this.store(); + assert.ok(!!model); +}); diff --git a/tests/unit/routes/session-test.js b/tests/unit/routes/lesson-test.js similarity index 81% rename from tests/unit/routes/session-test.js rename to tests/unit/routes/lesson-test.js index bd32881..9f0aa77 100644 --- a/tests/unit/routes/session-test.js +++ b/tests/unit/routes/lesson-test.js @@ -1,6 +1,6 @@ import { moduleFor, test } from 'ember-qunit'; -moduleFor('route:session', 'Unit | Route | session', { +moduleFor('route:lesson', 'Unit | Route | lesson', { // Specify the other units that are required for this test. // needs: ['controller:foo'] }); From 7d0b229ff386341b3ed953e56ba7dd89a6f3bffd Mon Sep 17 00:00:00 2001 From: Aram Zadikian Date: Sat, 22 Apr 2017 14:17:06 -0700 Subject: [PATCH 3/3] Various updates --- app/components/audio-recorder/component.js | 44 ++++++-- app/components/audio-recorder/styles.styl | 18 +++ app/components/audio-recorder/template.hbs | 11 +- .../communication/video-chat/component.js | 60 +++++----- .../communication/video-chat/styles.styl | 9 ++ .../communication/video-chat/template.hbs | 6 +- app/components/conversation-group/styles.styl | 13 +++ .../conversation-group/template.hbs | 31 ++--- app/components/flash-card-group/component.js | 16 +++ app/components/flash-card-group/styles.styl | 39 +++++++ app/components/flash-card-group/template.hbs | 33 ++++-- app/components/flash-card/component.js | 22 +--- app/components/flash-card/styles.styl | 66 ++++------- app/components/flash-card/template.hbs | 25 ++--- app/components/navs/lesson-nav/styles.styl | 4 + app/components/navs/lesson-nav/template.hbs | 13 +-- app/components/ui/icon-button/component.js | 2 +- app/components/ui/icon-button/styles.styl | 36 ++++-- app/components/ui/icon-button/template.hbs | 46 ++++---- app/models/conversation.js | 11 +- app/models/flash-card.js | 4 +- app/routes/lesson.js | 106 ++++++++++++++---- app/styles/app.styl | 2 + app/styles/color.styl | 19 ++++ app/styles/layout.styl | 5 +- app/styles/material.styl | 26 +++++ app/styles/reset.styl | 27 +++++ app/styles/variables.styl | 5 - app/templates/lesson.hbs | 6 +- 29 files changed, 483 insertions(+), 222 deletions(-) create mode 100644 app/components/conversation-group/styles.styl create mode 100644 app/components/flash-card-group/styles.styl create mode 100644 app/styles/color.styl create mode 100644 app/styles/material.styl diff --git a/app/components/audio-recorder/component.js b/app/components/audio-recorder/component.js index 1546fe4..c15c771 100644 --- a/app/components/audio-recorder/component.js +++ b/app/components/audio-recorder/component.js @@ -1,23 +1,47 @@ import Ember from 'ember'; +import firebase from 'firebase'; + +const { + computed: { notEmpty } +} = Ember; export default Ember.Component.extend({ + classNames: ['row'], audioRecorder: Ember.inject.service(), + hifi: Ember.inject.service(), + + hasAudio: notEmpty('model.audioUrl'), + saving: false, init() { this._super(...arguments); this.get("audioRecorder").requestAccess(); }, - mouseDown() { - const recorder = this.get("audioRecorder").createRecorder(); - this.set("recorder", recorder); - Ember.run.later(recorder.start, 100); - }, + actions: { + startRecording() { + const recorder = this.get("audioRecorder").createRecorder(); + this.set("recorder", recorder); + Ember.run.later(recorder.start, 100); + }, + + stopRecording() { + this.set("saving", true); + const recorder = this.get("recorder"); + recorder + .stop() + .then(this.get("created")) + .then(() => this.set("saving", false)); + }, + + play() { + const app = firebase.app(); + var storageRef = app.storage().ref(); + var audioRef = storageRef.child(this.get('model.audioUrl')); - mouseUp() { - const recorder = this.get("recorder"); - recorder - .stop() - .then(this.get("created")); + audioRef + .getDownloadURL() + .then(url => this.get("hifi").play(url)); + } } }); diff --git a/app/components/audio-recorder/styles.styl b/app/components/audio-recorder/styles.styl index 687a7da..701aefd 100644 --- a/app/components/audio-recorder/styles.styl +++ b/app/components/audio-recorder/styles.styl @@ -1,2 +1,20 @@ & border: none + +.btn + margin: 0.25em + display: block + border-radius: 50% + padding: 0.5em + background: rgba(off-white, 0.8) + height: 30px + width: 30px + transition: all 0.2s ease-in-out + +.btn:hover + background: rgba(off-white, 1) + +.btn:active + background: hot-pink + opacity: 1 + color: off-white diff --git a/app/components/audio-recorder/template.hbs b/app/components/audio-recorder/template.hbs index 6764e3b..f833fc2 100644 --- a/app/components/audio-recorder/template.hbs +++ b/app/components/audio-recorder/template.hbs @@ -1,3 +1,12 @@ {{ui/icon-button - label="Push & hold to record" + loading=saving + disabled=saving + mouseDown=(action 'startRecording') + mouseUp=(action 'stopRecording') leftIcon="microphone"}} + +{{#if hasAudio}} + {{ui/icon-button + click=(action "play") + leftIcon="play"}} +{{/if}} diff --git a/app/components/communication/video-chat/component.js b/app/components/communication/video-chat/component.js index 5d50bfd..085a101 100644 --- a/app/components/communication/video-chat/component.js +++ b/app/components/communication/video-chat/component.js @@ -3,11 +3,9 @@ import Ember from 'ember'; const Video = Twilio.Video; export default Ember.Component.extend({ - didInsertElement() { + startVideo() { const { token, identity } = this.get("twilioData"); - console.log(token, identity); - Video.connect(token, {name: "my-room"}) .then(room => { @@ -18,47 +16,41 @@ export default Ember.Component.extend({ room.on('participantDisconnected', ::this.participantDisconnected); room.once('disconnected', error => room.participants.forEach(::this.participantDisconnected)); - }, e => { - console.log(e); - }) + }, e => console.log(e)); }, attachTracks(tracks, container) { - tracks.forEach(track => { - container.appendChild(track.attach()) - }); + tracks.forEach(track => this.attachTrack(track, container)); }, - participantConnected(participant) { - this.attachTracks(participant.tracks, this.$(".others:first")[0]) - // console.log('Participant "%s" connected', participant.identity); - // - // const div = document.createElement('div'); - // div.id = participant.sid; - // div.innerText = participant.identity; - // - // participant.on('trackAdded', track => trackAdded(div, track)); - // participant.tracks.forEach(track => trackAdded(div, track)); - // participant.on('trackRemoved', trackRemoved); - // - // document.body.appendChild(div); + attachTrack(track, container) { + container.appendChild(track.attach()); }, - participantDisconnected(participant) { - console.log("Dis", participant); - // console.log('Participant "%s" disconnected', participant.identity); - // - // participant.tracks.forEach(trackRemoved); - // document.getElementById(participant.sid).remove(); + removeTracks(tracks) { + tracks.forEach(track => this.removeTrack(track)); }, - trackAdded(div, track) { - console.log("track added"); - // div.appendChild(track.attach()); + removeTrack(track) { + track.detach().forEach(element => element.remove()); + }, + + participantConnected(participant) { + const container = this.$(".others:first")[0]; + + participant.on('trackAdded', track => ::this.attachTrack(track, container)); + participant.on('trackRemoved', track => ::this.removeTrack(track)); + + this.attachTracks(participant.tracks, container); + }, + + participantDisconnected(participant) { + this.removeTracks(participant.tracks); }, - trackRemoved(track) { - console.log("trackRemoved"); - // track.detach().forEach(element => element.remove()); + actions: { + startVideo() { + this.startVideo(); + } } }); diff --git a/app/components/communication/video-chat/styles.styl b/app/components/communication/video-chat/styles.styl index 6d00b90..a212b12 100644 --- a/app/components/communication/video-chat/styles.styl +++ b/app/components/communication/video-chat/styles.styl @@ -14,3 +14,12 @@ video .vsc-controller display: none + +.start-video + background: dope-blue + // padding: 0.5em + width: 100px + height: 100px + .icon-container + // font-size: 1.5em + color: white diff --git a/app/components/communication/video-chat/template.hbs b/app/components/communication/video-chat/template.hbs index b398bf6..71f24c8 100644 --- a/app/components/communication/video-chat/template.hbs +++ b/app/components/communication/video-chat/template.hbs @@ -1,8 +1,12 @@ -
+
+ {{ui/icon-button + class="start-video" + rightIcon="video-camera" + click=(action startVideo)}}
diff --git a/app/components/conversation-group/styles.styl b/app/components/conversation-group/styles.styl new file mode 100644 index 0000000..eca0332 --- /dev/null +++ b/app/components/conversation-group/styles.styl @@ -0,0 +1,13 @@ +& + margin-top: 3em + +.create-conversation + width: 100% + padding: 1em + color: dark-grey + font-size: 1em + opacity: 0.15 + transition: all 0.2s ease-in-out + +.create-conversation:hover + opacity: 1 diff --git a/app/components/conversation-group/template.hbs b/app/components/conversation-group/template.hbs index 82fdcf4..7a85864 100644 --- a/app/components/conversation-group/template.hbs +++ b/app/components/conversation-group/template.hbs @@ -1,14 +1,19 @@ -
- {{#if hasConversations}} - {{#each sortedConversations as |conversation index|}} - {{flash-card-group - model=conversation - onAudioCreated=onAudioCreated - createFlashCard=createFlashCard - destroyFlashCard=destroyFlashCard - saveModel=saveModel}} - {{/each}} - {{else}} -

No conversations yet. Why not start one?

- {{/if}} +
+ {{ui/icon-button + class='create-conversation' + click=(action createConversation 0) + leftIcon="plus"}} + {{#each sortedConversations as |conversation index|}} + {{flash-card-group + model=conversation + index=(inc index) + onAudioCreated=onAudioCreated + createFlashCard=createFlashCard + destroyFlashCard=destroyFlashCard + saveModel=saveModel}} + {{ui/icon-button + class='create-conversation' + click=(action createConversation (inc index)) + leftIcon="plus"}} + {{/each}}
diff --git a/app/components/flash-card-group/component.js b/app/components/flash-card-group/component.js index 926b613..d5aebf0 100644 --- a/app/components/flash-card-group/component.js +++ b/app/components/flash-card-group/component.js @@ -1,4 +1,20 @@ import Ember from 'ember'; +import computed from 'ember-computed-decorators'; + +const { isPresent, computed: { alias, sort, gt } } = Ember; export default Ember.Component.extend({ + classNames: ['card-1'], + + sortAsc: ["position:asc"], + sortedFlashCards: sort('model.activeFlashCards', 'sortAsc'), + flashCardCount: alias("sortedFlashCards.length"), + hasFlashCards: gt("flashCardCount", 0), + + actions: { + handleUpdate(key, str) { + this.get("model").set(key, str); + this.get("saveModel")(this.get("model")); + } + } }); diff --git a/app/components/flash-card-group/styles.styl b/app/components/flash-card-group/styles.styl new file mode 100644 index 0000000..13191e9 --- /dev/null +++ b/app/components/flash-card-group/styles.styl @@ -0,0 +1,39 @@ +& + width: 100% + padding: 1em + background: dope-blue + height: 24em + +.conversation-header + margin-left: calc(2em - 1em) + color: off-white + font-size: 1.5em + align-items: baseline + .index + margin-right: 0.25em + +.conversation-title + background: 0 + border: 0 + border-bottom: 1px dashed + color: off-white + font-size: 1.3em + width: 16em + +.conversation-title::placeholder + color: rgba(off-white, 0.5) + +.flash-card-container + overflow-x: auto + overflow-y: hidden + margin: 1em 0 + +.create-flash-card + color: white + font-size: 1em + padding: 1em + opacity: 0.15 + transition: all 0.2s ease-in-out + +.create-flash-card:hover + opacity: 1 diff --git a/app/components/flash-card-group/template.hbs b/app/components/flash-card-group/template.hbs index 9e0522b..6ebbb40 100644 --- a/app/components/flash-card-group/template.hbs +++ b/app/components/flash-card-group/template.hbs @@ -1,16 +1,31 @@ -
- {{#each model.flashCards as |flashCard|}} +
+ + {{index}}. + + {{one-way-input model.title + class='conversation-title' + placeholder='What\'s this conversation about...' + update=(action "handleUpdate" "title") + autocomplete="off" + autocorrect="off" + autocapitalize="off" + spellcheck=false}} +
+
+ {{ui/icon-button + class="create-flash-card" + leftIcon="plus" + click=(action createFlashCard model 0)}} + {{#each sortedFlashCards as |flashCard index|}} {{flash-card model=flashCard - total=cardCount - index=index + index=(inc index) onAudioCreated=onAudioCreated destroyFlashCard=(action destroyFlashCard model) saveModel=saveModel}} + {{ui/icon-button + class="create-flash-card" + leftIcon="plus" + click=(action createFlashCard model (inc index))}} {{/each}}
- -{{ui/icon-button - label="Create" - leftIcon="add" - click=(action createFlashCard model)}} diff --git a/app/components/flash-card/component.js b/app/components/flash-card/component.js index 5b366bb..abcd94f 100644 --- a/app/components/flash-card/component.js +++ b/app/components/flash-card/component.js @@ -1,7 +1,6 @@ import Ember from 'ember'; import _ from 'lodash'; import computed from 'ember-computed-decorators'; -import firebase from 'firebase'; const TONE_REGEX = /([aeiouAEIOU][1234])/g; @@ -62,16 +61,7 @@ const { } = Ember; export default Ember.Component.extend({ - classNames: ['stretch'], - - hifi: Ember.inject.service(), - - @computed('total', 'index') - position(total, index) { - return total - index; - }, - - hasAudio: notEmpty('model.audioUrl'), + classNames: ['card-2', 'stretch'], setSelection(elm, start, end) { elm.selectionStart = start; @@ -100,16 +90,6 @@ export default Ember.Component.extend({ handleUpdate(key, str) { this.get("model").set(key, str); this.get("saveModel")(this.get("model")); - }, - - play() { - const app = firebase.app(); - var storageRef = app.storage().ref(); - var audioRef = storageRef.child(this.get('model.audioUrl')); - - audioRef - .getDownloadURL() - .then(url => this.get("hifi").play(url)); } } }); diff --git a/app/components/flash-card/styles.styl b/app/components/flash-card/styles.styl index 6b7deb1..91e868b 100644 --- a/app/components/flash-card/styles.styl +++ b/app/components/flash-card/styles.styl @@ -1,66 +1,46 @@ & - background: #FFB928 + background: dark-orange color: #2E282A - margin-bottom: 1em - border: 5px solid rgba(black, 0.25) - max-width: 80em - -&:nth-child(odd) - background: rgba(#59B5C1, 0.5) + min-width: 18em + width: 18em + margin: 0.5em .inputContainer - width: 100% - margin-right: 1em - .title - font-weight: 600 - height: 1.5em - padding-left: 0.2em - align-items: flex-end - -.inputContainer:last-child - margin-right: 0 + margin-left: 1em + margin-right: calc(1em + 0.25em) textarea + width: 100% resize: none - width: calc(100% - 10px - 0.2em) - padding: 0.2em - font-size: 1.5em - border: 5px solid rgba(black, 0.25) - - +below(950px) - font-size: 1.4em - +below(900px) - font-size: 1.3em - +below(850px) - font-size: 1.2em - +below(800px) - font-size: 1.1em - +below(750px) - font-size: 1em - +below(700px) - margin: 0.25em 0 - font-size: 1.4em - width: calc(100% - 10px - 0.2em) + font-weight: 600 + font-size: 1em + margin-bottom: 0.5em + border: 0 + padding: 0.25em + background: rgba(white, 0.75) .fieldsContainer - margin: 1em + // margin: 0.5em +below(700px) flex-direction: column header background: rgba(white, 0.5) - padding: 0.5em + align-items: baseline + margin-bottom: 1em + .delete + background: none + margin: 0 + padding: 0.5em + .index - margin-left: 1em - font-size: 1.5em + margin-left: 0.5em + font-size: 1.25em .audioUiContainer justify-content: flex-end margin: 1em - .btn - margin-left: 1em - border-radius: 3px hr border: 1px solid rgba(white, 0.5) diff --git a/app/components/flash-card/template.hbs b/app/components/flash-card/template.hbs index 5fddfb6..322488f 100644 --- a/app/components/flash-card/template.hbs +++ b/app/components/flash-card/template.hbs @@ -1,6 +1,6 @@
- {{position}}. + {{index}}.
@@ -8,14 +8,15 @@
{{ui/icon-button label="X" + class='delete' click=(action destroyFlashCard model)}}
-
+
-
汉语
{{one-way-textarea model.chinese + placeholder='汉语...' update=(action "handleUpdate" "chinese") autocomplete="off" autocorrect="off" @@ -24,8 +25,8 @@
-
Pinyin
{{one-way-textarea model.pinyin + placeholder='Pinyin...' class="pinyinEditor" update=(action 'processChange') autocomplete="off" @@ -35,8 +36,8 @@
-
English
{{one-way-textarea model.english + placeholder='English...' update=(action "handleUpdate" "english") autocomplete="off" autocorrect="off" @@ -45,16 +46,8 @@
-
-
- {{audio-recorder - created=onAudioCreated}} - - {{#if hasAudio}} - {{ui/icon-button - label="Play" - click=(action "play") - leftIcon="play"}} - {{/if}} + {{audio-recorder + model=model + created=(action onAudioCreated model)}}
diff --git a/app/components/navs/lesson-nav/styles.styl b/app/components/navs/lesson-nav/styles.styl index c93a10a..aafda8b 100644 --- a/app/components/navs/lesson-nav/styles.styl +++ b/app/components/navs/lesson-nav/styles.styl @@ -1,5 +1,6 @@ & position: relative + z-index: 1000 .uiContainer position: fixed @@ -13,6 +14,9 @@ +below(540px) flex-direction: column +.home-button + color: off-white + .leftContainer margin-left: 2em +below(540px) diff --git a/app/components/navs/lesson-nav/template.hbs b/app/components/navs/lesson-nav/template.hbs index 85dc1d6..a550e3a 100644 --- a/app/components/navs/lesson-nav/template.hbs +++ b/app/components/navs/lesson-nav/template.hbs @@ -1,20 +1,15 @@
{{ui/icon-button + class="home-button" label="Home" - click=navigateHome - leftIcon="arrow-left"}} + click=navigateHome}} - {{#copy-button +
- - {{ui/icon-button - label="Create Flashcard" - rightIcon="plus" - click=createConversation}}
diff --git a/app/components/ui/icon-button/component.js b/app/components/ui/icon-button/component.js index c566d49..55b8a36 100644 --- a/app/components/ui/icon-button/component.js +++ b/app/components/ui/icon-button/component.js @@ -3,7 +3,7 @@ import Ember from "ember"; const { notEmpty } = Ember.computed; export default Ember.Component.extend({ - classNames: ["row", "btn"], + classNames: ["btn"], hasLabel: notEmpty("label"), hasLeftIcon: notEmpty("leftIcon"), diff --git a/app/components/ui/icon-button/styles.styl b/app/components/ui/icon-button/styles.styl index 18ae556..d6e5b9f 100644 --- a/app/components/ui/icon-button/styles.styl +++ b/app/components/ui/icon-button/styles.styl @@ -2,8 +2,6 @@ cursor: pointer align-items: center justify-content: center - padding: 0.5rem - background: #F8F9F2 &:active opacity: 0.5 @@ -11,13 +9,33 @@ .label font-size: 1rem -.spacer - margin-right: 0.5rem - -.iconContainer - font-size: 0.5rem +.icon-container align-items: center justify-content: center -.content - padding: 0 1em +.spin-clockwise { + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} + +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/app/components/ui/icon-button/template.hbs b/app/components/ui/icon-button/template.hbs index 853475f..438ac10 100644 --- a/app/components/ui/icon-button/template.hbs +++ b/app/components/ui/icon-button/template.hbs @@ -1,25 +1,33 @@ -
- {{#if hasLeftIcon}} -
- {{fa-icon leftIcon}} -
- {{/if}} +
+ {{#if loading}} +
+ {{fa-icon 'spinner'}} +
+ {{else}} + {{#if hasLeftIcon}} +
+ {{fa-icon leftIcon}} +
+ {{/if}} - {{#if (and hasLabel hasLeftIcon)}} -
- {{/if}} + {{#if (and hasLabel hasLeftIcon)}} +
+ {{/if}} - {{#if hasLabel}} - {{label}} - {{/if}} + {{#if hasLabel}} + {{label}} + {{/if}} + + {{#if (and hasLabel hasRightIcon)}} +
+ {{/if}} + + {{#if hasRightIcon}} +
+ {{fa-icon rightIcon}} +
+ {{/if}} - {{#if (and hasLabel hasRightIcon)}} -
- {{/if}} - {{#if hasRightIcon}} -
- {{fa-icon rightIcon}} -
{{/if}}
diff --git a/app/models/conversation.js b/app/models/conversation.js index 01ea3a7..0a3f425 100644 --- a/app/models/conversation.js +++ b/app/models/conversation.js @@ -1,12 +1,17 @@ import DS from 'ember-data'; +import computed from 'ember-computed-decorators'; -const { empty } = Ember.computed; +const { empty, filterBy } = Ember.computed; export default DS.Model.extend({ title: DS.attr('string'), lesson: DS.belongsTo('lesson'), - position: DS.attr('number'), + ts: DS.attr('number'), + position: DS.attr('number', {defaultValue: 1}), + flashCards: DS.hasMany('flash-card'), - isEmpty: empty("flashCards") + activeFlashCards: filterBy('flashCards', 'isDeleted', false), + + isEmpty: empty("activeFlashCards") }); diff --git a/app/models/flash-card.js b/app/models/flash-card.js index 561cd4c..7b0463d 100644 --- a/app/models/flash-card.js +++ b/app/models/flash-card.js @@ -6,7 +6,7 @@ export default DS.Model.extend({ english: DS.attr('string'), audioUrl: DS.attr('string'), ts: DS.attr('number'), - position: DS.attr('number'), - + position: DS.attr('number', {defaultValue: 1}), + conversation: DS.belongsTo('conversation') }); diff --git a/app/routes/lesson.js b/app/routes/lesson.js index a508600..6aff8b2 100644 --- a/app/routes/lesson.js +++ b/app/routes/lesson.js @@ -2,6 +2,7 @@ import Ember from 'ember'; import firebase from 'firebase'; import { v4 as uuid } from 'uuid'; import moment from 'moment'; +import _ from 'lodash'; export default Ember.Route.extend({ setupController(controller, model) { @@ -20,9 +21,14 @@ export default Ember.Route.extend({ const record = await this.store.findRecord('lesson', params.id) .catch(() => { - return this.store - .createRecord('lesson', {id:params.id, date:new Date()}) - .save(); + const lesson = this.store.createRecord('lesson', {id:params.id, date:new Date()}), + conversation = this.store.createRecord('conversation', {lesson}), + flashCard = this.store.createRecord('flash-card', {conversation}); + + return lesson.save() + .then(lesson => conversation.save()) + .then(conversation => flashCard.save()) + .then(flashCard => lesson); }); return { @@ -32,6 +38,46 @@ export default Ember.Route.extend({ } }, + async createConversation(lesson, position = 0) { + const conversations = await lesson.get("conversations"); + + const sortedConversations = conversations.sortBy("position"); + + const prevCard = sortedConversations[position - 1]; + const nextCard = sortedConversations[position]; + + const prev = Ember.isPresent(prevCard) ? prevCard.get("position") : undefined; + const next = Ember.isPresent(nextCard) ? nextCard.get("position") : undefined; + + let newPosition; + + if(prev === undefined && next !== undefined) { + newPosition = next/2; + } + + if(prev !== undefined && next === undefined) { + newPosition = prev + 1; + } + + if(prev !== undefined && next !== undefined) { + newPosition = (next - prev)/2 + prev; + } + + if(prev === undefined && next === undefined) { + newPosition = 1; + } + + const conversation = this.store + .createRecord('conversation', { lesson, position: newPosition }); + + const flashCard = this.store + .createRecord('flash-card', { conversation }); + + await conversation.save(); + await flashCard.save(); + await lesson.save(); + }, + actions: { onAudioCreated(model, blob) { const app = firebase.app(); @@ -40,9 +86,9 @@ export default Ember.Route.extend({ const path = `audio/${uuid()}.wav`; var audioRef = storageRef.child(path); - audioRef.put(blob).then(() => { + return audioRef.put(blob).then(() => { model.set("audioUrl", path); - model.save(); + return model.save(); }); }, @@ -54,32 +100,54 @@ export default Ember.Route.extend({ model.save(); }, - // @TODO: Not sure why this is failing. async destroyFlashCard(conversation, flashCard) { - await flashCard - .destroyRecord() - .catch(() => {}); + flashCard.deleteRecord(); if(conversation.get("isEmpty")) { conversation.deleteRecord(); } + await flashCard.save(); await conversation.save(); }, - async createConversation(lesson) { - await this.store - .createRecord('conversation', { lesson }) - .save(); - - await lesson.save(); + createConversation(lesson, position) { + this.createConversation(lesson, position); }, - async createFlashCard(conversation) { - await this.store - .createRecord('flash-card', { conversation }) - .save(); + async createFlashCard(conversation, position) { + const flashCards = await conversation.get("flashCards"); + + const sortedFlashCards = flashCards.sortBy("position"); + + const leftCard = sortedFlashCards[position - 1]; + const rightCard = sortedFlashCards[position]; + + const left = Ember.isPresent(leftCard) ? leftCard.get("position") : undefined; + const right = Ember.isPresent(rightCard) ? rightCard.get("position") : undefined; + + let newPosition; + + if(left === undefined && right !== undefined) { + newPosition = right/2; + } + + if(left !== undefined && right === undefined) { + newPosition = left + 1; + } + + if(left !== undefined && right !== undefined) { + newPosition = (right - left)/2 + left; + } + + if(left === undefined && right === undefined) { + newPosition = 1; + } + + const flashCard = this.store + .createRecord('flash-card', { conversation, position: newPosition }); + await flashCard.save(); await conversation.save(); } } diff --git a/app/styles/app.styl b/app/styles/app.styl index 093c11a..22d13f3 100644 --- a/app/styles/app.styl +++ b/app/styles/app.styl @@ -1,8 +1,10 @@ @lost flexbox flex @import "variables" +@import "color" @import "reset" @import "layout" @import "typography" +@import "material" @import "utils" @import "pod-styles" diff --git a/app/styles/color.styl b/app/styles/color.styl new file mode 100644 index 0000000..6e74a2a --- /dev/null +++ b/app/styles/color.styl @@ -0,0 +1,19 @@ +body-color = #F4F4F4 +dope-grey = #1E1E1E +dope-pink = #F94848 +dope-green = #00ae9c + +slate = #232323 +off-white = #F9F9F9 +light-grey = #C9C9C9 +medium-grey = #EBEDEC +dark-grey = #4C4C4C +sky-blue = #00B3DD +baby-blue = #BDEFFF +light-blue = #F3FDFF +light-green = #DEFFEE +dark-green = #4ACE86 +dark-orange = #FFB928 +hot-pink = #FF646C +dope-blue = #4DA6FF +light-orange = #F5E385 diff --git a/app/styles/layout.styl b/app/styles/layout.styl index c034fe1..cd07419 100644 --- a/app/styles/layout.styl +++ b/app/styles/layout.styl @@ -22,6 +22,7 @@ .stretch width: 100% + height: 100% .space-between justify-content: space-between @@ -39,10 +40,6 @@ for num in (1..9) flex: num // Refactor out into components -.flashCardContainer - margin-top: 4em - padding: 1em - .landingContainer padding: 5em max-width: 60em diff --git a/app/styles/material.styl b/app/styles/material.styl new file mode 100644 index 0000000..80c4744 --- /dev/null +++ b/app/styles/material.styl @@ -0,0 +1,26 @@ +.card + border-radius: 2px + transition: all 0.2s ease-in-out + +.card-1 + @extend .card + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24) + +.card-2 + @extend .card + box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23) + + +.card-3 + @extend .card + box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23) + + +.card-4 + @extend .card + box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22) + + +.card-5 + @extend .card + box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22) diff --git a/app/styles/reset.styl b/app/styles/reset.styl index 32b8e0e..e19c4a2 100644 --- a/app/styles/reset.styl +++ b/app/styles/reset.styl @@ -16,3 +16,30 @@ button margin: 0 padding: 0 border: 0 + +::-webkit-scrollbar + width: 11px + height: 11px + +::-webkit-scrollbar-button + width: 0px + height: 0px + +::-webkit-scrollbar-thumb + background: #e1e1e1 + border: 0px none white + border-radius: 50px + +::-webkit-scrollbar-thumb:hover + background: white + +::-webkit-scrollbar-thumb:active + background: rgba(white, 0.9) + +::-webkit-scrollbar-track + background: rgba(white, 0.5) + border: 0px none white + border-radius: 50px + +::-webkit-scrollbar-corner + background: transparent diff --git a/app/styles/variables.styl b/app/styles/variables.styl index a65d37f..2812e90 100644 --- a/app/styles/variables.styl +++ b/app/styles/variables.styl @@ -1,6 +1 @@ rupture.enable-em-breakpoints = true - -body-color = #F4F4F4 -dope-grey = #1E1E1E -dope-pink = #F94848 -dope-green = #00ae9c diff --git a/app/templates/lesson.hbs b/app/templates/lesson.hbs index c52c91c..1a58a81 100644 --- a/app/templates/lesson.hbs +++ b/app/templates/lesson.hbs @@ -1,13 +1,13 @@ {{navs/lesson-nav lessonId=lessonId - navigateHome=(route-action "navigateHome") - createConversation=(route-action "createConversation" lesson)}} + navigateHome=(route-action "navigateHome")}} {{conversation-group + createConversation=(route-action "createConversation" lesson) onAudioCreated=(route-action 'onAudioCreated') createFlashCard=(route-action 'createFlashCard') saveModel=(route-action 'saveModel') destroyFlashCard=(route-action 'destroyFlashCard') model=lesson.conversations}} -{{communication/video-chat twilioData=twilioData}} +