Skip to content

Commit

Permalink
feat: home discover animation (#463)
Browse files Browse the repository at this point in the history
* 🚧 (HomeDiscover) lottie animation

* 🔥 (lottie) remove json

* fix: lottie ref

* ✨ (HomeDiscover) anim

* ♻️ (HomeDiscover) replace the 5 animations in one and add segments

* ✨ (HomeDiscover) update json lottie path

* ✨ (HomeDiscover) play/pause animation on scoll

* ✨ (HomeDiscover) anim according color mode

* ✨ (HomeDiscover) change threshold for anim visibility

* 🐛 (HomeDiscover) add any type on useContext to avoid lint error

* ♻️ (HomeDiscover) change layout anim size

Co-authored-by: Farnabaz <farnabaz@gmail.com>
Co-authored-by: Yaël GUILLOUX <yael.guilloux@gmail.com>
  • Loading branch information
3 people authored Jun 22, 2021
1 parent e1a1a2b commit eb8584a
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 38 deletions.
203 changes: 165 additions & 38 deletions nuxtjs.org/components/HomeDiscover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
alt="A landscape image"
/>

<HomeSection class="py-20 light:bg-gray-50 dark:bg-secondary-darkest">
<HomeSection class="pt-40 light:bg-gray-50 dark:bg-secondary-darkest">
<template #section-content>
<SectionContent class="col-span-6 items-center md:items-start justify-center">
<SectionContent class="col-span-12 justify-center">
<template #category>
<CategoryLabel :label="category" />
</template>
Expand All @@ -37,32 +37,53 @@
</template>

<template #paragraph>
<p class="pt-2 pb-8 text-center md:text-left font-normal text-body-base md:text-body-lg 2xl:text-body-xl">
<Markdown slot="description" unwrap="p" />
</p>
<div class="flex justify-center md:justify-start">
<SectionButton
:to="primary.url"
:aria-label="primary.text"
size="md"
class="bg-primary-green text-gray-800 hover:bg-green-300 focus:bg-green-300"
:icon-left="primary.icon"
>
{{ primary.text }}
</SectionButton>
</div>
<SectionDescription class="py-4 w-full" size="md">
Nuxt is an Open Source web framework based on official Vue.js libraries, Node.js and using powerful
development tools such as Vite, Webpack, Babel and PostCSS. Nuxt's purpose is to make web application
development intuitive and performant with a great developer experience in mind.
</SectionDescription>
</template>
</SectionContent>
</template>

<template #right-illustration>
<div class="col-span-6 w-full flex justify-center items-center md:justify-end">
<img
class="sm:w-3/5 md:w-3/4 lg:w-4/6 xl:w-3/5"
loading="lazy"
src="~/static/img/home/discover/modules/discover-modules.svg"
alt="Image of a simplified diagram of how Nuxt works"
/>
<div class="col-span-12">
<div class="flex flex-col md:flex-row justify-center items-center">
<div
class="
grid grid-cols-3
gap-8
md:gap-0 md:flex md:flex-col
items-center
md:items-start
space-x-4
md:space-x-0 md:space-y-2 md:w-2/5
xl:w-1/5
"
>
<div v-for="(animation, index) in animations" :key="animation.name">
<div class="flex flex-col-reverse md:flex-row md:flex-row justify-center items-center space-x-2">
<img
:src="`/img/home/discover/diamond.svg`"
alt="diamond"
class="h-4 w-4 opacity-0"
:class="{ 'opacity-100': index === currentIndex }"
/>
<button
class="font-semibold"
:class="
index === currentIndex ? 'text-gray-700 dark:text-white' : 'text-gray-400 dark:text-gray-400'
"
@click="changeAnimation(index)"
>
{{ animation.name }}
</button>
</div>
</div>
</div>
<div class="anim">
<div ref="lottieAnim" class="h-96" />
</div>
</div>
</div>
</template>
</HomeSection>
Expand All @@ -81,22 +102,128 @@
/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, watch, useContext, computed } from '@nuxtjs/composition-api'
import lottie, { AnimationItem, AnimationSegment } from 'lottie-web'
export default defineComponent({
setup(_props, context) {
const { $colorMode } = useContext() as any
const lottieAnimPathLight = 'https://assets10.lottiefiles.com/private_files/lf30_8cv6lgcx.json'
const lottieAnimPathDark = 'https://assets10.lottiefiles.com/private_files/lf30_obsnpogu.json'
const animations = ref([
{
name: 'Pages',
segment: [1, 238] as AnimationSegment
},
{
name: 'UI',
segment: [238, 448] as AnimationSegment
},
{
name: 'Data',
segment: [447, 688] as AnimationSegment
},
{
name: 'Modules',
segment: [688, 928] as AnimationSegment
},
{
name: 'Deployment',
segment: [928, 1167] as AnimationSegment
}
])
const lottieAnim = ref(null)
const currentIndex = ref(0)
const animFrames = ref([0, 238, 448, 688, 928])
let anim: AnimationItem
/* computed */
const colorMode = computed(() => {
return $colorMode.value
})
<script>
export default {
props: {
category: {
type: String,
default: 'Category'
},
primary: {
type: Object,
default: () => ({
text: 'Get started',
url: '/get-started',
icon: 'IconPlay'
/* function */
// if user clicks on section, stop loop and play specified segment
function changeAnimation(index: number) {
currentIndex.value = index
anim.loop = false
anim.playSegments(animations.value[index].segment, true)
}
function loadAnimation() {
anim?.destroy()
/**
* Temporary use `context.ref` this should replace by Vue3 ref
*/
lottieAnim.value = context.refs.lottieAnim as Element
anim = lottie.loadAnimation({
container: lottieAnim.value,
renderer: 'svg',
loop: true,
autoplay: false,
path: colorMode.value === 'dark' ? lottieAnimPathDark : lottieAnimPathLight
})
anim.addEventListener('DOMLoaded', function () {
// play animation when lottie container is visible otherwise pause it
animationObserver()
})
anim.addEventListener('enterFrame', function () {
const currentIndexFrame = animFrames.value.indexOf(Math.round(anim.currentFrame))
if (currentIndexFrame !== -1 && anim.loop === true) {
currentIndex.value = currentIndexFrame
}
})
anim.addEventListener('loopComplete', function () {
currentIndex.value = 0
})
}
function animationObserver() {
const callback = entries => {
entries.forEach(({ _, isIntersecting }) => {
if (!isIntersecting) {
anim.pause()
} else {
anim.play()
}
})
}
const observer = new IntersectionObserver(callback, {
root: document.querySelector('anim'),
threshold: 0.8 // isIntersecting when 80% of container is visible
})
observer.observe(lottieAnim.value)
}
/* watcher */
// reload anim with new path according color mode
watch(colorMode, (_, __) => {
loadAnimation()
})
onMounted(() => setTimeout(loadAnimation, 250))
return {
lottieAnim,
anim,
loadAnimation,
changeAnimation,
animations,
currentIndex,
animationObserver
}
}
}
})
</script>
<style lang="postcss" scoped>
.anim {
@apply w-full flex justify-center items-center md:justify-end w-full;
}
</style>
1 change: 1 addition & 0 deletions nuxtjs.org/static/img/home/discover/diamond.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"hasha": "^5.2.2",
"hookable": "^4.4.1",
"jiti": "^1.10.1",
"lottie-web": "^5.7.11",
"mande": "^1.0.0",
"marked": "^2.0.7",
"mkdirp": "^1.0.4",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8284,6 +8284,11 @@ loose-envify@^1.0.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"

lottie-web@^5.7.11:
version "5.7.11"
resolved "https://registry.yarnpkg.com/lottie-web/-/lottie-web-5.7.11.tgz#4ba74e8a629f76d3c0a0062ddc37d2b96e13765c"
integrity sha512-Jvz3PQqwrDj1rXGqfeQtipH/WNtM/Y4l8t8NIQXe1xUI0nVooH2bTYJGef0UkdBcWUx1s3miKsRhyP196g9tvQ==

loud-rejection@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
Expand Down

1 comment on commit eb8584a

@vercel
Copy link

@vercel vercel bot commented on eb8584a Jun 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.