1212
This commit is contained in:
252
frontend/src/components/BackgroundDesign.tsx
Normal file
252
frontend/src/components/BackgroundDesign.tsx
Normal file
@ -0,0 +1,252 @@
|
||||
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,
|
||||
},
|
||||
});
|
Reference in New Issue
Block a user