frontend: introduce category chips
It'll be used for antoerh patch down the line with the triggers
Pedro Lucas Porcellis porcellis@eletrotupi.com · 4 months ago
4101720fb8e44a37a975d664d9e92b2e444b98ec Browse filesParents
76614c0Changed files
1
Additions
+96
Deletions
0
/dev/null → frontend/components/ui/CategoryChips.tsx
1 +
import {
2 +
TouchableOpacity,
3 +
Text,
4 +
View,
5 +
StyleSheet,
6 +
} from 'react-native';
7 +
import { Colors } from '@/constants/theme';
8 +
9 +
export type CategoryOption<T extends string = string> = {
10 +
label: string;
11 +
value: T;
12 +
icon: React.ReactNode;
13 +
};
14 +
15 +
type Props<T extends string = string> = {
16 +
options: CategoryOption<T>[];
17 +
active: T | null;
18 +
onChange: (value: T) => void;
19 +
columns?: number;
20 +
};
21 +
22 +
export function CategoryChips<T extends string = string>({
23 +
options,
24 +
active,
25 +
onChange,
26 +
columns = 2,
27 +
}: Props<T>) {
28 +
return (
29 +
<View style={styles.grid}>
30 +
{options.map((option) => {
31 +
const isActive = option.value === active;
32 +
return (
33 +
<TouchableOpacity
34 +
key={option.value}
35 +
onPress={() => onChange(option.value)}
36 +
activeOpacity={0.7}
37 +
style={[
38 +
styles.chip,
39 +
{ width: `${100 / columns - 2}%` as any },
40 +
isActive && styles.chipActive,
41 +
]}
42 +
>
43 +
<View style={styles.chipInner}>
44 +
<View style={styles.iconWrapper}>{option.icon}</View>
45 +
<Text style={[styles.label, isActive && styles.labelActive]}>
46 +
{option.label}
47 +
</Text>
48 +
</View>
49 +
</TouchableOpacity>
50 +
);
51 +
})}
52 +
</View>
53 +
);
54 +
}
55 +
56 +
const styles = StyleSheet.create({
57 +
grid: {
58 +
flexDirection: 'row',
59 +
flexWrap: 'wrap',
60 +
gap: 10,
61 +
paddingHorizontal: 16,
62 +
paddingVertical: 8,
63 +
},
64 +
chip: {
65 +
paddingHorizontal: 16,
66 +
paddingVertical: 12,
67 +
borderRadius: 999,
68 +
backgroundColor: '#fff',
69 +
borderWidth: 1.5,
70 +
borderColor: 'transparent',
71 +
},
72 +
chipActive: {
73 +
backgroundColor: Colors.light.tint + '1A', // ~10% opacity tint background
74 +
borderColor: Colors.light.tint,
75 +
},
76 +
chipInner: {
77 +
flexDirection: 'row',
78 +
alignItems: 'center',
79 +
gap: 8,
80 +
},
81 +
iconWrapper: {
82 +
width: 20,
83 +
height: 20,
84 +
alignItems: 'center',
85 +
justifyContent: 'center',
86 +
},
87 +
label: {
88 +
fontSize: 14,
89 +
fontWeight: '500',
90 +
color: '#3C3C43',
91 +
letterSpacing: -0.1,
92 +
},
93 +
labelActive: {
94 +
fontWeight: '600',
95 +
},
96 +
});