Files
digital-pilates/components/sleep/SleepStagesInfoModal.tsx

246 lines
8.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Ionicons } from '@expo/vector-icons';
import React, { useState } from 'react';
import {
Animated,
Modal,
Pressable,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
// Sleep Stages Info Modal 组件
export const SleepStagesInfoModal = ({
visible,
onClose
}: {
visible: boolean;
onClose: () => void;
}) => {
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
const colorTokens = Colors[theme];
const slideAnim = useState(new Animated.Value(0))[0];
React.useEffect(() => {
if (visible) {
slideAnim.setValue(0);
Animated.spring(slideAnim, {
toValue: 1,
useNativeDriver: true,
tension: 100,
friction: 8,
}).start();
} else {
Animated.spring(slideAnim, {
toValue: 0,
useNativeDriver: true,
tension: 100,
friction: 8,
}).start();
}
}, [visible]);
const translateY = slideAnim.interpolate({
inputRange: [0, 1],
outputRange: [300, 0],
});
const opacity = slideAnim.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
});
return (
<Modal
transparent
visible={visible}
animationType="none"
onRequestClose={onClose}
>
<View style={styles.modalOverlay}>
<Pressable
style={StyleSheet.absoluteFillObject}
onPress={onClose}
/>
<Animated.View
style={[
styles.sleepStagesModalContent,
{
backgroundColor: colorTokens.background,
transform: [{ translateY }],
opacity,
}
]}
>
<View style={styles.sleepStagesModalInner}>
<View style={styles.modalHandle} />
<View style={styles.sleepStagesModalHeader}>
<Text style={[styles.sleepStagesModalTitle, { color: colorTokens.text }]}>
</Text>
<TouchableOpacity onPress={onClose} style={styles.infoModalCloseButton}>
<Ionicons name="close" size={24} color={colorTokens.textSecondary} />
</TouchableOpacity>
</View>
<ScrollView
style={styles.sleepStagesScrollView}
contentContainerStyle={styles.sleepStagesScrollContent}
showsVerticalScrollIndicator={false}
bounces={true}
scrollEnabled={true}
>
<Text style={[styles.sleepStagesDescription, { color: colorTokens.textSecondary }]}>
</Text>
{/* 清醒时间 */}
<View style={styles.sleepStageInfoCard}>
<View style={[styles.sleepStageInfoHeader, { borderBottomColor: colorTokens.border }]}>
<View style={styles.sleepStageInfoTitleContainer}>
<View style={[styles.sleepStageDot, { backgroundColor: '#F59E0B' }]} />
<Text style={[styles.sleepStageInfoTitle, { color: colorTokens.text }]}></Text>
</View>
</View>
<Text style={[styles.sleepStageInfoContent, { color: colorTokens.textSecondary }]}>
</Text>
</View>
{/* 快速动眼睡眠 */}
<View style={styles.sleepStageInfoCard}>
<View style={[styles.sleepStageInfoHeader, { borderBottomColor: colorTokens.border }]}>
<View style={styles.sleepStageInfoTitleContainer}>
<View style={[styles.sleepStageDot, { backgroundColor: '#EC4899' }]} />
<Text style={[styles.sleepStageInfoTitle, { color: colorTokens.text }]}></Text>
</View>
</View>
<Text style={[styles.sleepStageInfoContent, { color: colorTokens.textSecondary }]}>
</Text>
</View>
{/* 核心睡眠 */}
<View style={styles.sleepStageInfoCard}>
<View style={[styles.sleepStageInfoHeader, { borderBottomColor: colorTokens.border }]}>
<View style={styles.sleepStageInfoTitleContainer}>
<View style={[styles.sleepStageDot, { backgroundColor: '#8B5CF6' }]} />
<Text style={[styles.sleepStageInfoTitle, { color: colorTokens.text }]}></Text>
</View>
</View>
<Text style={[styles.sleepStageInfoContent, { color: colorTokens.textSecondary }]}>
</Text>
</View>
{/* 深度睡眠 */}
<View style={styles.sleepStageInfoCard}>
<View style={[styles.sleepStageInfoHeader, { borderBottomColor: colorTokens.border }]}>
<View style={styles.sleepStageInfoTitleContainer}>
<View style={[styles.sleepStageDot, { backgroundColor: '#3B82F6' }]} />
<Text style={[styles.sleepStageInfoTitle, { color: colorTokens.text }]}></Text>
</View>
</View>
<Text style={[styles.sleepStageInfoContent, { color: colorTokens.textSecondary }]}>
</Text>
</View>
</ScrollView>
</View>
</Animated.View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'flex-end',
},
modalHandle: {
width: 36,
height: 4,
backgroundColor: '#D1D5DB',
borderRadius: 2,
alignSelf: 'center',
marginBottom: 20,
},
infoModalCloseButton: {
padding: 4,
},
// Sleep Stages Modal 样式
sleepStagesModalContent: {
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
height: '80%',
shadowColor: '#000',
shadowOffset: { width: 0, height: -4 },
shadowOpacity: 0.1,
shadowRadius: 16,
elevation: 8,
},
sleepStagesModalInner: {
flex: 1,
paddingTop: 12,
paddingHorizontal: 20,
paddingBottom: 34,
},
sleepStagesModalHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
},
sleepStagesModalTitle: {
fontSize: 20,
fontWeight: '700',
letterSpacing: -0.4,
},
sleepStagesScrollView: {
flex: 1,
},
sleepStagesScrollContent: {
paddingBottom: 40,
},
sleepStagesDescription: {
fontSize: 15,
lineHeight: 22,
letterSpacing: -0.1,
marginBottom: 24,
},
sleepStageInfoCard: {
marginBottom: 20,
},
sleepStageInfoHeader: {
paddingBottom: 12,
marginBottom: 12,
},
sleepStageInfoTitleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
sleepStageDot: {
width: 12,
height: 12,
borderRadius: 6,
},
sleepStageInfoTitle: {
fontSize: 18,
fontWeight: '600',
letterSpacing: -0.2,
},
sleepStageInfoContent: {
fontSize: 15,
lineHeight: 22,
letterSpacing: -0.1,
},
});