From 5b81faffd399fb3403b24ea4312f9c37721243b1 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:25:36 +0200 Subject: [PATCH 1/8] 01 - The Medium Clap --- showcase/src/patterns/index.css | 81 +++++++++ showcase/src/patterns/index.js | 190 +++++++++++++++++++++ showcase/src/utils/generateRandomNumber.js | 4 + 3 files changed, 275 insertions(+) create mode 100644 showcase/src/patterns/index.css create mode 100644 showcase/src/patterns/index.js create mode 100644 showcase/src/utils/generateRandomNumber.js diff --git a/showcase/src/patterns/index.css b/showcase/src/patterns/index.css new file mode 100644 index 0000000..75eed52 --- /dev/null +++ b/showcase/src/patterns/index.css @@ -0,0 +1,81 @@ +/* Clap button */ +.clap { + position: relative; + outline: 1px solid transparent; + border-radius: 50%; + border: 1px solid #bdc3c7; + width: 80px; + height: 80px; + background: none; + user-select: none; + } +.clap:after { + content: ""; + position: absolute; + top: 0; + left: 0; + display: block; + border-radius: 50%; + width: 79px; + height: 79px; +} +.clap:hover { + cursor: pointer; + border: 1px solid #27ae60; + transition: border-color 0.3s ease-in; +} +.clap:hover:after { + animation: shockwave 1s ease-in infinite; +} + +@keyframes shockwave { + 0% { + transform: scale(1); + box-shadow: 0 0 2px #27ae60; + opacity: 1; + } + 100% { + transform: scale(1); + opacity: 0; + box-shadow: 0 0 50px #145b32, inset 0 0 10px #27ae60; + } +} + +/* Count */ +.count { + position: absolute; + top: -50px; + left: 20px; + font-size: 0.8rem; + color: white; + background: #27ae60; + border-radius: 50%; + height: 40px; + width: 40px; + line-height: 40px; +} + +/* Count total */ +.total { + position: absolute; + font-size: 0.8rem; + width: 80px; + text-align: center; + left: 0; + top: -22px; + color: #bdc3c7; + } + +/* Clap Icon */ +.icon { + width: 40px; + fill: none; + stroke: #27ae60; + stroke-width: 2px; + } + +.icon.checked { + fill: #27ae60; + stroke: #fff; + stroke-width: 1px; +} \ No newline at end of file diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js new file mode 100644 index 0000000..5803a6b --- /dev/null +++ b/showcase/src/patterns/index.js @@ -0,0 +1,190 @@ +import React, { Component, useState } from 'react' +import mojs from 'mo-js' +import { generateRandomNumber } from '../utils/generateRandomNumber' +import styles from './index.css' + +/** ==================================== +Smaller Component for Medium Clap +==================================== **/ + +const ClapIcon = ({ isClicked }) => { + return ( + + + + + + + ) +} +const ClapCount = ({ count }) => { + return ( + + +{count} + + ) +} +const CountTotal = ({ countTotal }) => { + return ( + + {countTotal} + + ) +} + +const initialState = { + count: 0, + countTotal: generateRandomNumber(500, 10000), + isClicked: false +} + +// 👉 Medium Clap +const MediumClap = ({ animationTimeline }) => { + const [clapState, setClapState] = useState(initialState) + const { count, countTotal, isClicked } = clapState + + const handleClapClick = () => { + // 👉 prop from HOC + animationTimeline.replay() + + setClapState({ + count: Math.min(count + 1, 50), + countTotal: countTotal + 1, + isClicked: true + }) + } + + return ( + + ) +} + +/** ==================================== +Higher Order Component for Animation +==================================== **/ +const withClapAnimation = WrappedComponent => { + class WithClapAnimation extends Component { + state = { + animationTimeline: new mojs.Timeline() + } + + componentDidMount () { + const tlDuration = 300 + + const triangleBurst = new mojs.Burst({ + parent: '#clap', + radius: { 50: 95 }, + count: 5, + angle: 30, + children: { + shape: 'polygon', + radius: { 6: 0 }, + scale: 1, + stroke: 'rgba(211,84,0 ,0.5)', + strokeWidth: 2, + angle: 210, + delay: 30, + speed: 0.2, + easing: mojs.easing.bezier(0.1, 1, 0.3, 1), + duration: tlDuration + } + }) + + const circleBurst = new mojs.Burst({ + parent: '#clap', + radius: { 50: 75 }, + angle: 25, + duration: tlDuration, + children: { + shape: 'circle', + fill: 'rgba(149,165,166 ,0.5)', + delay: 30, + speed: 0.2, + radius: { 3: 0 }, + easing: mojs.easing.bezier(0.1, 1, 0.3, 1) + } + }) + + const countAnimation = new mojs.Html({ + el: '#clapCount', + isShowStart: false, + isShowEnd: true, + y: { 0: -30 }, + opacity: { 0: 1 }, + duration: tlDuration + }).then({ + opacity: { 1: 0 }, + y: -80, + delay: tlDuration / 2 + }) + + const countTotalAnimation = new mojs.Html({ + el: '#clapCountTotal', + isShowStart: false, + isShowEnd: true, + opacity: { 0: 1 }, + delay: (3 * tlDuration) / 2, + duration: tlDuration, + y: { 0: -3 } + }) + + const scaleButton = new mojs.Html({ + el: '#clap', + duration: tlDuration, + scale: { 1.3: 1 }, + easing: mojs.easing.out + }) + + const clap = document.getElementById('clap') + clap.style.transform = 'scale(1, 1)' + this.state.animationTimeline.add([ + countAnimation, + countTotalAnimation, + scaleButton, + circleBurst, + triangleBurst + ]) + } + + render () { + return ( + + ) + } + } + + WithClapAnimation.displayName = `WithClapAnimation(${getDisplayName( + WrappedComponent + )})` + + return WithClapAnimation +} + +function getDisplayName (WrappedComponent) { + return WrappedComponent.displayName || WrappedComponent.name || 'Component' +} + +/** ==================================== + 🔰USAGE + Below's how a potention user may consume + the component API +==================================== **/ + +const Usage = () => { + const AnimatedMediumClap = withClapAnimation(MediumClap) + return +} + +export default Usage diff --git a/showcase/src/utils/generateRandomNumber.js b/showcase/src/utils/generateRandomNumber.js new file mode 100644 index 0000000..7a1e20c --- /dev/null +++ b/showcase/src/utils/generateRandomNumber.js @@ -0,0 +1,4 @@ +export const generateRandomNumber = (min, max) => { + console.log('gen number evaluated!') + return Math.floor(Math.random() * (max - min + 1) + min) +} From 9d40a1382284eed10bf7ae62476100bdbb0bf704 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:34:14 +0200 Subject: [PATCH 2/8] fix total count bug --- showcase/src/patterns/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index 5803a6b..95d3770 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -45,6 +45,7 @@ const initialState = { // 👉 Medium Clap const MediumClap = ({ animationTimeline }) => { + const MAXIMUM_USER_CLAP = 50 const [clapState, setClapState] = useState(initialState) const { count, countTotal, isClicked } = clapState @@ -53,8 +54,8 @@ const MediumClap = ({ animationTimeline }) => { animationTimeline.replay() setClapState({ - count: Math.min(count + 1, 50), - countTotal: countTotal + 1, + count: Math.min(count + 1, MAXIMUM_USER_CLAP), + countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, isClicked: true }) } From f1ea609d9d2d609ba8ed603833d5724c2fa286ea Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:40:03 +0200 Subject: [PATCH 3/8] cleanup --- showcase/src/utils/generateRandomNumber.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/showcase/src/utils/generateRandomNumber.js b/showcase/src/utils/generateRandomNumber.js index 7a1e20c..b9d970c 100644 --- a/showcase/src/utils/generateRandomNumber.js +++ b/showcase/src/utils/generateRandomNumber.js @@ -1,4 +1,2 @@ -export const generateRandomNumber = (min, max) => { - console.log('gen number evaluated!') - return Math.floor(Math.random() * (max - min + 1) + min) -} +export const generateRandomNumber = (min, max) => + Math.floor(Math.random() * (max - min + 1) + min) From 15bf11359beaa9e63af5bf891ad5529e7b591ef9 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:42:42 +0200 Subject: [PATCH 4/8] even better comments --- showcase/src/patterns/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index 95d3770..7dc3f8a 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -4,6 +4,7 @@ import { generateRandomNumber } from '../utils/generateRandomNumber' import styles from './index.css' /** ==================================== + * 🔰 SubComponents Smaller Component for Medium Clap ==================================== **/ @@ -70,6 +71,7 @@ const MediumClap = ({ animationTimeline }) => { } /** ==================================== + * 🔰HOC Higher Order Component for Animation ==================================== **/ const withClapAnimation = WrappedComponent => { @@ -178,9 +180,9 @@ function getDisplayName (WrappedComponent) { } /** ==================================== - 🔰USAGE - Below's how a potention user may consume - the component API + * 🔰USAGE + Below's how a potention user + may consumethe component API ==================================== **/ const Usage = () => { From c020873d1f4fc68c9b547c399bb2299f86fef5e3 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:43:51 +0200 Subject: [PATCH 5/8] additional comment --- showcase/src/patterns/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index 7dc3f8a..2f9891c 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -44,7 +44,10 @@ const initialState = { isClicked: false } -// 👉 Medium Clap +/** ==================================== + * 🔰 MediumClap +==================================== **/ + const MediumClap = ({ animationTimeline }) => { const MAXIMUM_USER_CLAP = 50 const [clapState, setClapState] = useState(initialState) From da44d1e555f600d07c2666b062f66bc863b1c9b6 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:44:53 +0200 Subject: [PATCH 6/8] further cleanups --- showcase/src/patterns/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index 2f9891c..f363283 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -4,7 +4,7 @@ import { generateRandomNumber } from '../utils/generateRandomNumber' import styles from './index.css' /** ==================================== - * 🔰 SubComponents + * 🔰SubComponents Smaller Component for Medium Clap ==================================== **/ @@ -184,8 +184,8 @@ function getDisplayName (WrappedComponent) { /** ==================================== * 🔰USAGE - Below's how a potention user - may consumethe component API + Below's how a potential user + may consume the component API ==================================== **/ const Usage = () => { From 36d60aac82b5fe46984c7eeb05e21e9cad3a36d2 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Thu, 24 Oct 2019 10:50:19 +0200 Subject: [PATCH 7/8] reorder component lisiting --- showcase/src/patterns/index.js | 139 ++++++++++++++++----------------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index f363283..a4a5ae5 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -3,76 +3,6 @@ import mojs from 'mo-js' import { generateRandomNumber } from '../utils/generateRandomNumber' import styles from './index.css' -/** ==================================== - * 🔰SubComponents -Smaller Component for Medium Clap -==================================== **/ - -const ClapIcon = ({ isClicked }) => { - return ( - - - - - - - ) -} -const ClapCount = ({ count }) => { - return ( - - +{count} - - ) -} -const CountTotal = ({ countTotal }) => { - return ( - - {countTotal} - - ) -} - -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -/** ==================================== - * 🔰 MediumClap -==================================== **/ - -const MediumClap = ({ animationTimeline }) => { - const MAXIMUM_USER_CLAP = 50 - const [clapState, setClapState] = useState(initialState) - const { count, countTotal, isClicked } = clapState - - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - return ( - - ) -} - /** ==================================== * 🔰HOC Higher Order Component for Animation @@ -182,6 +112,75 @@ function getDisplayName (WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component' } +/** ==================================== + * 🔰 MediumClap +==================================== **/ +const initialState = { + count: 0, + countTotal: generateRandomNumber(500, 10000), + isClicked: false +} + +const MediumClap = ({ animationTimeline }) => { + const MAXIMUM_USER_CLAP = 50 + const [clapState, setClapState] = useState(initialState) + const { count, countTotal, isClicked } = clapState + + const handleClapClick = () => { + // 👉 prop from HOC + animationTimeline.replay() + + setClapState({ + count: Math.min(count + 1, MAXIMUM_USER_CLAP), + countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, + isClicked: true + }) + } + + return ( + + ) +} + +/** ==================================== + * 🔰SubComponents +Smaller Component used by +==================================== **/ + +const ClapIcon = ({ isClicked }) => { + return ( + + + + + + + ) +} +const ClapCount = ({ count }) => { + return ( + + +{count} + + ) +} +const CountTotal = ({ countTotal }) => { + return ( + + {countTotal} + + ) +} + /** ==================================== * 🔰USAGE Below's how a potential user From 820e4139968006c41f81965edc43154b99debd52 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: Tue, 7 Jan 2020 05:55:56 +0100 Subject: [PATCH 8/8] fix: timeline update logic --- showcase/src/patterns/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js index a4a5ae5..34fb644 100644 --- a/showcase/src/patterns/index.js +++ b/showcase/src/patterns/index.js @@ -9,8 +9,9 @@ Higher Order Component for Animation ==================================== **/ const withClapAnimation = WrappedComponent => { class WithClapAnimation extends Component { + animationTimeline = new mojs.Timeline() state = { - animationTimeline: new mojs.Timeline() + animationTimeline: this.animationTimeline } componentDidMount () { @@ -82,13 +83,15 @@ const withClapAnimation = WrappedComponent => { const clap = document.getElementById('clap') clap.style.transform = 'scale(1, 1)' - this.state.animationTimeline.add([ + + const newAnimationTimeline = this.animationTimeline.add([ countAnimation, countTotalAnimation, scaleButton, circleBurst, triangleBurst ]) + this.setState({ animationTimeline: newAnimationTimeline }) } render () {