frontend: add filter pills component
Parents:
27c3a091 file(s) changed
- frontend/components/ui/FilterPills.tsx +111 -0
frontend/components/ui/FilterPills.tsx
@@ -0,0 +1,111 @@
1 + import { useRef } from 'react';
2 + import {
3 + ScrollView,
4 + TouchableOpacity,
5 + Text,
6 + View,
7 + StyleSheet,
8 + Platform,
9 + } from 'react-native';
10 + import { LinearGradient } from 'expo-linear-gradient';
11 + import type { HistoryCategory } from '@/lib/history/types';
12 + import { Colors } from '@/constants/theme';
13 +
14 + export type FilterOption = {
15 + label: string
16 + value: HistoryCategory | 'all'
17 + };
18 +
19 + export const HISTORY_FILTERS: FilterOption[] = [
20 + { label: 'Tudo', value: 'all' },
21 + { label: 'Humor', value: 'mood' },
22 + { label: 'Sono', value: 'sleep' }
23 + ];
24 +
25 + type Props = {
26 + active: HistoryCategory | 'all'
27 + onChange: (value: HistoryCategory | 'all') => void
28 + };
29 +
30 + export function FilterPills({ active, onChange }: Props) {
31 + const scrollRef = useRef<ScrollView>(null);
32 +
33 + return (
34 + <View style={styles.wrapper}>
35 + <ScrollView
36 + ref={scrollRef}
37 + horizontal
38 + showsHorizontalScrollIndicator={false}
39 + contentContainerStyle={styles.scrollContent}
40 + >
41 + {HISTORY_FILTERS.map((filter) => {
42 + const isActive = filter.value === active
43 + return (
44 + <TouchableOpacity
45 + key={filter.value}
46 + onPress={() => onChange(filter.value)}
47 + activeOpacity={0.7}
48 + style={[styles.pill, isActive && styles.pillActive]}
49 + >
50 + <Text style={[styles.label, isActive && styles.labelActive]}>
51 + {filter.label}
52 + </Text>
53 + </TouchableOpacity>
54 + )
55 + })}
56 + </ScrollView>
57 +
58 + {/*
59 + TODO: needs a new build, probably
60 + <LinearGradient
61 + colors={['transparent', 'rgba(255,255,255,0.95)']}
62 + start={{ x: 0, y: 0 }}
63 + end={{ x: 1, y: 0 }}
64 + style={styles.fadeRight}
65 + pointerEvents="none"
66 + />
67 + */}
68 + </View>
69 + )
70 + }
71 +
72 + const styles = StyleSheet.create({
73 + wrapper: {
74 + position: 'relative',
75 + },
76 + scrollContent: {
77 + paddingHorizontal: 16,
78 + paddingVertical: 12,
79 + gap: 8,
80 + flexDirection: 'row',
81 + },
82 + pill: {
83 + paddingHorizontal: 16,
84 + paddingVertical: 7,
85 + borderRadius: 999,
86 + backgroundColor: '#F2F2F7',
87 + borderWidth: 1,
88 + borderColor: 'transparent',
89 + elevation: 1
90 + },
91 + pillActive: {
92 + backgroundColor: Colors.light.tint,
93 + borderColor: Colors.light.tint,
94 + },
95 + label: {
96 + fontSize: 14,
97 + fontWeight: '500',
98 + color: '#3C3C43',
99 + letterSpacing: -0.1,
100 + },
101 + labelActive: {
102 + color: Colors.light.text
103 + },
104 + fadeRight: {
105 + position: 'absolute',
106 + right: 0,
107 + top: 0,
108 + bottom: 0,
109 + width: 48,
110 + },
111 + });