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

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

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

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

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

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

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

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

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

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

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

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

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