Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Jalson1982/451a5b8624866c33cca23df4a9259f4b to your computer and use it in GitHub Desktop.
Save Jalson1982/451a5b8624866c33cca23df4a9259f4b to your computer and use it in GitHub Desktop.
import React, {useEffect, useRef, useState} from 'react';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {
Canvas,
RoundedRect,
RadialGradient,
BackdropBlur,
Fill,
vec,
Rect,
} from '@shopify/react-native-skia';
import Animated, {
Easing,
runOnJS,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import {Dimensions, StyleSheet, View} from 'react-native';
import {
Directions,
Gesture,
GestureDetector,
} from 'react-native-gesture-handler';;
const duration = 300;
const _size = Dimensions.get('window').width * 0.8;
const layout = {
borderRadius: 16,
width: _size,
height: 193,
spacing: 12,
cardsGap: 22,
};
const colors = {
primary: '#6667AB',
light: '#fff',
dark: '#111',
};
const data = [
{
id: '0fa08fa5-6d45-4d56-86e0-8fd56632dfd4',
role: 'Subcontractor',
type: 'Excavator',
from: '10:52 AM',
to: '9:40 PM',
duration: 2,
distance: 19.7,
},
{
id: 'f8f798bb-c7bd-4080-9bc6-aa4cabfab482',
role: 'Surveyor',
type: 'Crawler',
from: '11:45 AM',
to: '4:08 PM',
duration: 0,
distance: 55.2,
},
{
id: '068de8c4-1b87-4051-9885-ee28a48cd274',
role: 'Surveyor',
type: 'Scraper',
from: '9:04 AM',
to: '9:17 PM',
duration: 5,
distance: 1.9,
},
];
export const locationImage =
'https://miro.medium.com/v2/resize:fit:1200/1*ybR6fbfwo6XTmWvTjXSOAA.png';
const cards = [
{id: 1, text: 'Card 1'},
{id: 2, text: 'Card 2'},
{id: 3, text: 'Card 3'},
];
export const Home = () => {
const {top} = useSafeAreaInsets();
const animation = useSharedValue(0);
const [currentIndex, setCurrentIndex] = useState(0);
function mapIndex(index: number, totalCards: number) {
const scaleFactor = 0.2; // Change this value to adjust the scaling effect
return 1 + scaleFactor * (totalCards - 1 - index);
}
const animatedStyles = cards.map((_, index) =>
useAnimatedStyle(() => {
const isCurrent = currentIndex === index;
return {
transform: [
{
translateY: withTiming(isCurrent ? 100 : index * -50, {
duration: 500,
easing: Easing.inOut(Easing.ease),
}),
},
{
scale: withTiming(1 + 0.2 * (3 - index), {
duration: 500,
easing: Easing.inOut(Easing.ease),
}),
},
],
opacity: withTiming(isCurrent ? 1 : 0.5, {
duration: 500,
easing: Easing.inOut(Easing.ease),
}),
zIndex: isCurrent ? 1 : 0,
};
}),
);
const [activeIndex, setActiveIndex] = useState(0);
const floatActiveIndex = useSharedValue(0);
const [isMenuVisible, setIsMenuVisible] = useState(false);
const [data1, setData1] = useState(data);
const [boom, setBoom] = useState(0);
const offsetX = useSharedValue(0);
function perfomSwipe(direction) {
if (direction === 'right' && boom >= data1.length - 1) {
return;
}
if (direction === 'left' && boom <= 0) {
return;
}
if (direction === 'right') {
setBoom(boom + 1);
} else {
setBoom(boom - 1);
}
setData1(oldData => {
const newData = [...oldData];
const lastElement = newData.pop();
newData.unshift(lastElement);
return newData;
});
}
const panGesture = Gesture.Pan()
.onChange(event => {
offsetX.value = event.translationX;
})
.onFinalize(event => {
if (
Math.abs(event.translationX) > 120 ||
Math.abs(event.translationY) > 120
) {
//runOnJS(perfomSwipe)();
}
offsetX.value = withTiming(0);
});
const flingUp = Gesture.Fling()
.direction(Directions.UP)
.onStart(() => {
if (floatActiveIndex.value <= 0) {
floatActiveIndex.value = 0;
return;
}
floatActiveIndex.value = withTiming(floatActiveIndex.value - 1, {
duration,
});
});
const flingDown = Gesture.Fling()
.direction(Directions.RIGHT)
.onStart(() => {
if (floatActiveIndex.value === data.length) {
return;
}
floatActiveIndex.value = withTiming(floatActiveIndex.value + 1, {
duration,
});
});
const flingRight = Gesture.Fling()
.direction(Directions.RIGHT)
.onStart(() => {
if (floatActiveIndex.value === data.length) {
return;
}
floatActiveIndex.value = withTiming(floatActiveIndex.value + 1, {
duration,
});
});
const flingLeft = Gesture.Fling()
.direction(Directions.LEFT)
.onStart(() => {
if (floatActiveIndex.value <= 0) {
floatActiveIndex.value = 0;
return;
}
floatActiveIndex.value = withTiming(floatActiveIndex.value - 1, {
duration,
});
});
return (
<Box
flex={1}
backgroundColor="primary950"
style={{
paddingTop: top + 10,
}}>
<Box
style={{
alignItems: 'center',
flex: 1,
justifyContent: 'center',
marginBottom: layout.cardsGap * 2,
}}
pointerEvents="box-none">
{data1.map((c, index) => {
return (
<Card
info={c}
key={c.id}
id={c.id}
index={index}
totalLength={data.length - 1}
activeIndex={floatActiveIndex}
perfomSwipe={perfomSwipe}
offsetX={offsetX}
isFirst={index === 0}
boom={boom}
/>
);
})}
</Box>
</Box>
);
};
function Card({
info,
index,
totalLength,
activeIndex,
perfomSwipe,
isFirst,
id,
boom,
}) {
const offsetX = useSharedValue(0);
const indexRef = useSharedValue(index);
console.log('index', index, id);
const createPanGesture = cardIndex => {
return Gesture.Pan()
.onChange(event => {
console.log('event111boom', boom);
if (boom === 0 && event.translationX < 0) {
console.log('muuu');
return;
}
if (boom >= totalLength && event.translationX > 0) {
console.log('muuu');
return;
}
console.log('event111222', event.translationX, id);
offsetX.value = event.translationX;
})
.onFinalize(event => {
if (Math.abs(event.translationX) > 120) {
if (cardIndex === 0 && event.translationX < 0) return;
console.log('event111', cardIndex, isFirst, event.translationX);
runOnJS(perfomSwipe)(event.translationX > 0 ? 'right' : 'left');
}
offsetX.value = withTiming(0);
});
};
const panGesture = createPanGesture(index);
const stylez = useAnimatedStyle(() => {
return {
position: 'absolute',
opacity: withTiming(
Math.max(
1 - ((totalLength - index - 1) / 10) * 1 * (totalLength - index - 1),
0.8,
),
),
transform: [
{translateX: offsetX.value},
{
scaleX: withTiming(
Math.max(
1 -
(totalLength - index - 1) / 10 +
0 * (totalLength - index - 1),
0.8,
),
),
},
{translateY: withTiming(-Math.min((totalLength - index - 1) * 15, 10))},
],
zIndex: 0,
};
});
return (
<GestureDetector
// We use Exclusive to prevent using different gestures at the same time
// There's only one gesture that can be performed. This is by design.
// If you would like to support multiple gestures, you can use `Simultaneous`
gesture={panGesture}>
<Animated.View
style={[
{
borderRadius: layout.borderRadius,
width: layout.width,
height: layout.height,
},
stylez,
]}>
<Canvas
style={{
position: 'absolute',
width: layout.width,
height: layout.height,
borderRadius: layout.borderRadius,
overflow: 'hidden',
}}>
<Rect
x={0}
y={0}
width={Dimensions.get('window').width * 0.8}
height={193}>
<RadialGradient
c={vec((Dimensions.get('window').width * 0.8) / 2, 193)} // Center at 50% 100%
r={193} // Radius to cover the canvas height
colors={[
'rgba(190, 87, 209, 0.60)', // Color at the center
'rgba(91, 44, 198, 1.0)', // Color at the edge
]}
/>
</Rect>
<BackdropBlur
blur={4}
clip={{
x: 0,
y: 0,
width: Dimensions.get('window').width * 0.8,
height: 193,
}}>
<Fill color="rgba(0, 0, 0, 0.)" />
</BackdropBlur>
</Canvas>
<>
<Text style={styles.title}>{info.type}</Text>
<View style={styles.row}>
<Text style={styles.subtitle}>
{info.from} - {info.to}
</Text>
</View>
<View style={styles.row}>
<Text style={styles.subtitle}>{info.distance} km</Text>
</View>
<View style={styles.row}>
<Text style={styles.subtitle}>{info.role}</Text>
</View>
</>
</Animated.View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30,
backgroundColor: colors.primary,
padding: layout.spacing,
},
card: {
borderRadius: layout.borderRadius,
width: layout.width,
height: layout.height,
padding: layout.spacing,
backgroundColor: colors.light,
},
title: {
fontSize: 32,
fontWeight: '600',
textAlign: 'center',
color: 'white',
},
subtitle: {color: 'white', textAlign: 'center'},
cardContent: {textAlign: 'center'},
locationImage: {
flex: 1,
borderRadius: layout.borderRadius - layout.spacing / 2,
},
row: {
flexDirection: 'row',
columnGap: layout.spacing / 2,
alignItems: 'center',
justifyContent: 'center',
},
icon: {},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment