252 lines
6.5 KiB
TypeScript
252 lines
6.5 KiB
TypeScript
import React from 'react';
|
||
import { View, StyleSheet, Dimensions } from 'react-native';
|
||
import { LinearGradient } from 'expo-linear-gradient';
|
||
import Animated, {
|
||
useSharedValue,
|
||
useAnimatedStyle,
|
||
withRepeat,
|
||
withTiming,
|
||
withSequence,
|
||
interpolate,
|
||
Easing,
|
||
} from 'react-native-reanimated';
|
||
|
||
const { width, height } = Dimensions.get('window');
|
||
|
||
interface BackgroundDesignProps {
|
||
variant?: 'default' | 'login' | 'chat';
|
||
children?: React.ReactNode;
|
||
}
|
||
|
||
export const BackgroundDesign: React.FC<BackgroundDesignProps> = ({
|
||
variant = 'default',
|
||
children
|
||
}) => {
|
||
const floatAnimation = useSharedValue(0);
|
||
const rotateAnimation = useSharedValue(0);
|
||
const pulseAnimation = useSharedValue(0);
|
||
|
||
React.useEffect(() => {
|
||
// Плавное движение вверх-вниз
|
||
floatAnimation.value = withRepeat(
|
||
withSequence(
|
||
withTiming(1, { duration: 4000, easing: Easing.inOut(Easing.ease) }),
|
||
withTiming(0, { duration: 4000, easing: Easing.inOut(Easing.ease) })
|
||
),
|
||
-1,
|
||
false
|
||
);
|
||
|
||
// Вращение элементов
|
||
rotateAnimation.value = withRepeat(
|
||
withTiming(360, { duration: 30000, easing: Easing.linear }),
|
||
-1,
|
||
false
|
||
);
|
||
|
||
// Пульсация
|
||
pulseAnimation.value = withRepeat(
|
||
withSequence(
|
||
withTiming(1, { duration: 2000, easing: Easing.inOut(Easing.ease) }),
|
||
withTiming(0, { duration: 2000, easing: Easing.inOut(Easing.ease) })
|
||
),
|
||
-1,
|
||
false
|
||
);
|
||
}, []);
|
||
|
||
const floatingStyle = useAnimatedStyle(() => {
|
||
const translateY = interpolate(floatAnimation.value, [0, 1], [0, -30]);
|
||
return {
|
||
transform: [{ translateY }],
|
||
};
|
||
});
|
||
|
||
const rotatingStyle = useAnimatedStyle(() => {
|
||
return {
|
||
transform: [{ rotate: `${rotateAnimation.value}deg` }],
|
||
};
|
||
});
|
||
|
||
const pulsingStyle = useAnimatedStyle(() => {
|
||
const scale = interpolate(pulseAnimation.value, [0, 1], [1, 1.1]);
|
||
const opacity = interpolate(pulseAnimation.value, [0, 1], [0.3, 0.6]);
|
||
return {
|
||
transform: [{ scale }],
|
||
opacity,
|
||
};
|
||
});
|
||
|
||
return (
|
||
<View style={styles.container}>
|
||
{/* Основной градиентный фон */}
|
||
<LinearGradient
|
||
colors={['#0a0a0a', '#1a1a1a', '#0f0f0f']}
|
||
style={StyleSheet.absoluteFillObject}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 1 }}
|
||
/>
|
||
|
||
{/* Декоративные элементы */}
|
||
<View style={styles.decorativeElements}>
|
||
{/* Большой круг с градиентом слева вверху */}
|
||
<Animated.View style={[styles.circle1, pulsingStyle]}>
|
||
<LinearGradient
|
||
colors={['rgba(255,255,255,0.03)', 'rgba(255,255,255,0.01)']}
|
||
style={styles.circleGradient}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 1 }}
|
||
/>
|
||
</Animated.View>
|
||
|
||
{/* Плавающий элемент справа */}
|
||
<Animated.View style={[styles.floatingElement1, floatingStyle]}>
|
||
<LinearGradient
|
||
colors={['rgba(255,255,255,0.05)', 'rgba(255,255,255,0.02)']}
|
||
style={styles.elementGradient}
|
||
/>
|
||
</Animated.View>
|
||
|
||
{/* Вращающийся квадрат */}
|
||
<Animated.View style={[styles.rotatingSquare, rotatingStyle]}>
|
||
<View style={styles.squareInner} />
|
||
</Animated.View>
|
||
|
||
{/* Сетка точек для login варианта */}
|
||
{variant === 'login' && (
|
||
<View style={styles.dotsGrid}>
|
||
{Array.from({ length: 10 }).map((_, i) =>
|
||
Array.from({ length: 15 }).map((_, j) => (
|
||
<View
|
||
key={`${i}-${j}`}
|
||
style={[
|
||
styles.dot,
|
||
{
|
||
left: i * (width / 9),
|
||
top: j * (height / 14),
|
||
opacity: 0.05 + Math.random() * 0.05,
|
||
}
|
||
]}
|
||
/>
|
||
))
|
||
)}
|
||
</View>
|
||
)}
|
||
|
||
{/* Градиентные блики */}
|
||
<View style={styles.glowContainer}>
|
||
<LinearGradient
|
||
colors={['rgba(255,255,255,0.1)', 'transparent']}
|
||
style={[styles.glow1]}
|
||
start={{ x: 0.5, y: 0 }}
|
||
end={{ x: 0.5, y: 1 }}
|
||
/>
|
||
<LinearGradient
|
||
colors={['rgba(255,255,255,0.08)', 'transparent']}
|
||
style={[styles.glow2]}
|
||
start={{ x: 0, y: 0.5 }}
|
||
end={{ x: 1, y: 0.5 }}
|
||
/>
|
||
</View>
|
||
</View>
|
||
|
||
{/* Контент поверх фона */}
|
||
<View style={styles.contentContainer}>
|
||
{children}
|
||
</View>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: '#0a0a0a',
|
||
},
|
||
decorativeElements: {
|
||
...StyleSheet.absoluteFillObject,
|
||
overflow: 'hidden',
|
||
},
|
||
contentContainer: {
|
||
flex: 1,
|
||
zIndex: 1,
|
||
},
|
||
circle1: {
|
||
position: 'absolute',
|
||
top: -width * 0.2,
|
||
left: -width * 0.2,
|
||
width: width * 0.6,
|
||
height: width * 0.6,
|
||
borderRadius: width * 0.3,
|
||
overflow: 'hidden',
|
||
},
|
||
circleGradient: {
|
||
flex: 1,
|
||
},
|
||
floatingElement1: {
|
||
position: 'absolute',
|
||
top: height * 0.2,
|
||
right: width * 0.1,
|
||
width: 80,
|
||
height: 80,
|
||
borderRadius: 40,
|
||
backgroundColor: 'rgba(255,255,255,0.02)',
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(255,255,255,0.05)',
|
||
overflow: 'hidden',
|
||
},
|
||
elementGradient: {
|
||
flex: 1,
|
||
},
|
||
rotatingSquare: {
|
||
position: 'absolute',
|
||
bottom: height * 0.15,
|
||
left: width * 0.15,
|
||
width: 60,
|
||
height: 60,
|
||
backgroundColor: 'transparent',
|
||
borderWidth: 2,
|
||
borderColor: 'rgba(255,255,255,0.1)',
|
||
transform: [{ rotate: '45deg' }],
|
||
},
|
||
squareInner: {
|
||
flex: 1,
|
||
margin: 10,
|
||
backgroundColor: 'transparent',
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(255,255,255,0.05)',
|
||
},
|
||
dotsGrid: {
|
||
position: 'absolute',
|
||
top: 0,
|
||
left: 0,
|
||
width: width,
|
||
height: height,
|
||
},
|
||
dot: {
|
||
position: 'absolute',
|
||
width: 2,
|
||
height: 2,
|
||
borderRadius: 1,
|
||
backgroundColor: '#666666',
|
||
},
|
||
glowContainer: {
|
||
...StyleSheet.absoluteFillObject,
|
||
},
|
||
glow1: {
|
||
position: 'absolute',
|
||
top: height * 0.1,
|
||
right: -width * 0.2,
|
||
width: width * 0.8,
|
||
height: width * 0.8,
|
||
borderRadius: width * 0.4,
|
||
},
|
||
glow2: {
|
||
position: 'absolute',
|
||
bottom: -height * 0.1,
|
||
left: -width * 0.1,
|
||
width: width * 0.7,
|
||
height: width * 0.7,
|
||
borderRadius: width * 0.35,
|
||
},
|
||
}); |