Skip to content

Commit 84af8b5

Browse files
feat(mobile): complete minimalist brutalist redesign of all screens
- Redesigned GroupList, GroupDetail, Profile, and AddExpense screens. - Updated child components (ListItem, BalanceCard, ExpenseCard, SectionHeader) with bold borders and hard shadows. - Applied consistent high-contrast, uppercase typography across all screens. - Standardized Brutalist design patterns (sharp edges, thick borders, offset shadows).
1 parent 117b016 commit 84af8b5

8 files changed

Lines changed: 721 additions & 759 deletions

File tree

apps/mobile/app/components/BalanceCard.tsx

Lines changed: 61 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const BalanceCard = memo(function BalanceCard({
2020
icon = 'wallet',
2121
variant = 'default',
2222
}: BalanceCardProps) {
23-
const { colors, isDark } = useAppTheme();
23+
const { colors } = useAppTheme();
2424

2525
const accentColor =
2626
variant === 'success'
@@ -30,99 +30,88 @@ export const BalanceCard = memo(function BalanceCard({
3030
: colors.primary;
3131

3232
return (
33-
<View
34-
style={[
35-
styles.card,
36-
{
37-
backgroundColor: isDark
38-
? `${accentColor}18`
39-
: `${accentColor}0A`,
40-
borderColor: isDark ? `${accentColor}30` : `${accentColor}20`,
41-
},
42-
]}
43-
>
44-
<View style={styles.iconContainer}>
45-
<View
46-
style={[
47-
styles.iconBg,
48-
{
49-
backgroundColor: `${accentColor}20`,
50-
},
51-
]}
52-
>
53-
<MaterialCommunityIcons
54-
name={icon}
55-
size={22}
56-
color={accentColor}
57-
/>
33+
<View style={styles.wrapper}>
34+
<View style={[styles.shadow, { backgroundColor: colors.border }]} />
35+
<View style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border }]}>
36+
<View style={styles.header}>
37+
<View style={[styles.iconBg, { backgroundColor: accentColor }]}>
38+
<MaterialCommunityIcons name={icon} size={24} color={colors.background} />
39+
</View>
40+
<Text style={[styles.title, { color: colors.text_secondary }]}>
41+
{title.toUpperCase()}
42+
</Text>
5843
</View>
59-
</View>
60-
<View style={styles.content}>
61-
<Text
62-
style={[
63-
styles.title,
64-
{ color: colors.text_secondary },
65-
]}
66-
>
67-
{title}
68-
</Text>
69-
<Text
70-
style={[
71-
styles.amount,
72-
{ color: colors.text_primary },
73-
]}
74-
>
75-
{amount}
76-
</Text>
77-
{subtitle ? (
78-
<Text
79-
style={[
80-
styles.subtitle,
81-
{ color: colors.text_secondary },
82-
]}
83-
>
84-
{subtitle}
44+
45+
<View style={styles.content}>
46+
<Text style={[styles.amount, { color: colors.text_primary }]}>
47+
{amount}
8548
</Text>
86-
) : null}
49+
{subtitle ? (
50+
<View style={[styles.subtitleBadge, { backgroundColor: accentColor }]}>
51+
<Text style={[styles.subtitleText, { color: colors.background }]}>
52+
{subtitle.toUpperCase()}
53+
</Text>
54+
</View>
55+
) : null}
56+
</View>
8757
</View>
8858
</View>
8959
);
9060
});
9161

9262
const styles = StyleSheet.create({
63+
wrapper: {
64+
position: 'relative',
65+
marginBottom: 8,
66+
marginRight: 8,
67+
},
68+
shadow: {
69+
position: 'absolute',
70+
top: 6,
71+
left: 6,
72+
right: -6,
73+
bottom: -6,
74+
backgroundColor: '#000000',
75+
},
9376
card: {
94-
borderRadius: 16,
9577
padding: spacing.lg,
96-
borderWidth: 1,
78+
borderWidth: 3,
79+
gap: spacing.md,
80+
},
81+
header: {
9782
flexDirection: 'row',
9883
alignItems: 'center',
9984
gap: spacing.md,
10085
},
101-
iconContainer: {},
10286
iconBg: {
103-
width: 44,
104-
height: 44,
105-
borderRadius: 14,
87+
width: 40,
88+
height: 40,
10689
alignItems: 'center',
10790
justifyContent: 'center',
10891
},
109-
content: {
110-
flex: 1,
111-
},
11292
title: {
11393
fontSize: 12,
114-
fontWeight: '600',
115-
letterSpacing: 0.8,
116-
textTransform: 'uppercase',
117-
marginBottom: 2,
94+
fontWeight: '900',
95+
letterSpacing: 2,
96+
},
97+
content: {
98+
flexDirection: 'row',
99+
alignItems: 'flex-end',
100+
justifyContent: 'space-between',
101+
gap: spacing.md,
118102
},
119103
amount: {
120-
fontSize: 24,
121-
fontWeight: '700',
122-
letterSpacing: -0.5,
104+
fontSize: 32,
105+
fontWeight: '900',
106+
letterSpacing: -1,
107+
},
108+
subtitleBadge: {
109+
paddingHorizontal: 8,
110+
paddingVertical: 4,
123111
},
124-
subtitle: {
125-
fontSize: 13,
126-
marginTop: 2,
112+
subtitleText: {
113+
fontSize: 10,
114+
fontWeight: '900',
115+
letterSpacing: 1,
127116
},
128117
});

apps/mobile/app/components/ExpenseCard.tsx

Lines changed: 97 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -24,120 +24,135 @@ export const ExpenseCard = memo(function ExpenseCard({
2424
date,
2525
onPress,
2626
}: ExpenseCardProps) {
27-
const { colors, isDark } = useAppTheme();
27+
const { colors } = useAppTheme();
2828

2929
return (
30-
<TouchableOpacity
31-
style={[
32-
styles.card,
33-
{
34-
backgroundColor: isDark ? colors.card : colors.surface,
35-
borderColor: colors.border,
36-
},
37-
]}
38-
onPress={onPress}
39-
activeOpacity={0.7}
40-
accessibilityLabel={`Expense: ${description}, ${amount}`}
41-
accessibilityRole="button"
42-
>
43-
<View style={styles.row}>
44-
{/* Payer Avatar */}
45-
<View style={[styles.avatar, { backgroundColor: colors.primary }]}>
46-
<Text style={styles.avatarText}>{payerInitials}</Text>
47-
</View>
48-
49-
{/* Content */}
50-
<View style={styles.content}>
51-
<Text
52-
style={[styles.description, { color: colors.text_primary }]}
53-
numberOfLines={1}
54-
>
55-
{description}
56-
</Text>
57-
<View style={styles.metaRow}>
58-
<Text style={[styles.meta, { color: colors.text_secondary }]}>
59-
{payerName}
30+
<View style={styles.wrapper}>
31+
<View style={[styles.shadow, { backgroundColor: colors.border }]} />
32+
<TouchableOpacity
33+
style={[
34+
styles.card,
35+
{
36+
backgroundColor: colors.surface,
37+
borderColor: colors.border,
38+
},
39+
]}
40+
onPress={onPress}
41+
activeOpacity={0.8}
42+
accessibilityLabel={`Expense: ${description}, ${amount}`}
43+
accessibilityRole="button"
44+
>
45+
<View style={styles.topRow}>
46+
<View style={[styles.avatar, { backgroundColor: colors.primary }]}>
47+
<Text style={[styles.avatarText, { color: colors.background }]}>{payerInitials}</Text>
48+
</View>
49+
<View style={styles.descriptionContainer}>
50+
<Text style={[styles.description, { color: colors.text_primary }]} numberOfLines={1}>
51+
{description.toUpperCase()}
6052
</Text>
61-
<View style={styles.dot} />
62-
<View style={styles.chipRow}>
63-
<MaterialCommunityIcons
64-
name="account-multiple"
65-
size={13}
66-
color={colors.text_secondary}
67-
/>
68-
<Text style={[styles.meta, { color: colors.text_secondary }]}>
69-
{participantCount}
70-
</Text>
71-
</View>
72-
<View style={styles.dot} />
73-
<Text style={[styles.meta, { color: colors.text_secondary }]}>
74-
{date}
53+
<Text style={[styles.payer, { color: colors.text_secondary }]}>
54+
BY {payerName.toUpperCase()}
7555
</Text>
7656
</View>
57+
<Text style={[styles.amount, { color: colors.text_primary }]}>
58+
{amount}
59+
</Text>
7760
</View>
7861

79-
{/* Amount */}
80-
<Text style={[styles.amount, { color: colors.text_primary }]}>
81-
{amount}
82-
</Text>
83-
</View>
84-
</TouchableOpacity>
62+
<View style={[styles.divider, { backgroundColor: colors.border }]} />
63+
64+
<View style={styles.bottomRow}>
65+
<View style={styles.metaItem}>
66+
<MaterialCommunityIcons name="account-multiple" size={16} color={colors.primary} />
67+
<Text style={[styles.metaText, { color: colors.text_secondary }]}>
68+
{participantCount} INVOLVED
69+
</Text>
70+
</View>
71+
<Text style={[styles.date, { color: colors.text_secondary }]}>
72+
{date.toUpperCase()}
73+
</Text>
74+
</View>
75+
</TouchableOpacity>
76+
</View>
8577
);
8678
});
8779

8880
const styles = StyleSheet.create({
81+
wrapper: {
82+
position: 'relative',
83+
marginBottom: spacing.lg,
84+
marginRight: spacing.sm,
85+
},
86+
shadow: {
87+
position: 'absolute',
88+
top: 6,
89+
left: 6,
90+
right: -6,
91+
bottom: -6,
92+
backgroundColor: '#000000',
93+
},
8994
card: {
90-
borderRadius: 14,
91-
padding: spacing.md,
92-
marginBottom: spacing.sm,
93-
borderWidth: 1,
95+
padding: spacing.lg,
96+
borderWidth: 3,
9497
},
95-
row: {
98+
topRow: {
9699
flexDirection: 'row',
97100
alignItems: 'center',
98101
gap: spacing.md,
99102
},
100103
avatar: {
101-
width: 40,
102-
height: 40,
103-
borderRadius: 20,
104+
width: 44,
105+
height: 44,
104106
alignItems: 'center',
105107
justifyContent: 'center',
108+
borderWidth: 2,
109+
borderColor: '#000000',
106110
},
107111
avatarText: {
108-
color: '#FFFFFF',
109-
fontWeight: '700',
110-
fontSize: 15,
112+
fontWeight: '900',
113+
fontSize: 16,
111114
},
112-
content: {
115+
descriptionContainer: {
113116
flex: 1,
114117
},
115118
description: {
116-
fontSize: 15,
117-
fontWeight: '600',
118-
marginBottom: 2,
119+
fontSize: 16,
120+
fontWeight: '900',
121+
letterSpacing: 0.5,
119122
},
120-
metaRow: {
121-
flexDirection: 'row',
122-
alignItems: 'center',
123-
gap: 4,
123+
payer: {
124+
fontSize: 10,
125+
fontWeight: '700',
126+
marginTop: 2,
127+
letterSpacing: 1,
124128
},
125-
meta: {
126-
fontSize: 12,
129+
amount: {
130+
fontSize: 20,
131+
fontWeight: '900',
132+
letterSpacing: -0.5,
127133
},
128-
dot: {
129-
width: 3,
130-
height: 3,
131-
borderRadius: 1.5,
132-
backgroundColor: '#9CA3AF',
134+
divider: {
135+
height: 2,
136+
marginVertical: spacing.md,
133137
},
134-
chipRow: {
138+
bottomRow: {
135139
flexDirection: 'row',
136140
alignItems: 'center',
137-
gap: 2,
141+
justifyContent: 'space-between',
138142
},
139-
amount: {
140-
fontSize: 16,
141-
fontWeight: '700',
143+
metaItem: {
144+
flexDirection: 'row',
145+
alignItems: 'center',
146+
gap: 6,
147+
},
148+
metaText: {
149+
fontSize: 10,
150+
fontWeight: '800',
151+
letterSpacing: 1,
152+
},
153+
date: {
154+
fontSize: 10,
155+
fontWeight: '800',
156+
letterSpacing: 1,
142157
},
143158
});

0 commit comments

Comments
 (0)