- 新增挑战列表页 `app/(tabs)/challenges.tsx`,展示热门挑战卡片 - 新增挑战详情页 `app/challenges/[id].tsx`,支持排行榜、分享与参与 - 在标签栏中新增“挑战”入口,替换原有“发现”与“AI”页 - 调整标签栏间距与圆角,适配新布局 - 新增挑战相关路由常量 `TAB_CHALLENGES` - 迁移 `coach.tsx` 与 `explore.tsx` 至根目录,保持结构清晰
684 lines
19 KiB
TypeScript
684 lines
19 KiB
TypeScript
import { CHALLENGES, type Challenge } from '@/app/(tabs)/challenges';
|
||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||
import { Colors } from '@/constants/Colors';
|
||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||
import { Ionicons } from '@expo/vector-icons';
|
||
import { LinearGradient } from 'expo-linear-gradient';
|
||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||
import React, { useMemo, useState } from 'react';
|
||
import {
|
||
Dimensions,
|
||
Image,
|
||
Platform,
|
||
ScrollView,
|
||
Share,
|
||
StatusBar,
|
||
StyleSheet,
|
||
Text,
|
||
TouchableOpacity,
|
||
View,
|
||
} from 'react-native';
|
||
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
||
|
||
const { width } = Dimensions.get('window');
|
||
const HERO_HEIGHT = width * 0.86;
|
||
const BADGE_SIZE = 120;
|
||
|
||
type ChallengeDetail = {
|
||
badgeImage: string;
|
||
periodLabel: string;
|
||
durationLabel: string;
|
||
requirementLabel: string;
|
||
summary?: string;
|
||
participantsCount: number;
|
||
rankingDescription?: string;
|
||
rankings: Record<string, RankingItem[]>;
|
||
highlightTitle: string;
|
||
highlightSubtitle: string;
|
||
ctaLabel: string;
|
||
};
|
||
|
||
type RankingItem = {
|
||
id: string;
|
||
name: string;
|
||
avatar: string;
|
||
metric: string;
|
||
badge?: string;
|
||
};
|
||
|
||
const DETAIL_PRESETS: Record<string, ChallengeDetail> = {
|
||
'hydration-hippo': {
|
||
badgeImage:
|
||
'https://images.unsplash.com/photo-1616628182503-5ef2941510da?auto=format&fit=crop&w=240&q=80',
|
||
periodLabel: '9月01日 - 9月30日 · 剩余 4 天',
|
||
durationLabel: '30 天',
|
||
requirementLabel: '喝水 1500ml 15 天以上',
|
||
summary: '与河马一起练就最佳补水习惯,让身体如湖水般澄澈充盈。',
|
||
participantsCount: 9009,
|
||
rankingDescription: '榜单实时更新,记录每位补水达人每日平均饮水量。',
|
||
rankings: {
|
||
all: [
|
||
{
|
||
id: 'all-1',
|
||
name: '湖光暮色',
|
||
avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 3,200 ml',
|
||
badge: '金冠冠军',
|
||
},
|
||
{
|
||
id: 'all-2',
|
||
name: '温柔潮汐',
|
||
avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 2,980 ml',
|
||
},
|
||
{
|
||
id: 'all-3',
|
||
name: '晨雾河岸',
|
||
avatar: 'https://images.unsplash.com/photo-1544723795-432537f48b2b?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 2,860 ml',
|
||
},
|
||
],
|
||
male: [
|
||
{
|
||
id: 'male-1',
|
||
name: '北岸微风',
|
||
avatar: 'https://images.unsplash.com/photo-1488426862026-3ee34a7d66df?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 3,120 ml',
|
||
},
|
||
{
|
||
id: 'male-2',
|
||
name: '静水晚霞',
|
||
avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 2,940 ml',
|
||
},
|
||
],
|
||
female: [
|
||
{
|
||
id: 'female-1',
|
||
name: '露珠初晓',
|
||
avatar: 'https://images.unsplash.com/photo-1544723795-3fb6469f5b39?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 3,060 ml',
|
||
},
|
||
{
|
||
id: 'female-2',
|
||
name: '桔梗水语',
|
||
avatar: 'https://images.unsplash.com/photo-1521572267360-ee0c2909d518?auto=format&fit=crop&w=140&q=80',
|
||
metric: '平均 2,880 ml',
|
||
},
|
||
],
|
||
},
|
||
highlightTitle: '分享一次,免费参与',
|
||
highlightSubtitle: '解锁高级会员,无限加入挑战',
|
||
ctaLabel: '马上分享激励好友',
|
||
},
|
||
};
|
||
|
||
const DEFAULT_DETAIL: ChallengeDetail = {
|
||
badgeImage: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=240&q=80',
|
||
periodLabel: '本周进行中',
|
||
durationLabel: '30 天',
|
||
requirementLabel: '保持专注完成每日任务',
|
||
participantsCount: 3200,
|
||
highlightTitle: '立即参加,点燃动力',
|
||
highlightSubtitle: '邀请好友一起坚持,更容易收获成果',
|
||
ctaLabel: '立即加入挑战',
|
||
rankings: {
|
||
all: [],
|
||
},
|
||
};
|
||
|
||
const SEGMENTS = [
|
||
{ key: 'all', label: '全部' },
|
||
{ key: 'male', label: '男生' },
|
||
{ key: 'female', label: '女生' },
|
||
] as const;
|
||
|
||
type SegmentKey = (typeof SEGMENTS)[number]['key'];
|
||
|
||
export default function ChallengeDetailScreen() {
|
||
const { id } = useLocalSearchParams<{ id?: string }>();
|
||
const router = useRouter();
|
||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||
const colorTokens = Colors[theme];
|
||
const insets = useSafeAreaInsets();
|
||
|
||
const challenge = useMemo<Challenge | undefined>(() => {
|
||
if (!id) return undefined;
|
||
return CHALLENGES.find((item) => item.id === id);
|
||
}, [id]);
|
||
|
||
const detail = useMemo<ChallengeDetail>(() => {
|
||
if (!id) return DEFAULT_DETAIL;
|
||
return DETAIL_PRESETS[id] ?? {
|
||
...DEFAULT_DETAIL,
|
||
periodLabel: challenge?.dateRange ?? DEFAULT_DETAIL.periodLabel,
|
||
highlightTitle: `加入 ${challenge?.title ?? '挑战'}`,
|
||
};
|
||
}, [challenge?.dateRange, challenge?.title, id]);
|
||
|
||
const [segment, setSegment] = useState<SegmentKey>('all');
|
||
|
||
const rankingData = detail.rankings[segment] ?? detail.rankings.all ?? [];
|
||
|
||
const handleShare = async () => {
|
||
if (!challenge) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await Share.share({
|
||
title: challenge.title,
|
||
message: `我正在参与「${challenge.title}」,一起坚持吧!`,
|
||
url: challenge.image,
|
||
});
|
||
} catch (error) {
|
||
console.warn('分享失败', error);
|
||
}
|
||
};
|
||
|
||
const handleJoin = () => {
|
||
// 当前没有具体业务流程,先回退到挑战列表
|
||
router.back();
|
||
};
|
||
|
||
if (!challenge) {
|
||
return (
|
||
<SafeAreaView style={[styles.safeArea, { backgroundColor: colorTokens.background }]}>
|
||
<HeaderBar title="挑战详情" onBack={() => router.back()} withSafeTop transparent={false} />
|
||
<View style={styles.missingContainer}>
|
||
<Text style={[styles.missingText, { color: colorTokens.textSecondary }]}>未找到该挑战,稍后再试试吧。</Text>
|
||
</View>
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<SafeAreaView style={styles.safeArea} edges={['bottom']} >
|
||
<StatusBar barStyle="light-content" />
|
||
<View
|
||
pointerEvents="box-none"
|
||
style={[styles.headerOverlay, { paddingTop: insets.top }]}
|
||
>
|
||
<HeaderBar
|
||
title=""
|
||
tone="light"
|
||
transparent
|
||
withSafeTop={false}
|
||
right={
|
||
<TouchableOpacity style={styles.circularButton} activeOpacity={0.85} onPress={handleShare}>
|
||
<Ionicons name="share-social-outline" size={20} color="#ffffff" />
|
||
</TouchableOpacity>
|
||
}
|
||
/>
|
||
</View>
|
||
|
||
<ScrollView
|
||
style={styles.scrollView}
|
||
bounces
|
||
showsVerticalScrollIndicator={false}
|
||
contentContainerStyle={[styles.scrollContent]}
|
||
>
|
||
<View style={styles.heroContainer}>
|
||
<Image source={{ uri: challenge.image }} style={styles.heroImage} resizeMode="cover" />
|
||
<LinearGradient
|
||
colors={['rgba(0,0,0,0.35)', 'rgba(0,0,0,0.15)', 'rgba(244, 246, 255, 1)']}
|
||
style={StyleSheet.absoluteFillObject}
|
||
/>
|
||
</View>
|
||
|
||
<View style={styles.badgeWrapper}>
|
||
<View style={styles.badgeShadow}>
|
||
<Image source={{ uri: detail.badgeImage }} style={styles.badgeImage} resizeMode="cover" />
|
||
</View>
|
||
</View>
|
||
|
||
<View style={styles.headerTextBlock}>
|
||
<Text style={styles.periodLabel}>{detail.periodLabel}</Text>
|
||
<Text style={styles.title}>{challenge.title}</Text>
|
||
{detail.summary ? <Text style={styles.summary}>{detail.summary}</Text> : null}
|
||
</View>
|
||
|
||
<View style={styles.detailCard}>
|
||
<View style={styles.detailRow}>
|
||
<View style={styles.detailIconWrapper}>
|
||
<Ionicons name="calendar-outline" size={20} color="#4F5BD5" />
|
||
</View>
|
||
<View style={styles.detailTextWrapper}>
|
||
<Text style={styles.detailLabel}>{challenge.dateRange}</Text>
|
||
<Text style={styles.detailMeta}>{detail.durationLabel}</Text>
|
||
</View>
|
||
</View>
|
||
|
||
<View style={styles.detailRow}>
|
||
<View style={styles.detailIconWrapper}>
|
||
<Ionicons name="flag-outline" size={20} color="#4F5BD5" />
|
||
</View>
|
||
<View style={styles.detailTextWrapper}>
|
||
<Text style={styles.detailLabel}>{detail.requirementLabel}</Text>
|
||
<Text style={styles.detailMeta}>按日打卡自动累计</Text>
|
||
</View>
|
||
</View>
|
||
|
||
<View style={styles.detailRow}>
|
||
<View style={styles.detailIconWrapper}>
|
||
<Ionicons name="people-outline" size={20} color="#4F5BD5" />
|
||
</View>
|
||
<View style={[styles.detailTextWrapper, { flex: 1 }]}
|
||
>
|
||
<Text style={styles.detailLabel}>{detail.participantsCount.toLocaleString('zh-CN')} 人正在参与</Text>
|
||
<View style={styles.avatarRow}>
|
||
{challenge.avatars.slice(0, 6).map((avatar, index) => (
|
||
<Image
|
||
key={`${avatar}-${index}`}
|
||
source={{ uri: avatar }}
|
||
style={[styles.avatar, index > 0 && styles.avatarOffset]}
|
||
/>
|
||
))}
|
||
<TouchableOpacity style={styles.moreAvatarButton}>
|
||
<Text style={styles.moreAvatarText}>更多</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
<View style={styles.sectionHeader}>
|
||
<Text style={styles.sectionTitle}>排行榜</Text>
|
||
<TouchableOpacity>
|
||
<Text style={styles.sectionAction}>查看全部</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
{detail.rankingDescription ? (
|
||
<Text style={styles.sectionSubtitle}>{detail.rankingDescription}</Text>
|
||
) : null}
|
||
|
||
<View style={styles.segmentedControl}>
|
||
{SEGMENTS.map(({ key, label }) => {
|
||
const isActive = segment === key;
|
||
const disabled = !(detail.rankings[key] && detail.rankings[key].length);
|
||
return (
|
||
<TouchableOpacity
|
||
key={key}
|
||
style={[styles.segmentButton, isActive && styles.segmentButtonActive, disabled && styles.segmentDisabled]}
|
||
activeOpacity={disabled ? 1 : 0.8}
|
||
onPress={() => {
|
||
if (disabled) return;
|
||
setSegment(key);
|
||
}}
|
||
>
|
||
<Text style={[styles.segmentLabel, isActive && styles.segmentLabelActive, disabled && styles.segmentLabelDisabled]}>
|
||
{label}
|
||
</Text>
|
||
</TouchableOpacity>
|
||
);
|
||
})}
|
||
</View>
|
||
|
||
<View style={styles.rankingCard}>
|
||
{rankingData.length ? (
|
||
rankingData.map((item, index) => (
|
||
<View key={item.id} style={[styles.rankingRow, index > 0 && styles.rankingRowDivider]}>
|
||
<View style={styles.rankingOrderCircle}>
|
||
<Text style={styles.rankingOrder}>{index + 1}</Text>
|
||
</View>
|
||
<Image source={{ uri: item.avatar }} style={styles.rankingAvatar} />
|
||
<View style={styles.rankingInfo}>
|
||
<Text style={styles.rankingName}>{item.name}</Text>
|
||
<Text style={styles.rankingMetric}>{item.metric}</Text>
|
||
</View>
|
||
{item.badge ? <Text style={styles.rankingBadge}>{item.badge}</Text> : null}
|
||
</View>
|
||
))
|
||
) : (
|
||
<View style={styles.emptyRanking}>
|
||
<Text style={styles.emptyRankingText}>榜单即将开启,快来抢占席位。</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
|
||
<View style={styles.highlightCard}>
|
||
<LinearGradient
|
||
colors={['#5E8BFF', '#6B6CFF']}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 1 }}
|
||
style={StyleSheet.absoluteFillObject}
|
||
/>
|
||
<Text style={styles.highlightTitle}>{detail.highlightTitle}</Text>
|
||
<Text style={styles.highlightSubtitle}>{detail.highlightSubtitle}</Text>
|
||
<TouchableOpacity style={styles.highlightButton} activeOpacity={0.9} onPress={handleJoin}>
|
||
<Text style={styles.highlightButtonLabel}>{detail.ctaLabel}</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</ScrollView>
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
safeArea: {
|
||
flex: 1,
|
||
backgroundColor: '#f3f4fb',
|
||
},
|
||
headerOverlay: {
|
||
position: 'absolute',
|
||
left: 0,
|
||
right: 0,
|
||
top: 0,
|
||
zIndex: 20,
|
||
},
|
||
heroContainer: {
|
||
height: HERO_HEIGHT,
|
||
width: '100%',
|
||
overflow: 'hidden',
|
||
borderBottomLeftRadius: 36,
|
||
borderBottomRightRadius: 36,
|
||
},
|
||
heroImage: {
|
||
width: '100%',
|
||
height: '100%',
|
||
},
|
||
scrollView: {
|
||
flex: 1,
|
||
},
|
||
scrollContent: {
|
||
paddingBottom: Platform.select({ ios: 40, default: 28 }),
|
||
},
|
||
badgeWrapper: {
|
||
alignItems: 'center',
|
||
marginTop: -BADGE_SIZE / 2,
|
||
},
|
||
badgeShadow: {
|
||
width: BADGE_SIZE,
|
||
height: BADGE_SIZE,
|
||
borderRadius: BADGE_SIZE / 2,
|
||
backgroundColor: '#fff',
|
||
padding: 12,
|
||
shadowColor: 'rgba(17, 24, 39, 0.2)',
|
||
shadowOpacity: 0.25,
|
||
shadowRadius: 18,
|
||
shadowOffset: { width: 0, height: 10 },
|
||
elevation: 12,
|
||
},
|
||
badgeImage: {
|
||
flex: 1,
|
||
borderRadius: BADGE_SIZE / 2,
|
||
},
|
||
headerTextBlock: {
|
||
paddingHorizontal: 24,
|
||
marginTop: 24,
|
||
alignItems: 'center',
|
||
},
|
||
periodLabel: {
|
||
fontSize: 14,
|
||
color: '#596095',
|
||
letterSpacing: 0.2,
|
||
},
|
||
title: {
|
||
marginTop: 10,
|
||
fontSize: 24,
|
||
fontWeight: '800',
|
||
color: '#1c1f3a',
|
||
textAlign: 'center',
|
||
},
|
||
summary: {
|
||
marginTop: 12,
|
||
fontSize: 14,
|
||
lineHeight: 20,
|
||
color: '#7080b4',
|
||
textAlign: 'center',
|
||
},
|
||
detailCard: {
|
||
marginTop: 28,
|
||
marginHorizontal: 20,
|
||
padding: 20,
|
||
borderRadius: 28,
|
||
backgroundColor: '#ffffff',
|
||
shadowColor: 'rgba(30, 41, 59, 0.18)',
|
||
shadowOpacity: 0.2,
|
||
shadowRadius: 20,
|
||
shadowOffset: { width: 0, height: 12 },
|
||
elevation: 8,
|
||
gap: 20,
|
||
},
|
||
detailRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
},
|
||
detailIconWrapper: {
|
||
width: 42,
|
||
height: 42,
|
||
borderRadius: 21,
|
||
backgroundColor: '#EFF1FF',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
detailTextWrapper: {
|
||
marginLeft: 14,
|
||
},
|
||
detailLabel: {
|
||
fontSize: 15,
|
||
fontWeight: '600',
|
||
color: '#1c1f3a',
|
||
},
|
||
detailMeta: {
|
||
marginTop: 4,
|
||
fontSize: 12,
|
||
color: '#6f7ba7',
|
||
},
|
||
avatarRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
marginTop: 12,
|
||
},
|
||
avatar: {
|
||
width: 36,
|
||
height: 36,
|
||
borderRadius: 18,
|
||
borderWidth: 2,
|
||
borderColor: '#fff',
|
||
},
|
||
avatarOffset: {
|
||
marginLeft: -12,
|
||
},
|
||
moreAvatarButton: {
|
||
marginLeft: 12,
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 6,
|
||
borderRadius: 14,
|
||
backgroundColor: '#EEF0FF',
|
||
},
|
||
moreAvatarText: {
|
||
fontSize: 12,
|
||
color: '#4F5BD5',
|
||
fontWeight: '600',
|
||
},
|
||
sectionHeader: {
|
||
marginTop: 36,
|
||
marginHorizontal: 24,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
},
|
||
sectionTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '700',
|
||
color: '#1c1f3a',
|
||
},
|
||
sectionAction: {
|
||
fontSize: 13,
|
||
fontWeight: '600',
|
||
color: '#5F6BF0',
|
||
},
|
||
sectionSubtitle: {
|
||
marginTop: 8,
|
||
marginHorizontal: 24,
|
||
fontSize: 13,
|
||
color: '#6f7ba7',
|
||
lineHeight: 18,
|
||
},
|
||
segmentedControl: {
|
||
marginTop: 20,
|
||
marginHorizontal: 24,
|
||
borderRadius: 20,
|
||
backgroundColor: '#EAECFB',
|
||
padding: 4,
|
||
flexDirection: 'row',
|
||
},
|
||
segmentButton: {
|
||
flex: 1,
|
||
paddingVertical: 8,
|
||
borderRadius: 16,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
segmentButtonActive: {
|
||
backgroundColor: '#fff',
|
||
shadowColor: 'rgba(79, 91, 213, 0.25)',
|
||
shadowOpacity: 0.3,
|
||
shadowRadius: 10,
|
||
shadowOffset: { width: 0, height: 6 },
|
||
elevation: 4,
|
||
},
|
||
segmentDisabled: {
|
||
opacity: 0.5,
|
||
},
|
||
segmentLabel: {
|
||
fontSize: 13,
|
||
fontWeight: '600',
|
||
color: '#6372C6',
|
||
},
|
||
segmentLabelActive: {
|
||
color: '#4F5BD5',
|
||
},
|
||
segmentLabelDisabled: {
|
||
color: '#9AA3CF',
|
||
},
|
||
rankingCard: {
|
||
marginTop: 20,
|
||
marginHorizontal: 24,
|
||
borderRadius: 24,
|
||
backgroundColor: '#ffffff',
|
||
paddingVertical: 10,
|
||
shadowColor: 'rgba(30, 41, 59, 0.12)',
|
||
shadowOpacity: 0.16,
|
||
shadowRadius: 18,
|
||
shadowOffset: { width: 0, height: 10 },
|
||
elevation: 6,
|
||
},
|
||
rankingRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
paddingVertical: 12,
|
||
paddingHorizontal: 18,
|
||
},
|
||
rankingRowDivider: {
|
||
borderTopWidth: StyleSheet.hairlineWidth,
|
||
borderTopColor: '#E5E7FF',
|
||
},
|
||
rankingOrderCircle: {
|
||
width: 32,
|
||
height: 32,
|
||
borderRadius: 16,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
backgroundColor: '#EEF0FF',
|
||
marginRight: 12,
|
||
},
|
||
rankingOrder: {
|
||
fontSize: 15,
|
||
fontWeight: '700',
|
||
color: '#4F5BD5',
|
||
},
|
||
rankingAvatar: {
|
||
width: 44,
|
||
height: 44,
|
||
borderRadius: 22,
|
||
marginRight: 14,
|
||
},
|
||
rankingInfo: {
|
||
flex: 1,
|
||
},
|
||
rankingName: {
|
||
fontSize: 15,
|
||
fontWeight: '700',
|
||
color: '#1c1f3a',
|
||
},
|
||
rankingMetric: {
|
||
marginTop: 4,
|
||
fontSize: 13,
|
||
color: '#6f7ba7',
|
||
},
|
||
rankingBadge: {
|
||
fontSize: 12,
|
||
color: '#A67CFF',
|
||
fontWeight: '700',
|
||
},
|
||
emptyRanking: {
|
||
paddingVertical: 40,
|
||
alignItems: 'center',
|
||
},
|
||
emptyRankingText: {
|
||
fontSize: 14,
|
||
color: '#6f7ba7',
|
||
},
|
||
highlightCard: {
|
||
marginTop: 32,
|
||
marginHorizontal: 24,
|
||
borderRadius: 28,
|
||
paddingVertical: 28,
|
||
paddingHorizontal: 24,
|
||
overflow: 'hidden',
|
||
},
|
||
highlightTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '800',
|
||
color: '#ffffff',
|
||
},
|
||
highlightSubtitle: {
|
||
marginTop: 10,
|
||
fontSize: 14,
|
||
color: 'rgba(255,255,255,0.85)',
|
||
lineHeight: 20,
|
||
},
|
||
highlightButton: {
|
||
marginTop: 22,
|
||
backgroundColor: 'rgba(255,255,255,0.18)',
|
||
paddingVertical: 12,
|
||
borderRadius: 22,
|
||
alignItems: 'center',
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(247,248,255,0.5)',
|
||
},
|
||
highlightButtonLabel: {
|
||
fontSize: 15,
|
||
fontWeight: '700',
|
||
color: '#ffffff',
|
||
},
|
||
circularButton: {
|
||
width: 40,
|
||
height: 40,
|
||
borderRadius: 20,
|
||
backgroundColor: 'rgba(255,255,255,0.24)',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(255,255,255,0.45)',
|
||
},
|
||
shareIcon: {
|
||
fontSize: 18,
|
||
color: '#ffffff',
|
||
fontWeight: '700',
|
||
},
|
||
missingContainer: {
|
||
flex: 1,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
paddingHorizontal: 32,
|
||
},
|
||
missingText: {
|
||
fontSize: 16,
|
||
textAlign: 'center',
|
||
},
|
||
});
|