Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import { Card, Text, XStack, YStack } from 'tamagui';
import { IconSymbol } from '@/src/components/ui/IconSymbol';
import { OptimizedImage } from '@/src/components/ui/OptimizedImage';
import { Colors, withAlpha } from '@/src/constants/colors';
import { useThemeAwareColorScheme } from '@/src/hooks/useThemeAwareColorScheme';
import type { Pet } from '@/src/schemas/pet.schema';
interface PetCardProps {
pet: Pet;
onPress?: () => void;
}
/**
* 宠物卡片组件
* 展示单个宠物的基本信息
*/
export function PetCard({ pet, onPress }: PetCardProps) {
const colorScheme = useThemeAwareColorScheme();
const colors = Colors[colorScheme];
// 防御性检查:如果没有 pet,则不渲染(在 hooks 之后检查)
if (!pet) return null;
return (
<Card
padding="$4"
borderWidth={1}
borderColor={withAlpha(colors.icon, 0.188) as any}
backgroundColor={colors.background as any}
pressStyle={{
scale: 0.97,
opacity: 0.8,
borderColor: withAlpha(colors.tint, 0.376) as any,
}}
hoverStyle={{
borderColor: withAlpha(colors.tint, 0.251) as any,
}}
{...(onPress ? { onPress } : {})}
animation="quick"
borderRadius="$4"
>
<XStack gap="$4" alignItems="center">
{/* Pet Photo */}
{pet.photo_url ? (
<YStack
borderRadius="$3"
overflow="hidden"
borderWidth={2}
borderColor={withAlpha(colors.tint, 0.188) as any}
>
<OptimizedImage
source={pet.photo_url}
style={{
width: 70,
height: 70,
}}
contentFit="cover"
cachePolicy="memory-disk"
/>
</YStack>
) : (
<YStack
width={70}
height={70}
borderRadius="$3"
backgroundColor={withAlpha(colors.tint, 0.125) as any}
alignItems="center"
justifyContent="center"
borderWidth={2}
borderColor={withAlpha(colors.tint, 0.188) as any}
>
<Text fontSize={40}>🐱</Text>
</YStack>
)}
{/* Pet Info */}
<YStack flex={1} gap="$1">
<Text fontSize={17} fontWeight="700" color={colors.text as any}>
{pet.name || '宠物'}
</Text>
<XStack gap="$2" alignItems="center">
<Text fontSize={14} color={colors.icon as any}>
{pet.species_display ?? pet.species ?? '未知'}
</Text>
{pet.age != null && (
<>
<Text fontSize={14} color={withAlpha(colors.icon, 0.376) as any}>
·
</Text>
<Text fontSize={14} color={colors.icon as any}>
{pet.age}岁
</Text>
</>
)}
</XStack>
{pet.breed && (
<Text fontSize={13} color={withAlpha(colors.icon, 0.502) as any} numberOfLines={1}>
{pet.breed}
</Text>
)}
</YStack>
{/* Arrow Icon */}
<IconSymbol name="chevron.right" size={20} color={withAlpha(colors.icon, 0.376)} />
</XStack>
</Card>
);
}
|