feat: redesenho premium mobile-first dos ecras ShopDetails e Profile

This commit is contained in:
2026-05-26 16:08:27 +01:00
parent d07e0e8e4d
commit 6726c4d539
2 changed files with 1175 additions and 325 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ import { Button } from '../components/ui/Button';
import { currency } from '../lib/format';
import { RootStackParamList } from '../navigation/types';
import { colors, radius, shadows } from '../lib/theme';
import { Ionicons } from '@expo/vector-icons';
type Tab = 'servicos' | 'barbeiros' | 'produtos' | 'detalhes';
@@ -34,6 +35,7 @@ export default function ShopDetails() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.centerState}>
<Ionicons name="sync-outline" size={40} color={colors.primary} style={styles.loadingSpinner} />
<Text style={styles.centerTitle}>Carregando...</Text>
</View>
</SafeAreaView>
@@ -44,6 +46,7 @@ export default function ShopDetails() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.centerState}>
<Ionicons name="alert-circle-outline" size={48} color={colors.danger} />
<Text style={styles.centerTitle}>Não encontrado</Text>
<Button onPress={() => navigation.navigate('Explore')}>Voltar</Button>
</View>
@@ -69,62 +72,97 @@ export default function ShopDetails() {
const schedule = shop.schedule || defaultSchedule;
const currentDayIndex = new Date().getDay() === 0 ? 6 : new Date().getDay() - 1;
const isFav = isFavorite(shop.id);
return (
<View style={styles.container}>
<ScrollView bounces={false} contentContainerStyle={styles.scrollContent}>
<ScrollView bounces={false} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
{/* Cover Hero Banner */}
<View style={styles.hero}>
{shop.imageUrl ? (
<Image source={{ uri: shop.imageUrl }} style={styles.heroImage} />
) : (
<View style={styles.heroPlaceholder}><Text style={styles.heroPlaceholderText}>💈</Text></View>
<View style={styles.heroPlaceholder}>
<Ionicons name="storefront-outline" size={64} color={colors.primary} style={{ opacity: 0.6 }} />
</View>
)}
<View style={styles.heroOverlay} />
<SafeAreaView style={styles.heroHeader}>
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backBtn}>
<Text style={styles.backIcon}></Text>
<SafeAreaView style={styles.heroHeader} edges={['top']}>
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backBtn} activeOpacity={0.8}>
<Ionicons name="chevron-back" size={24} color={colors.textInverse} />
</TouchableOpacity>
<TouchableOpacity onPress={() => toggleFavorite(shop.id)} style={styles.favBtn}>
<Text style={[styles.favIcon, isFavorite(shop.id) && styles.favActive]}>
{isFavorite(shop.id) ? '♥' : '♡'}
</Text>
<TouchableOpacity onPress={() => toggleFavorite(shop.id)} style={styles.favBtn} activeOpacity={0.8}>
<Ionicons
name={isFav ? "heart" : "heart-outline"}
size={24}
color={isFav ? colors.danger : colors.textInverse}
/>
</TouchableOpacity>
</SafeAreaView>
</View>
{/* Overlapping Info Summary Sheet */}
<View style={styles.summaryWrap}>
<View style={styles.summaryCard}>
<View style={styles.summaryTop}>
<View style={styles.ratingBox}>
<Text style={styles.ratingValue}> {shop.rating.toFixed(1)}</Text>
<View style={styles.ratingBadge}>
<Ionicons name="star" size={14} color={colors.star} />
<Text style={styles.ratingValue}>{(shop.rating || 0).toFixed(1)}</Text>
</View>
<View style={styles.servicesCountBadge}>
<Text style={styles.summaryMeta}>{shop.services.length} serviços</Text>
</View>
<Text style={styles.summaryMeta}>{shop.services.length} serviços</Text>
</View>
<Text style={styles.shopName}>{shop.name}</Text>
<TouchableOpacity onPress={openMap} style={styles.addrBox}>
<Text style={styles.shopAddr} numberOfLines={2}>📍 {shop.address}</Text>
<TouchableOpacity onPress={openMap} style={styles.addrBox} activeOpacity={0.7}>
<Ionicons name="location-outline" size={16} color={colors.primary} />
<Text style={styles.shopAddr} numberOfLines={2}>
{shop.address && shop.address !== 'Endereço a definir' ? shop.address : 'Endereço por definir'}
</Text>
</TouchableOpacity>
{/* Quick Stats Grid */}
<View style={styles.quickStats}>
<View style={styles.quickStat}>
<Text style={styles.quickValue}>{shop.barbers.length}</Text>
<Text style={styles.quickLabel}>Equipa</Text>
<Ionicons name="people-outline" size={18} color={colors.primary} />
<View>
<Text style={styles.quickValue}>{shop.barbers.length}</Text>
<Text style={styles.quickLabel}>Equipa</Text>
</View>
</View>
<View style={styles.quickStat}>
<Text style={styles.quickValue}>{shop.products.length}</Text>
<Text style={styles.quickLabel}>Produtos</Text>
<Ionicons name="basket-outline" size={18} color={colors.primary} />
<View>
<Text style={styles.quickValue}>{shop.products.length}</Text>
<Text style={styles.quickLabel}>Produtos</Text>
</View>
</View>
<View style={styles.quickStat}>
<Text style={styles.quickValue}>{schedule[currentDayIndex]?.closed ? 'Fechado' : 'Aberto'}</Text>
<Text style={styles.quickLabel}>Hoje</Text>
<Ionicons name="time-outline" size={18} color={colors.primary} />
<View>
<Text style={[styles.quickValue, schedule[currentDayIndex]?.closed && styles.closedText]}>
{schedule[currentDayIndex]?.closed ? 'Fechado' : 'Aberto'}
</Text>
<Text style={styles.quickLabel}>Hoje</Text>
</View>
</View>
</View>
<Button onPress={() => reserveService(shop.services[0]?.id)} disabled={shop.services.length === 0}>
Agendar agora
<Button
onPress={() => reserveService(shop.services[0]?.id)}
disabled={shop.services.length === 0}
style={styles.reserveBtn}
>
Agendar agora
</Button>
</View>
</View>
{/* Tab Selector section */}
<View style={styles.tabSection}>
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.tabsScroll}>
{[
@@ -137,6 +175,7 @@ export default function ShopDetails() {
key={id}
onPress={() => setTab(id as Tab)}
style={[styles.tabItem, tab === id && styles.tabItemActive]}
activeOpacity={0.8}
>
<Text style={[styles.tabText, tab === id && styles.tabTextActive]}>{label}</Text>
</TouchableOpacity>
@@ -144,71 +183,135 @@ export default function ShopDetails() {
</ScrollView>
</View>
{/* Listagem de Conteúdo */}
{/* Content Tabs Area */}
<View style={styles.contentArea}>
{tab === 'servicos' && (
<View style={styles.grid}>
{shop.services.map((s) => (
<Card key={s.id} style={styles.serviceCard}>
<View style={styles.svcInfo}>
<Text style={styles.svcName}>{s.name}</Text>
<Text style={styles.svcMeta}>{s.duration} min · {currency(s.price)}</Text>
</View>
<Button size="sm" onPress={() => reserveService(s.id)}>Agendar</Button>
</Card>
))}
{shop.services.length > 0 ? (
shop.services.map((s) => (
<Card key={s.id} style={styles.serviceCard}>
<View style={styles.svcInfo}>
<Text style={styles.svcName}>{s.name}</Text>
<View style={styles.svcMetaRow}>
<Ionicons name="time-outline" size={13} color={colors.textMuted} />
<Text style={styles.svcMeta}>{s.duration} min</Text>
<Text style={styles.bulletSeparator}></Text>
<Text style={styles.svcPrice}>{currency(s.price)}</Text>
</View>
</View>
<Button size="sm" onPress={() => reserveService(s.id)} style={styles.svcBookBtn}>
Agendar
</Button>
</Card>
))
) : (
<View style={styles.emptyContentBlock}>
<Ionicons name="cut-outline" size={32} color={colors.textSubtle} />
<Text style={styles.emptyContentText}>Sem serviços disponíveis de momento.</Text>
</View>
)}
</View>
)}
{tab === 'barbeiros' && (
<View style={styles.barberList}>
{shop.barbers.map((b) => (
<Card key={b.id} style={styles.barberCard}>
<View style={styles.barberAvatar}>
<Text style={styles.avatarTxt}>{b.name.charAt(0)}</Text>
</View>
<View style={{ flex: 1 }}>
<Text style={styles.barberName}>{b.name}</Text>
<Text style={styles.barberSpecs}>{b.specialties.join(', ')}</Text>
</View>
</Card>
))}
{shop.barbers.length > 0 ? (
shop.barbers.map((b) => (
<Card key={b.id} style={styles.barberCard}>
<View style={styles.barberAvatar}>
<Text style={styles.avatarTxt}>{b.name.charAt(0).toUpperCase()}</Text>
</View>
<View style={styles.barberInfo}>
<Text style={styles.barberName}>{b.name}</Text>
<Text style={styles.barberSpecs} numberOfLines={1}>
{b.specialties.length > 0 ? b.specialties.join(', ') : 'Barbeiro especialista'}
</Text>
</View>
<View style={styles.barberBadge}>
<Ionicons name="shield-checkmark" size={14} color={colors.primary} />
</View>
</Card>
))
) : (
<View style={styles.emptyContentBlock}>
<Ionicons name="people-outline" size={32} color={colors.textSubtle} />
<Text style={styles.emptyContentText}>Sem profissionais disponíveis de momento.</Text>
</View>
)}
</View>
)}
{tab === 'produtos' && (
<View style={styles.grid}>
{shop.products.map((p) => (
<Card key={p.id} style={styles.productCard}>
<View style={styles.prodHeader}>
<Text style={styles.prodName}>{p.name}</Text>
<Text style={styles.prodPrice}>{currency(p.price)}</Text>
</View>
<Text style={styles.prodStock}>{p.stock} em stock</Text>
<Button size="sm" variant="outline" onPress={() => addProduct(p.id)} disabled={p.stock <= 0}>
{p.stock > 0 ? 'Adicionar' : 'Esgotado'}
</Button>
</Card>
))}
{shop.products.length > 0 ? (
shop.products.map((p) => (
<Card key={p.id} style={styles.productCard}>
<View style={styles.prodHeader}>
<Text style={styles.prodName} numberOfLines={1}>{p.name}</Text>
<Text style={styles.prodPrice}>{currency(p.price)}</Text>
</View>
<View style={styles.productMetaRow}>
<View style={[styles.stockBadge, p.stock <= 0 && styles.outOfStockBadge]}>
<Text style={[styles.stockText, p.stock <= 0 && styles.outOfStockText]}>
{p.stock > 0 ? `${p.stock} em stock` : 'Esgotado'}
</Text>
</View>
</View>
<Button
size="sm"
variant={p.stock > 0 ? "outline" : "ghost"}
onPress={() => addProduct(p.id)}
disabled={p.stock <= 0}
style={styles.productBtn}
>
{p.stock > 0 ? 'Adicionar 🛒' : 'Indisponível'}
</Button>
</Card>
))
) : (
<View style={styles.emptyContentBlock}>
<Ionicons name="basket-outline" size={32} color={colors.textSubtle} />
<Text style={styles.emptyContentText}>Sem produtos disponíveis de momento.</Text>
</View>
)}
</View>
)}
{tab === 'detalhes' && (
<Card style={styles.detailsBox}>
<Text style={styles.detailTitle}>Horário</Text>
{schedule.map((s, idx) => (
<View key={s.day} style={styles.schedRow}>
<Text style={[styles.schedDay, idx === currentDayIndex && styles.today]}>{s.day}</Text>
<Text style={[styles.schedTime, idx === currentDayIndex && styles.today]}>
{s.closed ? 'Fechado' : `${s.open} - ${s.close}`}
</Text>
</View>
))}
<View style={styles.detailTitleRow}>
<Ionicons name="calendar-outline" size={18} color={colors.primary} />
<Text style={styles.detailTitle}>Horário de Funcionamento</Text>
</View>
<View style={styles.scheduleList}>
{schedule.map((s, idx) => (
<View key={s.day} style={[styles.schedRow, idx === currentDayIndex && styles.schedRowToday]}>
<Text style={[styles.schedDay, idx === currentDayIndex && styles.today]}>
{s.day} {idx === currentDayIndex && '• Hoje'}
</Text>
<Text style={[styles.schedTime, idx === currentDayIndex && styles.today]}>
{s.closed ? 'Fechado' : `${s.open} - ${s.close}`}
</Text>
</View>
))}
</View>
<View style={styles.divider} />
<Text style={styles.detailTitle}>Contacto</Text>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${shop.contacts?.phone1}`)}>
<Text style={styles.contactLink}>{shop.contacts?.phone1 || 'Não disponível'}</Text>
</TouchableOpacity>
<View style={styles.detailTitleRow}>
<Ionicons name="call-outline" size={18} color={colors.primary} />
<Text style={styles.detailTitle}>Contacto Telefónico</Text>
</View>
{shop.contacts?.phone1 ? (
<TouchableOpacity onPress={() => Linking.openURL(`tel:${shop.contacts?.phone1}`)} style={styles.phoneLinkBox} activeOpacity={0.7}>
<Ionicons name="phone-portrait-outline" size={18} color={colors.primaryDark} />
<Text style={styles.contactLink}>{shop.contacts?.phone1}</Text>
</TouchableOpacity>
) : (
<Text style={styles.noContactText}>Contacto telefónico não disponível.</Text>
)}
</Card>
)}
</View>
@@ -226,7 +329,7 @@ const styles = StyleSheet.create({
paddingBottom: 40,
},
hero: {
height: 230,
height: 250,
position: 'relative',
},
heroImage: {
@@ -240,12 +343,9 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
heroPlaceholderText: {
fontSize: 64,
},
heroOverlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: colors.overlay,
backgroundColor: 'rgba(12,20,17,0.3)',
},
heroHeader: {
position: 'absolute',
@@ -258,116 +358,135 @@ const styles = StyleSheet.create({
paddingTop: 10,
},
backBtn: {
width: 44,
height: 44,
borderRadius: radius.pill,
width: 42,
height: 42,
borderRadius: 21,
backgroundColor: 'rgba(20,33,29,0.72)',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderWidth: 0.5,
borderColor: 'rgba(255,255,255,0.16)',
},
backIcon: {
color: colors.textInverse,
fontSize: 20,
fontWeight: '700',
},
favBtn: {
width: 44,
height: 44,
borderRadius: radius.pill,
width: 42,
height: 42,
borderRadius: 21,
backgroundColor: 'rgba(20,33,29,0.72)',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderWidth: 0.5,
borderColor: 'rgba(255,255,255,0.16)',
},
favIcon: {
color: colors.textInverse,
fontSize: 22,
},
favActive: {
color: colors.danger,
},
summaryWrap: {
paddingHorizontal: 20,
marginTop: -36,
marginTop: -46,
zIndex: 2,
},
summaryCard: {
backgroundColor: colors.surface,
borderRadius: radius.sm,
padding: 18,
gap: 12,
borderRadius: radius.lg,
padding: 20,
gap: 14,
borderWidth: 1,
borderColor: colors.border,
...shadows.card,
borderColor: 'rgba(15,118,110,0.06)',
shadowColor: '#102018',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.08,
shadowRadius: 16,
elevation: 4,
},
summaryTop: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
summaryMeta: {
color: colors.textMuted,
fontSize: 12,
fontWeight: '800',
textTransform: 'uppercase',
},
ratingBox: {
alignSelf: 'flex-start',
backgroundColor: colors.accent,
ratingBadge: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.accentSoft,
borderRadius: radius.pill,
paddingHorizontal: 10,
paddingVertical: 4,
gap: 4,
},
ratingValue: {
color: colors.textInverse,
color: '#7a4310',
fontSize: 12,
fontWeight: '900',
},
servicesCountBadge: {
backgroundColor: colors.primarySoft,
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: radius.pill,
},
summaryMeta: {
color: colors.primaryDark,
fontSize: 11,
fontWeight: '800',
textTransform: 'uppercase',
},
shopName: {
color: colors.text,
fontSize: 28,
lineHeight: 32,
fontSize: 26,
fontWeight: '900',
letterSpacing: -0.5,
},
addrBox: {
opacity: 0.8,
flexDirection: 'row',
alignItems: 'center',
gap: 6,
},
shopAddr: {
flex: 1,
color: colors.textMuted,
fontSize: 14,
fontWeight: '500',
},
quickStats: {
flexDirection: 'row',
gap: 10,
gap: 8,
marginTop: 2,
},
quickStat: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: colors.surfaceMuted,
borderRadius: radius.sm,
borderRadius: radius.md,
padding: 10,
borderWidth: 1,
borderColor: colors.border,
borderColor: 'rgba(15,118,110,0.05)',
},
quickValue: {
color: colors.text,
fontSize: 16,
fontSize: 14,
fontWeight: '900',
},
closedText: {
color: colors.danger,
},
quickLabel: {
color: colors.textMuted,
fontSize: 11,
fontSize: 10,
fontWeight: '700',
marginTop: 2,
textTransform: 'uppercase',
marginTop: 1,
},
reserveBtn: {
marginTop: 4,
borderRadius: radius.md,
shadowColor: colors.primary,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 3,
},
tabSection: {
backgroundColor: colors.background,
paddingVertical: 10,
marginTop: 6,
paddingVertical: 12,
marginTop: 8,
},
tabsScroll: {
paddingHorizontal: 20,
@@ -375,11 +494,11 @@ const styles = StyleSheet.create({
},
tabItem: {
paddingVertical: 10,
paddingHorizontal: 14,
paddingHorizontal: 16,
borderRadius: radius.pill,
backgroundColor: colors.surfaceMuted,
backgroundColor: colors.surface,
borderWidth: 1,
borderColor: colors.border,
borderColor: 'rgba(15,118,110,0.05)',
},
tabItemActive: {
backgroundColor: colors.primary,
@@ -394,7 +513,7 @@ const styles = StyleSheet.create({
color: colors.textInverse,
},
contentArea: {
padding: 20,
paddingHorizontal: 20,
},
grid: {
gap: 12,
@@ -404,19 +523,48 @@ const styles = StyleSheet.create({
alignItems: 'center',
padding: 16,
gap: 12,
borderRadius: radius.md,
borderWidth: 1,
borderColor: 'rgba(15,118,110,0.06)',
backgroundColor: colors.surface,
shadowColor: '#102018',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.02,
shadowRadius: 6,
elevation: 1,
},
svcInfo: {
flex: 1,
gap: 4,
gap: 6,
},
svcName: {
color: colors.text,
fontSize: 16,
fontWeight: '800',
},
svcMetaRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
svcMeta: {
color: colors.textMuted,
fontSize: 13,
fontWeight: '500',
},
bulletSeparator: {
color: colors.borderStrong,
fontSize: 12,
marginHorizontal: 2,
},
svcPrice: {
color: colors.primary,
fontSize: 14,
fontWeight: '800',
},
svcBookBtn: {
borderRadius: radius.md,
paddingHorizontal: 14,
},
barberList: {
gap: 12,
@@ -426,20 +574,30 @@ const styles = StyleSheet.create({
alignItems: 'center',
padding: 14,
gap: 14,
borderRadius: radius.md,
borderWidth: 1,
borderColor: 'rgba(15,118,110,0.06)',
backgroundColor: colors.surface,
},
barberAvatar: {
width: 50,
height: 50,
borderRadius: radius.md,
width: 48,
height: 48,
borderRadius: 24,
backgroundColor: colors.primarySoft,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: 'rgba(15,118,110,0.1)',
},
avatarTxt: {
color: colors.primary,
fontSize: 20,
fontSize: 18,
fontWeight: '900',
},
barberInfo: {
flex: 1,
gap: 2,
},
barberName: {
color: colors.text,
fontSize: 16,
@@ -448,15 +606,29 @@ const styles = StyleSheet.create({
barberSpecs: {
color: colors.textMuted,
fontSize: 12,
fontWeight: '500',
},
barberBadge: {
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: colors.primarySoft,
alignItems: 'center',
justifyContent: 'center',
},
productCard: {
padding: 16,
gap: 8,
gap: 10,
borderRadius: radius.md,
borderWidth: 1,
borderColor: 'rgba(15,118,110,0.06)',
backgroundColor: colors.surface,
},
prodHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
gap: 12,
},
prodName: {
color: colors.text,
@@ -469,28 +641,69 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: '900',
},
prodStock: {
color: colors.textMuted,
fontSize: 12,
marginBottom: 4,
productMetaRow: {
flexDirection: 'row',
alignItems: 'center',
},
stockBadge: {
backgroundColor: colors.successSoft,
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: radius.xs,
},
outOfStockBadge: {
backgroundColor: colors.dangerSoft,
},
stockText: {
color: colors.success,
fontSize: 10,
fontWeight: '800',
textTransform: 'uppercase',
},
outOfStockText: {
color: colors.danger,
},
productBtn: {
borderRadius: radius.md,
marginTop: 2,
},
detailsBox: {
padding: 20,
gap: 12,
gap: 14,
borderRadius: radius.lg,
borderWidth: 1,
borderColor: 'rgba(15,118,110,0.06)',
backgroundColor: colors.surface,
},
detailTitleRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
marginBottom: 4,
},
detailTitle: {
color: colors.text,
fontSize: 18,
fontSize: 16,
fontWeight: '800',
marginBottom: 8,
},
scheduleList: {
gap: 8,
},
schedRow: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: 4,
paddingHorizontal: 8,
},
schedRowToday: {
backgroundColor: colors.primarySoft,
borderRadius: radius.sm,
paddingVertical: 6,
},
schedDay: {
color: colors.textMuted,
fontSize: 14,
fontWeight: '500',
},
schedTime: {
color: colors.text,
@@ -498,28 +711,61 @@ const styles = StyleSheet.create({
fontWeight: '600',
},
today: {
color: colors.primary,
color: colors.primaryDark,
fontWeight: '800',
},
divider: {
height: 1,
backgroundColor: colors.border,
marginVertical: 12,
backgroundColor: 'rgba(15,118,110,0.08)',
marginVertical: 6,
},
phoneLinkBox: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: colors.primarySoft,
alignSelf: 'flex-start',
paddingVertical: 8,
paddingHorizontal: 14,
borderRadius: radius.sm,
borderWidth: 0.5,
borderColor: 'rgba(15,118,110,0.1)',
},
contactLink: {
color: colors.primaryDark,
fontSize: 16,
fontWeight: '700',
fontSize: 15,
fontWeight: '800',
},
noContactText: {
color: colors.textSubtle,
fontSize: 14,
fontWeight: '500',
},
centerState: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 40,
gap: 12,
},
centerTitle: {
color: colors.text,
fontSize: 18,
fontSize: 16,
fontWeight: '800',
},
loadingSpinner: {
marginBottom: 4,
},
emptyContentBlock: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 40,
gap: 10,
},
emptyContentText: {
color: colors.textMuted,
fontSize: 14,
fontWeight: '600',
textAlign: 'center',
},
});