feat(medications): 增强药品详情页面的编辑功能
- 添加剂量、剂型和服药频率的交互式选择器 - 实现提醒时间的动态编辑和添加功能 - 引入玻璃效果优化删除按钮的视觉体验 - 重构常量配置,提取药物相关常量到独立文件 - 创建可复用的InfoCard组件支持玻璃效果
This commit is contained in:
149
components/ui/InfoCard.tsx
Normal file
149
components/ui/InfoCard.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
import type { Colors } from '@/constants/Colors';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
export interface InfoCardProps {
|
||||
label: string;
|
||||
value: string;
|
||||
icon: keyof typeof Ionicons.glyphMap;
|
||||
colors: (typeof Colors)[keyof typeof Colors];
|
||||
onPress?: () => void;
|
||||
clickable?: boolean;
|
||||
glassEffectStyle?: 'clear' | 'regular';
|
||||
tintColor?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const InfoCard: React.FC<InfoCardProps> = ({
|
||||
label,
|
||||
value,
|
||||
icon,
|
||||
colors,
|
||||
onPress,
|
||||
clickable = false,
|
||||
glassEffectStyle = 'clear',
|
||||
|
||||
}) => {
|
||||
const isGlassAvailable = isLiquidGlassAvailable();
|
||||
|
||||
// 如果可点击且有onPress回调,使用TouchableOpacity包装
|
||||
if (clickable && onPress) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.container}
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
{isGlassAvailable ? (
|
||||
<GlassView
|
||||
style={[
|
||||
styles.infoCard,
|
||||
]}
|
||||
glassEffectStyle={glassEffectStyle}
|
||||
isInteractive={true}
|
||||
>
|
||||
<View style={styles.infoCardArrow}>
|
||||
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
|
||||
</View>
|
||||
<View style={styles.infoCardIcon}>
|
||||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||||
</View>
|
||||
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
|
||||
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
|
||||
</GlassView>
|
||||
) : (
|
||||
<View style={[styles.infoCard]}>
|
||||
<View style={styles.infoCardArrow}>
|
||||
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
|
||||
</View>
|
||||
<View style={styles.infoCardIcon}>
|
||||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||||
</View>
|
||||
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
|
||||
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
// 不可点击的版本
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{isGlassAvailable ? (
|
||||
<GlassView
|
||||
style={[
|
||||
styles.infoCard,
|
||||
{
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: `${colors.border}80`,
|
||||
}
|
||||
]}
|
||||
glassEffectStyle={glassEffectStyle}
|
||||
>
|
||||
<View style={styles.infoCardIcon}>
|
||||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||||
</View>
|
||||
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
|
||||
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
|
||||
</GlassView>
|
||||
) : (
|
||||
<View style={[styles.infoCard, { backgroundColor: colors.surface }]}>
|
||||
<View style={styles.infoCardIcon}>
|
||||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||||
</View>
|
||||
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
|
||||
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
infoCard: {
|
||||
flex: 1,
|
||||
borderRadius: 20,
|
||||
padding: 16,
|
||||
backgroundColor: '#fff',
|
||||
gap: 6,
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 8,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
elevation: 2,
|
||||
position: 'relative',
|
||||
overflow: 'hidden', // 保证玻璃边界圆角效果
|
||||
},
|
||||
infoCardArrow: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
right: 12,
|
||||
zIndex: 1,
|
||||
},
|
||||
infoCardIcon: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
backgroundColor: '#EEF1FF',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
infoCardLabel: {
|
||||
fontSize: 13,
|
||||
color: '#6B7280',
|
||||
marginTop: 8,
|
||||
},
|
||||
infoCardValue: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#1F2933',
|
||||
},
|
||||
});
|
||||
|
||||
export default InfoCard;
|
||||
Reference in New Issue
Block a user