Files
digital-pilates/components/StressMeter.tsx

170 lines
3.9 KiB
TypeScript
Raw 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 { LinearGradient } from 'expo-linear-gradient';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
interface StressMeterProps {
value: number;
status: '放松' | '正常' | '紧张';
}
export function StressMeter({ value, status }: StressMeterProps) {
// 计算进度条位置0-100%
const progressPercentage = Math.min(100, Math.max(0, (value / 150) * 100));
// 根据状态获取颜色
const getStatusColor = () => {
switch (status) {
case '放松': return '#10B981';
case '正常': return '#F59E0B';
case '紧张': return '#EF4444';
default: return '#F59E0B';
}
};
// 根据状态获取表情
const getStatusEmoji = () => {
switch (status) {
case '放松': return '😌';
case '正常': return '😊';
case '紧张': return '😰';
default: return '😊';
}
};
return (
<View style={styles.container}>
{/* 头部区域 */}
<View style={styles.header}>
<View style={styles.leftSection}>
<View style={styles.iconContainer}>
<Ionicons name="heart" size={20} color="#3B82F6" />
</View>
<Text style={styles.title}></Text>
</View>
<Text style={styles.emoji}>{getStatusEmoji()}</Text>
</View>
{/* 数值显示区域 */}
<View style={styles.valueSection}>
<Text style={styles.value}>{value}</Text>
<Text style={styles.unit}></Text>
</View>
{/* 进度条区域 */}
<View style={styles.progressContainer}>
<View style={styles.progressTrack}>
{/* 渐变背景进度条 */}
<View style={[styles.progressBar, { width: `${progressPercentage}%` }]}>
<LinearGradient
colors={['#F97316', '#FCD34D', '#84CC16', '#10B981']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.gradientBar}
/>
</View>
{/* 白色圆形指示器 */}
<View style={[styles.indicator, { left: `${Math.max(0, progressPercentage - 2)}%` }]} />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
borderRadius: 20,
padding: 16,
marginBottom: 12,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.08,
shadowRadius: 12,
elevation: 3,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 12,
},
leftSection: {
flexDirection: 'row',
alignItems: 'center',
},
iconContainer: {
width: 28,
height: 28,
borderRadius: 8,
backgroundColor: '#EBF4FF',
alignItems: 'center',
justifyContent: 'center',
marginRight: 8,
},
title: {
fontSize: 16,
fontWeight: '700',
color: '#1F2937',
},
emoji: {
fontSize: 24,
},
valueSection: {
flexDirection: 'row',
alignItems: 'baseline',
marginBottom: 16,
},
value: {
fontSize: 42,
fontWeight: '800',
color: '#1F2937',
lineHeight: 46,
},
unit: {
fontSize: 14,
fontWeight: '500',
color: '#6B7280',
marginLeft: 4,
},
progressContainer: {
height: 20,
},
progressTrack: {
height: 12,
backgroundColor: '#F3F4F6',
borderRadius: 6,
position: 'relative',
overflow: 'visible',
},
progressBar: {
height: '100%',
borderRadius: 6,
overflow: 'hidden',
},
gradientBar: {
height: '100%',
borderRadius: 6,
},
indicator: {
position: 'absolute',
top: -4,
width: 20,
height: 20,
borderRadius: 10,
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.15,
shadowRadius: 4,
elevation: 4,
borderWidth: 2,
borderColor: '#E5E7EB',
},
});