-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(apps/mobile): add animated cat button
- Loading branch information
1 parent
7f8129f
commit dae7cff
Showing
8 changed files
with
265 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import { CatEarL } from './CatEarL'; | ||
import { CatEarR } from './CatEarR'; | ||
import { CatHead } from './CatHead'; | ||
import { CatNose } from './CatNose'; | ||
import { CatEye } from './CatEye'; | ||
import { GestureResponderEvent, Pressable, View } from 'react-native'; | ||
import Animated, { | ||
interpolate, | ||
useAnimatedStyle, | ||
useSharedValue, withDelay, | ||
withRepeat, | ||
withSequence, withSpring, withTiming | ||
} from 'react-native-reanimated'; | ||
import { useCallback, useEffect } from 'react'; | ||
|
||
type CatButtonProps = { | ||
onPress: ((event: GestureResponderEvent) => void) | null | undefined; | ||
} | ||
|
||
const CatButton = ({ onPress }: CatButtonProps) => { | ||
|
||
const xVal = useSharedValue(-1); | ||
const yVal = useSharedValue(0); | ||
const blinkVal = useSharedValue(1); | ||
const boopVal = useSharedValue(0); | ||
|
||
const idle = useCallback(() => { | ||
'worklet'; | ||
xVal.value = withRepeat( | ||
withSequence( | ||
withDelay(2000 + Math.random() * 2000, withSpring(-1 + Math.random() * 2)), | ||
withDelay(2000 + Math.random() * 3000, withSpring(0)), | ||
withDelay(2000 + Math.random() * 2000, withSpring(-1 + Math.random() * 2)), | ||
withDelay(2000 + Math.random() * 3000, withSpring(0)), | ||
), | ||
0 | ||
); | ||
yVal.value = withRepeat( | ||
withSequence( | ||
withDelay(2000 + Math.random() * 3000, withSpring(-1 + Math.random() * 2)), | ||
withDelay(2000 + Math.random() * 3000, withSpring(0)), | ||
withDelay(2000 + Math.random() * 3000, withSpring(-1 + Math.random() * 2)), | ||
withDelay(2000 + Math.random() * 3000, withSpring(0)), | ||
), | ||
0 | ||
); | ||
blinkVal.value = withRepeat( | ||
withSequence( | ||
withSpring(0.9), | ||
withTiming(0, { duration: 50 }), | ||
withTiming(1, { duration: 100 }), | ||
withDelay(2000, withSpring(0.5)), | ||
withDelay(1000, withSpring(0.9)), | ||
withTiming(0, { duration: 50 }), | ||
withTiming(1, { duration: 100 }), | ||
withDelay(2000, withSpring(0.8)), | ||
), | ||
0 | ||
) | ||
}, [blinkVal, xVal, yVal]); | ||
|
||
const boop = useCallback(() => { | ||
'worklet'; | ||
xVal.value = withSpring(0); | ||
yVal.value = 1; | ||
yVal.value = withSpring(-2, { stiffness: 600 }); | ||
blinkVal.value = withTiming(0.2); | ||
boopVal.value = withSequence( | ||
withTiming(1, { duration: 50 }), | ||
withTiming(0, { duration: 50 }), | ||
); | ||
|
||
setTimeout(() => { | ||
idle(); | ||
if (onPress) { | ||
// @ts-ignore | ||
onPress(); | ||
} | ||
}, 400); | ||
}, [blinkVal, idle, xVal, yVal]) | ||
|
||
useEffect(() => { | ||
idle(); | ||
}, [idle]); | ||
|
||
const noseStyle = useAnimatedStyle(() => { | ||
return { | ||
transform: [ | ||
{ translateY: interpolate(yVal.value, [-1, 1], [20, -20]) }, | ||
{ translateX: interpolate(xVal.value, [-1, 1], [-50, 30]) } | ||
] | ||
} | ||
}); | ||
|
||
const leftEyeStyle = useAnimatedStyle(() => { | ||
return { | ||
transform: [ | ||
{ translateY: interpolate(yVal.value, [-1, 1], [-30, -50]) }, | ||
{ translateX: interpolate(xVal.value, [-1, 1], [-100, -60]) }, | ||
{ scaleY: interpolate(blinkVal.value, [0, 1], [0, 1]) } | ||
] | ||
} | ||
}); | ||
|
||
const rightEyeStyle = useAnimatedStyle(() => { | ||
return { | ||
transform: [ | ||
{ translateY: interpolate(yVal.value, [-1, 1], [-30, -50]) }, | ||
{ translateX: interpolate(xVal.value, [-1, 1], [60, 100]) }, | ||
{ scaleY: interpolate(blinkVal.value, [0, 1], [0, 1]) } | ||
] | ||
} | ||
}); | ||
|
||
const leftEarStyle = useAnimatedStyle(() => { | ||
return { | ||
transform: [ | ||
{ translateX: -160 }, | ||
{ translateY: interpolate(yVal.value, [-1, 1], [-160, -140]) }, | ||
{ scale: interpolate(xVal.value, [-1, 1], [0.95, 1.05]) } | ||
] | ||
} | ||
}); | ||
|
||
const rightEarStyle = useAnimatedStyle(() => { | ||
return { | ||
transform: [ | ||
{ translateX: 60 }, | ||
{ translateY: interpolate(yVal.value, [-1, 1], [-160, -140]) }, | ||
{ scale: interpolate(xVal.value, [-1, 1], [1.05, 0.95]) } | ||
] | ||
} | ||
}); | ||
|
||
return ( | ||
<Pressable onPress={boop}> | ||
<View style={{ flex: 1, transform: [ { scale: 0.5 }], shadowOpacity: 1, shadowRadius: 10, shadowColor: '#000' }}> | ||
|
||
<Animated.View style={[leftEarStyle, { position: 'absolute' }]}> | ||
<CatEarL stroke={'#444'} strokeWidth={5} color={'#000'} secondaryColor={'#fff'} /> | ||
</Animated.View> | ||
|
||
<Animated.View style={[rightEarStyle, { position: 'absolute' }]}> | ||
<CatEarR stroke={'#444'} strokeWidth={5} color={'#000'} secondaryColor={'#fff'} /> | ||
</Animated.View> | ||
|
||
<CatHead stroke={'#777'} strokeWidth={5} color={'#000'} style={{ position: 'absolute', transform: [ { translateX: -140 }, { translateY: -100 }]}}/> | ||
|
||
<Animated.View style={[noseStyle, { position: 'absolute' }]}> | ||
<CatNose color={'#fff'} /> | ||
</Animated.View> | ||
|
||
<Animated.View style={[leftEyeStyle, { position: 'absolute', transform: [ { translateX: -80 }, { translateY: -50 }]}]}> | ||
<CatEye color={'#fff'} /> | ||
</Animated.View> | ||
|
||
<Animated.View style={[rightEyeStyle, { position: 'absolute', transform: [ { translateX: 80 }, { translateY: -40 }]}]}> | ||
<CatEye color={'#fff'} /> | ||
</Animated.View> | ||
</View> | ||
</Pressable> | ||
) | ||
} | ||
|
||
export default CatButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Path } from "react-native-svg" | ||
import { memo } from "react" | ||
const SvgComponent = (props: SvgProps & { secondaryColor: string }) => ( | ||
<Svg width={115} height={149} fill="none" {...props}> | ||
<Path | ||
fill={props.color} | ||
d="M25.215 97.155c9.53 51.779 26.273 48.698 40.45 46.089 14.178-2.609 45.089-22.487 36.926-50.55C94.429 64.63 26.657 9.136 26.657 9.136s-10.971 36.24-1.442 88.02Z" | ||
/> | ||
<Path | ||
fill={props.secondaryColor} | ||
d="M31.832 81.034c4.418 28.843 6.199 25.275 18.125 16.743 8.51-6.088 20.82-14.445 17.095-30.068C63.326 52.086 32.154 31.95 32.154 31.95s-4.74 20.242-.322 49.084Z" | ||
/> | ||
</Svg> | ||
); | ||
const Memo = memo(SvgComponent) | ||
export { Memo as CatEarL } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Path } from "react-native-svg" | ||
import { memo } from "react" | ||
const SvgComponent = (props: SvgProps & { secondaryColor: string }) => ( | ||
<Svg width={116} height={149} fill="none" {...props}> | ||
<Path | ||
fill={props.color} | ||
d="M90.075 97.038c-9.53 51.779-26.273 48.698-40.45 46.089-14.178-2.609-45.09-22.487-36.926-50.55C20.862 64.512 88.633 9.017 88.633 9.017s10.971 36.241 1.442 88.02Z" | ||
/> | ||
<Path | ||
fill={props.secondaryColor} | ||
d="M82.873 81.034c-4.418 28.843-6.199 25.275-18.126 16.743-8.51-6.088-20.82-14.445-17.094-30.068C51.378 52.086 82.55 31.95 82.55 31.95s4.74 20.242.323 49.084Z" | ||
/> | ||
</Svg> | ||
); | ||
const Memo = memo(SvgComponent) | ||
export { Memo as CatEarR } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Circle } from "react-native-svg" | ||
import { memo } from "react" | ||
const SvgComponent = (props: SvgProps) => ( | ||
<Svg width={19} height={19} fill="none" {...props}> | ||
<Circle cx={9.5} cy={9.5} r={9.5} fill={props.color} /> | ||
</Svg> | ||
); | ||
const Memo = memo(SvgComponent) | ||
export { Memo as CatEye } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Path } from "react-native-svg" | ||
import { memo } from "react" | ||
const SvgComponent = (props: SvgProps) => ( | ||
<Svg | ||
width={297} | ||
height={246} | ||
scale={[0.5]} | ||
fill="none" | ||
{...props} | ||
> | ||
<Path | ||
fill={props.color} | ||
d="M296.29 128c0 39.785-15.699 43.904-41.239 70.5-26.933 28.044-64.808 47.5-106.761 47.5-41.953 0-79.828-17.456-106.76-45.5C15.988 173.904.29 167.785.29 128c0-81.738 66.262-128 148-128s148 46.262 148 128Z" | ||
/> | ||
</Svg> | ||
) | ||
const Memo = memo(SvgComponent) | ||
export { Memo as CatHead } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Path } from "react-native-svg" | ||
import { memo } from 'react'; | ||
import Animated from 'react-native-reanimated'; | ||
|
||
const AnimatedPath = Animated.createAnimatedComponent(Path); | ||
const SvgComponent = (props: SvgProps) => { | ||
|
||
return ( | ||
<Svg width={51} height={32} fill="none" {...props}> | ||
<AnimatedPath | ||
fill={`rgb(99, 68, 108)`} | ||
d="M50.133 13c0 6.57-12.33 6.72-16.519 11.165-4.561 4.84-1.283 7.689-8.48 7.689-7.198 0-3.92-2.85-8.482-7.69C12.464 19.72.133 19.57.133 13 .133-.727 12-1.5 25.133 1.854 39.5-1 50.133-.727 50.133 13Z" | ||
/> | ||
</Svg> | ||
); | ||
|
||
} | ||
|
||
const Memo = memo(SvgComponent); | ||
export { Memo as CatNose } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import * as React from "react" | ||
import Svg, { SvgProps, Path } from "react-native-svg" | ||
import { memo } from "react" | ||
const SvgComponent = (props: SvgProps) => ( | ||
<Svg width={189} height={116} fill="none" {...props}> | ||
<Path | ||
fill={props.color} | ||
d="M189 58.791c0 18.274-10.024 20.165-26.332 32.381C145.472 104.053 121.287 116 94.5 116c-26.787 0-50.971-11.028-68.168-23.91C10.024 79.876 0 77.066 0 58.792 0 21.248 42.31 0 94.5 0 146.691 0 189 21.248 189 58.791Z" | ||
/> | ||
</Svg> | ||
); | ||
const Memo = memo(SvgComponent) | ||
export { Memo as CatSnout } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters