eletrotupi / tcc/ frontend/components/ui/Sections.tsx32b1e688c7e7c65b735c7e23ba3c4aeb89c33a3d
3.1 KB | 144 lines Raw
1
import React from 'react';
2
import {
3
  View,
4
  StyleSheet,
5
  Pressable,
6
  ViewStyle,
7
  TextStyle,
8
} from 'react-native';
9
import { Text } from '@/components/ui/Text'
10
import { Row, Between } from '@/components/ui/LayoutHelpers';
11

12
import { Colors, Typography, Spacing } from '@/constants/theme';
13
import { useThemeColor } from '@/hooks/use-theme-color';
14

15
interface SectionProps {
16
  children: React.ReactNode;
17
  style?: ViewStyle;
18
}
19

20
export const Section: React.FC<SectionProps> = ({ children, style }) => {
21
  const styles = StyleSheet.create({
22
    section: {
23
      marginBottom: Spacing.sectionGap,
24
    },
25
  });
26
  return <View style={[styles.section, style]}>{children}</View>;
27
};
28

29
interface SectionHeaderProps {
30
  title: string;
31
  subtitle?: string;
32
  info?: string;
33
  actionLabel?: string;
34
  onActionPress?: () => void;
35
  style?: ViewStyle;
36
  variant?: 'default' | 'subtle';
37
  testID?: string;
38
}
39

40
// XXX: A Section must either have a label as a pill/informative thing
41
// or it should be a link
42
export const SectionHeader: React.FC<SectionHeaderProps> = ({
43
  title,
44
  subtitle,
45
  info,
46
  actionLabel,
47
  onActionPress,
48
  variant,
49
  style,
50
  testID,
51
}) => {
52
  const textColor = useThemeColor({}, 'text');
53
  const tintColor = useThemeColor({}, 'tint');
54
  const textSecondaryColor = useThemeColor({}, 'textSecondary')
55

56
  const getTextColor = () => {
57
    switch (variant) {
58
      case 'subtle':
59
        return textSecondaryColor;
60
      default:
61
        return textColor;
62
    }
63
  };
64

65
  const getFont = (): TextStyle => {
66
    switch (variant) {
67
      case 'subtle':
68
        return {
69
          fontSize: 11,
70
          fontWeight: '600',
71
          letterSpacing: 0.8,
72
          color: Colors.light.textSecondary,
73
          textTransform: 'uppercase',
74
        };
75
      default:
76
        return {
77
          fontSize: Typography.headlineMd.fontSize,
78
          fontWeight: Typography.headlineMd.fontWeight,
79
        };
80
    }
81
  }
82

83
  const styles = StyleSheet.create({
84
    headerContainer: {
85
      marginBottom: variant === 'subtle' ? 10 : (Spacing.cardGap * 2),
86
    },
87
    title: {
88
      color: getTextColor(),
89
      ...getFont(),
90
    },
91
    subtitle: {
92
      fontSize: 14,
93
      color: textSecondaryColor,
94
      lineHeight: 20,
95
      marginTop: 4
96
    },
97
    actionButton: {
98
      padding: 4,
99
    },
100
    actionText: {
101
      fontSize: Typography.bodyMd.fontSize,
102
      fontWeight: '600',
103
      color: tintColor,
104
    },
105
  });
106

107
  // TODO: Rework these when we finally have chips/badges
108
  return (
109
    <View style={[styles.headerContainer, style]}>
110
      <Between>
111
        <Text style={styles.title} testID={testID}>
112
          {title}
113
        </Text>
114

115
        {info && !actionLabel && (
116
          <Text>
117
            {info}
118
          </Text>
119
        )}
120

121
        {actionLabel && !info && onActionPress && (
122
          <Pressable
123
            style={styles.actionButton}
124
            onPress={onActionPress}
125
            hitSlop={8}
126
          >
127
            <Text style={styles.actionText}>
128
              {actionLabel}
129
            </Text>
130
          </Pressable>
131
        )}
132
      </Between>
133

134
      {subtitle && (
135
        <Row>
136
          <Text style={styles.subtitle}>
137
            {subtitle}
138
          </Text>
139
        </Row>
140
      )}
141
    </View>
142
  );
143
};
144