diff --git a/app/pods/components/animate/component.js b/app/pods/components/animate/component.js | |
new file mode 100644 | |
index 00000000..c959f943 | |
--- /dev/null | |
+++ b/app/pods/components/animate/component.js | |
@@ -0,0 +1,21 @@ | |
+import Component from "@ember/component"; | |
+import { fadeIn } from "ember-animated/motions/opacity"; | |
+import { wait } from "ember-animated"; | |
+import { easeExpOut } from "d3-ease"; | |
+ | |
+export default Component.extend({ | |
+ *fade({ duration, receivedSprites }) { | |
+ receivedSprites.forEach(sprite => { | |
+ sprite.applyStyles({ | |
+ opacity: 0 | |
+ }); | |
+ sprite.moveToFinalPosition(); | |
+ }); | |
+ | |
+ yield wait(duration * 0.5); | |
+ | |
+ receivedSprites.forEach(sprite => { | |
+ fadeIn(sprite, { from: 0, easing: easeExpOut }); | |
+ }); | |
+ } | |
+}); | |
diff --git a/app/pods/components/animate/template.hbs b/app/pods/components/animate/template.hbs | |
new file mode 100644 | |
index 00000000..cc6314b6 | |
--- /dev/null | |
+++ b/app/pods/components/animate/template.hbs | |
@@ -0,0 +1,3 @@ | |
+{{#animated-value @model use=this.fade}} | |
+ {{yield}} | |
+{{/animated-value}} | |
diff --git a/app/pods/components/ui-video-hero/component.js b/app/pods/components/ui-video-hero/component.js | |
index 6eb1283c..f1a60ae7 100644 | |
--- a/app/pods/components/ui-video-hero/component.js | |
+++ b/app/pods/components/ui-video-hero/component.js | |
@@ -1,6 +1,9 @@ | |
import { inject as service } from "@ember/service"; | |
import Component from "@ember/component"; | |
import diffAttrs from "ember-diff-attrs"; | |
+import resize from "ember-animated/motions/resize"; | |
+import move from "ember-animated/motions/move"; | |
+import { easeExpOut } from "d3-ease"; | |
export default Component.extend({ | |
video: null, | |
@@ -11,6 +14,17 @@ export default Component.extend({ | |
metrics: service(), | |
state: service("components/ui-video-hero"), | |
+ *transition({ duration, receivedSprites }) { | |
+ receivedSprites.forEach(sprite => { | |
+ sprite.applyStyles({ | |
+ zIndex: 1 | |
+ }); | |
+ | |
+ resize(sprite, { easing: easeExpOut, duration: duration * 0.5 }); | |
+ move(sprite, { easing: easeExpOut, duration: duration * 0.5 }); | |
+ }); | |
+ }, | |
+ | |
didInsertElement() { | |
this.setProperties({ | |
hasTrackedPlay: false, | |
diff --git a/app/pods/components/ui-video-hero/template.hbs b/app/pods/components/ui-video-hero/template.hbs | |
index 86494dc2..9cb97dc3 100644 | |
--- a/app/pods/components/ui-video-hero/template.hbs | |
+++ b/app/pods/components/ui-video-hero/template.hbs | |
@@ -13,7 +13,11 @@ | |
{{#can-watch-clip clip=video as |canWatch|}} | |
- <div class="bg-true-black"> | |
+ <div class="relative"> | |
+ <Animate @model={{video}}> | |
+ <div class='absolute pin bg-true-black'></div> | |
+ </Animate> | |
+ | |
{{#ui-container style='video gutterless'}} | |
{{#if video.isComingSoon}} | |
@@ -115,16 +119,21 @@ | |
{{! this should be a component that uses the js api }} | |
{{{video.vimeoVideo.embed}}} | |
{{else}} | |
- {{video-player | |
- sources=video.encodes | |
- poster=(img-url video.posterS3Key w=1280) | |
- data-test-id="video-player" | |
- playbackRate=state.playbackRate | |
- did-add-video-element=(action 'setVideoElement') | |
- on-end=(action 'onEnd') | |
- on-play=(action 'onPlay') | |
- on-pause=(action 'onPause') | |
- on-percent-complete=(action 'onPercentComplete')}} | |
+ <AnimatedContainer> | |
+ {{#animated-value video use=this.transition}} | |
+ {{video-player | |
+ sources=video.encodes | |
+ video=video | |
+ poster=(img-url video.posterS3Key w=1280) | |
+ data-test-id="video-player" | |
+ playbackRate=state.playbackRate | |
+ did-add-video-element=(action 'setVideoElement') | |
+ on-end=(action 'onEnd') | |
+ on-play=(action 'onPlay') | |
+ on-pause=(action 'onPause') | |
+ on-percent-complete=(action 'onPercentComplete')}} | |
+ {{/animated-value}} | |
+ </AnimatedContainer> | |
{{/if}} | |
{{/with-features}} | |
@@ -136,9 +145,12 @@ | |
{{/can-watch-clip}} | |
- | |
-{{#if screen.isSmallAndDown}} | |
- {{ui-video-hero/control-bar-collapsible clip=video}} | |
-{{else}} | |
- {{ui-video-hero/control-bar clip=video}} | |
-{{/if}} | |
+<AnimatedContainer> | |
+ <Animate @model={{video}}> | |
+ {{#if screen.isSmallAndDown}} | |
+ {{ui-video-hero/control-bar-collapsible clip=video}} | |
+ {{else}} | |
+ {{ui-video-hero/control-bar clip=video}} | |
+ {{/if}} | |
+ </Animate> | |
+</AnimatedContainer> | |
diff --git a/app/pods/components/video-player/template.hbs b/app/pods/components/video-player/template.hbs | |
index 5f609bea..00aabf11 100644 | |
--- a/app/pods/components/video-player/template.hbs | |
+++ b/app/pods/components/video-player/template.hbs | |
@@ -23,9 +23,11 @@ | |
{{else if isStopped}} | |
- <div class="video-player__play-button"> | |
- {{fa-icon 'play' prefix="fas"}} | |
- </div> | |
+ <Animate @model={{video}}> | |
+ <div class="video-player__play-button"> | |
+ {{fa-icon 'play' prefix="fas"}} | |
+ </div> | |
+ </Animate> | |
{{/if}} | |
diff --git a/app/pods/podcast/components/podcast-card/body/template.hbs b/app/pods/podcast/components/podcast-card/body/template.hbs | |
new file mode 100644 | |
index 00000000..8ec86779 | |
--- /dev/null | |
+++ b/app/pods/podcast/components/podcast-card/body/template.hbs | |
@@ -0,0 +1,22 @@ | |
+<div class='bg-white p-3 xs:px-20px'> | |
+ <div class="flex text-8 text-grey-dark font-semibold leading-normal"> | |
+ <span class="uppercase"> | |
+ {{moment-format episode.publishedAt 'MMMM D, YYYY'}} | |
+ </span> | |
+ <div class="ml-auto"> | |
+ Ep. {{episode.position}} | |
+ </div> | |
+ </div> | |
+ | |
+ {{ui-spacer style='xs'}} | |
+ | |
+ {{#ui-p style='leading-tight bold marginless'}} | |
+ {{episode.title}} | |
+ {{/ui-p}} | |
+ | |
+ {{ui-spacer style='xs'}} | |
+ | |
+ {{#ui-p style='small subtle marginless leading-1.4'}} | |
+ {{truncate episode.description words=14}}... | |
+ {{/ui-p}} | |
+</div> | |
diff --git a/app/pods/podcast/components/podcast-card/image/template.hbs b/app/pods/podcast/components/podcast-card/image/template.hbs | |
new file mode 100644 | |
index 00000000..ace13c9e | |
--- /dev/null | |
+++ b/app/pods/podcast/components/podcast-card/image/template.hbs | |
@@ -0,0 +1,10 @@ | |
+{{#aspect-ratio ratio='16:9'}} | |
+ <div | |
+ class="h-full w-full bg-cover rounded-t" | |
+ style={{html-safe (concat | |
+ 'background-image: url(' | |
+ (img-url episode.posterS3Key w=760) | |
+ ')' | |
+ )}} | |
+ ></div> | |
+{{/aspect-ratio}} | |
diff --git a/app/pods/podcast/components/podcast-card/template.hbs b/app/pods/podcast/components/podcast-card/template.hbs | |
index dabe57e5..d5fdf374 100644 | |
--- a/app/pods/podcast/components/podcast-card/template.hbs | |
+++ b/app/pods/podcast/components/podcast-card/template.hbs | |
@@ -4,39 +4,17 @@ | |
shadow-pickupable hover:shadow-picked-up hover:nudge-u-sm | |
transition rounded overflow-hidden | |
"> | |
- {{#aspect-ratio ratio='16:9'}} | |
- <div | |
- class="h-full w-full bg-cover rounded-t" | |
- style={{html-safe (concat | |
- 'background-image: url(' | |
- (img-url episode.posterS3Key w=760) | |
- ')' | |
- )}} | |
- ></div> | |
- {{/aspect-ratio}} | |
- <div class='bg-white p-3 xs:px-20px'> | |
- <div class="flex text-8 text-grey-dark font-semibold leading-normal"> | |
- <span class="uppercase"> | |
- {{moment-format episode.publishedAt 'MMMM D, YYYY'}} | |
- </span> | |
- <div class="ml-auto"> | |
- Ep. {{episode.position}} | |
- </div> | |
- </div> | |
+ {{#if (has-block)}} | |
+ {{yield (hash | |
+ Image=(component 'podcast/components/podcast-card/image' episode=episode) | |
+ Body=(component 'podcast/components/podcast-card/body' episode=episode) | |
+ )}} | |
+ {{else}} | |
+ <Podcast::Components::PodcastCard::Image @episode={{episode}} /> | |
+ <Podcast::Components::PodcastCard::Body @episode={{episode}} /> | |
+ {{/if}} | |
- {{ui-spacer style='xs'}} | |
- | |
- {{#ui-p style='leading-tight bold marginless'}} | |
- {{episode.title}} | |
- {{/ui-p}} | |
- | |
- {{ui-spacer style='xs'}} | |
- | |
- {{#ui-p style='small subtle marginless leading-1.4'}} | |
- {{truncate episode.description words=14}}... | |
- {{/ui-p}} | |
- </div> | |
</div> | |
{{/ui-link-to}} | |
</div> | |
diff --git a/app/pods/podcast/episode/controller.js b/app/pods/podcast/episode/controller.js | |
new file mode 100644 | |
index 00000000..de74ea9b | |
--- /dev/null | |
+++ b/app/pods/podcast/episode/controller.js | |
@@ -0,0 +1,15 @@ | |
+import Controller from "@ember/controller"; | |
+ | |
+export default Controller.extend({ | |
+ *fade({ receivedSprites }) { | |
+ console.log("fade: ", arguments[0]); | |
+ receivedSprites.forEach(sprite => { | |
+ sprite.applyStyles({ | |
+ opacity: 0 | |
+ }); | |
+ sprite.moveToFinalPosition(); | |
+ | |
+ fadeIn(sprite, { from: 0 }); | |
+ }); | |
+ } | |
+}); | |
diff --git a/app/pods/podcast/episode/template.hbs b/app/pods/podcast/episode/template.hbs | |
index 87434049..4e286362 100644 | |
--- a/app/pods/podcast/episode/template.hbs | |
+++ b/app/pods/podcast/episode/template.hbs | |
@@ -1,104 +1,108 @@ | |
{{ui-video-hero video=model}} | |
-{{#ui-container}} | |
- <div class="text-5 max-w-measure-wide mx-auto"> | |
- <div class="my-4 pb-2 lg:flex justify-between"> | |
- <div class="w-full flex-no-shrink"> | |
+<AnimatedContainer> | |
+ <Animate @model={{model}}> | |
+ {{#ui-container}} | |
+ <div class="text-5 max-w-measure-wide mx-auto"> | |
+ <div class="py-4 pb-2 lg:flex justify-between"> | |
+ <div class="w-full flex-no-shrink"> | |
- {{#ui-p style='uppercase xxs strong subtle marginless'}} | |
- {{moment-format model.publishedAt 'MMMM D, YYYY'}} | |
- {{/ui-p}} | |
+ {{#ui-p style='uppercase xxs strong subtle marginless'}} | |
+ {{moment-format model.publishedAt 'MMMM D, YYYY'}} | |
+ {{/ui-p}} | |
- {{ui-spacer style='xs'}} | |
+ {{ui-spacer style='xs'}} | |
- {{#ui-title style='headline marginless'}} | |
- <span class="leading-none"> | |
- {{model.title}} | |
- </span> | |
- {{/ui-title}} | |
+ {{#ui-title style='headline marginless'}} | |
+ <span class="leading-none"> | |
+ {{model.title}} | |
+ </span> | |
+ {{/ui-title}} | |
- <div class="py-1"></div> | |
+ <div class="py-1"></div> | |
- <p class="text-6 font-medium"> | |
- Episode {{model.position}} | |
- <span class='px-1'>//</span> | |
- The EmberMap Podcast | |
- </p> | |
+ <p class="text-6 font-medium"> | |
+ Episode {{model.position}} | |
+ <span class='px-1'>//</span> | |
+ The EmberMap Podcast | |
+ </p> | |
- {{ui-hr}} | |
+ {{ui-hr}} | |
- {{ui-spacer style='small'}} | |
+ {{ui-spacer style='small'}} | |
- <p class="text-5 md:text-4 mb-3" data-test-id="episode-description"> | |
- {{model.description}} | |
- </p> | |
+ <p class="text-5 md:text-4 mb-3" data-test-id="episode-description"> | |
+ {{model.description}} | |
+ </p> | |
- {{ui-spacer style='lg'}} | |
+ {{ui-spacer style='lg'}} | |
- {{#ui-title}} | |
- How to listen | |
- {{/ui-title}} | |
+ {{#ui-title}} | |
+ How to listen | |
+ {{/ui-title}} | |
- <p class="text-5 md:text-4 mb-3"> | |
- Watch above, or find us on your favorite channel: | |
- </p> | |
- | |
- <div class="flex flex-wrap"> | |
- <a href="https://itunes.apple.com/us/podcast/the-embermap-podcast/id1288274408?mt=2" class='mr-1'> | |
- {{svg-jar 'apple-podcasts-listen-badge' height="34" width=null}} | |
- </a> | |
- <a href="https://www.youtube.com/playlist?list=PLc_oqaQ4aMWGLL7iu2IoU30aOC9pykK_L" class='mr-1'> | |
- {{svg-jar 'youtube-watch-badge' height="34" width=null}} | |
- </a> | |
- </div> | |
+ <p class="text-5 md:text-4 mb-3"> | |
+ Watch above, or find us on your favorite channel: | |
+ </p> | |
- {{ui-spacer style='lg'}} | |
+ <div class="flex flex-wrap"> | |
+ <a href="https://itunes.apple.com/us/podcast/the-embermap-podcast/id1288274408?mt=2" class='mr-1'> | |
+ {{svg-jar 'apple-podcasts-listen-badge' height="34" width=null}} | |
+ </a> | |
+ <a href="https://www.youtube.com/playlist?list=PLc_oqaQ4aMWGLL7iu2IoU30aOC9pykK_L" class='mr-1'> | |
+ {{svg-jar 'youtube-watch-badge' height="34" width=null}} | |
+ </a> | |
+ </div> | |
- {{#ui-title}} | |
- Show notes | |
- {{/ui-title}} | |
+ {{ui-spacer style='lg'}} | |
- <div data-test-id="episode-summary"> | |
- {{ui-md source=model.summary}} | |
- </div> | |
+ {{#ui-title}} | |
+ Show notes | |
+ {{/ui-title}} | |
- </div> | |
- </div> | |
- </div> | |
-{{/ui-container}} | |
- | |
-<div class="bg-grey-lightest py-5"> | |
- {{#ui-container}} | |
- {{#ui-title style='center marginless'}} | |
- Recent episodes | |
- {{/ui-title}} | |
- | |
- <LoadRecords | |
- @modelName='podcast-episode' | |
- @params={{hash | |
- sort='-position' | |
- page=(hash limit=4) | |
- }} | |
- @backgroundReload={{false}} | |
- as |isLoading isError latestEpisodes|> | |
- | |
- {{#if latestEpisodes}} | |
- <Grid @columns='lg:3' @gutters='lg:3' as |grid|> | |
- {{#each (take 3 (without model latestEpisodes)) as |episode|}} | |
- <grid.Column> | |
- <Podcast::Components::PodcastCard @episode={{episode}} /> | |
- </grid.Column> | |
- {{/each}} | |
- </Grid> | |
- | |
- <div class="mt-5"> | |
- <p class='text-center'> | |
- or {{#link-to 'podcast' class='text-black font-semibold'}}View all episodes{{/link-to}} | |
- </p> | |
+ <div data-test-id="episode-summary"> | |
+ {{ui-md source=model.summary}} | |
+ </div> | |
+ | |
+ </div> | |
</div> | |
- {{/if}} | |
+ </div> | |
+ {{/ui-container}} | |
- </LoadRecords> | |
+ <div class="bg-grey-lightest py-5"> | |
+ {{#ui-container}} | |
+ {{#ui-title style='center marginless'}} | |
+ Recent episodes | |
+ {{/ui-title}} | |
- {{/ui-container}} | |
-</div> | |
+ <LoadRecords | |
+ @modelName='podcast-episode' | |
+ @params={{hash | |
+ sort='-position' | |
+ page=(hash limit=4) | |
+ }} | |
+ @backgroundReload={{false}} | |
+ as |isLoading isError latestEpisodes|> | |
+ | |
+ {{#if latestEpisodes}} | |
+ <Grid @columns='lg:3' @gutters='lg:3' as |grid|> | |
+ {{#each (take 3 (without model latestEpisodes)) as |episode|}} | |
+ <grid.Column> | |
+ <Podcast::Components::PodcastCard @episode={{episode}} /> | |
+ </grid.Column> | |
+ {{/each}} | |
+ </Grid> | |
+ | |
+ <div class="mt-5"> | |
+ <p class='text-center'> | |
+ or {{#link-to 'podcast' class='text-black font-semibold'}}View all episodes{{/link-to}} | |
+ </p> | |
+ </div> | |
+ {{/if}} | |
+ | |
+ </LoadRecords> | |
+ | |
+ {{/ui-container}} | |
+ </div> | |
+ </Animate> | |
+</AnimatedContainer> | |
diff --git a/app/pods/podcast/index/controller.js b/app/pods/podcast/index/controller.js | |
index 4b91afa9..963a4a64 100644 | |
--- a/app/pods/podcast/index/controller.js | |
+++ b/app/pods/podcast/index/controller.js | |
@@ -14,5 +14,9 @@ export default Controller.extend({ | |
episodes: computed("sortedEpisodes.[]", function() { | |
return this.sortedEpisodes.slice(1); | |
- }) | |
+ }), | |
+ | |
+ *transition() { | |
+ console.log("index: ", arguments[0]); | |
+ } | |
}); | |
diff --git a/app/pods/podcast/index/template.hbs b/app/pods/podcast/index/template.hbs | |
index 3f50669f..6a61675a 100644 | |
--- a/app/pods/podcast/index/template.hbs | |
+++ b/app/pods/podcast/index/template.hbs | |
@@ -40,7 +40,12 @@ | |
<Grid @columns='md:2 lg:3' @gutters='md:3' as |grid|> | |
{{#each sortedEpisodes as |episode|}} | |
<grid.Column> | |
- <Podcast::Components::PodcastCard @episode={{episode}} /> | |
+ <Podcast::Components::PodcastCard @episode={{episode}} as |card|> | |
+ {{#animated-value episode use=this.transition}} | |
+ <card.Image /> | |
+ {{/animated-value}} | |
+ <card.Body /> | |
+ </Podcast::Components::PodcastCard> | |
</grid.Column> | |
{{/each}} | |
</Grid> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment