eletrotupi / tcc/ frontend/components/ui/Sections.tsxb8a4c922c03ac082a5983fdce4f1b80a99486b57
3.1 KB | 140 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
  actionLabel?: string;
32
  onActionPress?: () => void;
33
  style?: ViewStyle;
34
  variant?: 'default' | 'subtle';
35
}
36

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

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

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

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

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

111
        {info && !actionLabel && (
112
          <Text>
113
            {info}
114
          </Text>
115
        )}
116

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

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