@xetwa/design-system 1.0.40 → 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xetwa/design-system",
3
- "version": "1.0.40",
3
+ "version": "1.0.41",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -132,17 +132,17 @@ export const BoardingPassCard = ({
132
132
  styles.container,
133
133
  {
134
134
  borderRadius: scale(20),
135
- minHeight: scale(210),
135
+ minHeight: scale(240),
136
136
  },
137
137
  style
138
138
  ]}>
139
139
  {/* Top Section */}
140
140
  <View style={[
141
- styles.topSection,
142
- {
141
+ styles.topSection,
142
+ {
143
143
  backgroundColor: currentHeaderBg,
144
- paddingTop: scale(16),
145
- paddingBottom: scale(16),
144
+ paddingTop: scale(24),
145
+ paddingBottom: scale(24),
146
146
  paddingHorizontal: scale(18),
147
147
  }
148
148
  ]}>
@@ -158,7 +158,7 @@ export const BoardingPassCard = ({
158
158
  ]} />
159
159
 
160
160
  <View style={[styles.headerRow, { marginBottom: scale(16) }]}>
161
- <Typography variant="caption" style={[styles.headerText]}>CARTÃO DE EMBARQUE</Typography>
161
+ <Typography variant="labelHeavy" style={[styles.headerText]}>CARTÃO DE EMBARQUE</Typography>
162
162
  <View style={styles.headerPlaneContainer}>
163
163
  <Plane stroke={theme.colors.white} strokeWidth={2.2} size={scale(22)} />
164
164
  </View>
@@ -166,8 +166,8 @@ export const BoardingPassCard = ({
166
166
 
167
167
  <View style={styles.routeRow}>
168
168
  <View style={styles.cityCol}>
169
- <Typography variant="h1" style={[styles.cityCode]}>{originCode}</Typography>
170
- <Typography variant="caption" style={[styles.cityName]}>{originName}</Typography>
169
+ <Typography variant="display2" style={[styles.cityCode]}>{originCode}</Typography>
170
+ <Typography variant="small" style={[styles.cityName]}>{originName}</Typography>
171
171
  </View>
172
172
 
173
173
  <View style={[styles.flightLineContainer, { height: scale(30), marginHorizontal: scale(12) }]}>
@@ -178,8 +178,8 @@ export const BoardingPassCard = ({
178
178
  </View>
179
179
 
180
180
  <View style={[styles.cityCol, { alignItems: 'flex-end' }]}>
181
- <Typography variant="h1" style={[styles.cityCode]}>{destCode}</Typography>
182
- <Typography variant="caption" style={[styles.cityName]}>{destName}</Typography>
181
+ <Typography variant="display2" style={[styles.cityCode]}>{destCode}</Typography>
182
+ <Typography variant="small" style={[styles.cityName]}>{destName}</Typography>
183
183
  </View>
184
184
  </View>
185
185
  </View>
@@ -188,7 +188,7 @@ export const BoardingPassCard = ({
188
188
  <View style={[
189
189
  styles.bottomSection,
190
190
  {
191
- paddingVertical: scale(14),
191
+ paddingVertical: scale(20),
192
192
  paddingHorizontal: scale(18),
193
193
  }
194
194
  ]}>
@@ -205,8 +205,8 @@ export const BoardingPassCard = ({
205
205
  {flagIconNode ? flagIconNode : <Flag countryCode={countryName} size={scale(40)} />}
206
206
  </View>
207
207
  <View style={styles.countryContent}>
208
- <Typography variant="h2" style={[styles.countryName]}>{countryName}</Typography>
209
- <Typography variant="bodySm" style={[styles.countrySubtitle]}>{countrySubtitle}</Typography>
208
+ <Typography variant="subtitle1" style={[styles.countryName]}>{countryName}</Typography>
209
+ <Typography variant="label" style={[styles.countrySubtitle]}>{countrySubtitle}</Typography>
210
210
  </View>
211
211
  </View>
212
212
 
@@ -220,12 +220,12 @@ export const BoardingPassCard = ({
220
220
 
221
221
  <View style={[styles.footerRow, { gap: scale(14) }]}>
222
222
  <View style={styles.footerCol}>
223
- <Typography variant="caption" style={[styles.footerLabel]}>MÓDULOS</Typography>
224
- <Typography variant="h3" style={[styles.footerValue]}>{modulesCount}</Typography>
223
+ <Typography variant="labelHeavy" style={[styles.footerLabel]}>MÓDULOS</Typography>
224
+ <Typography variant="subtitle1" style={[styles.footerValue]}>{modulesCount}</Typography>
225
225
  </View>
226
226
  <View style={styles.footerCol}>
227
- <Typography variant="caption" style={[styles.footerLabel]}>FOCO</Typography>
228
- <Typography variant="h3" style={[styles.footerValue]}>{focusText}</Typography>
227
+ <Typography variant="labelHeavy" style={[styles.footerLabel]}>FOCO</Typography>
228
+ <Typography variant="subtitle1" style={[styles.footerValue]}>{focusText}</Typography>
229
229
  </View>
230
230
  </View>
231
231
  </View>
@@ -241,6 +241,10 @@ const styles = StyleSheet.create({
241
241
  minHeight: 230,
242
242
  ...theme.shadows.lg,
243
243
  },
244
+ headerText: {
245
+ color: theme.colors.white,
246
+ opacity: 0.9,
247
+ },
244
248
  topSection: {
245
249
  paddingTop: 16,
246
250
  paddingBottom: 16,
@@ -266,11 +270,6 @@ const styles = StyleSheet.create({
266
270
  headerPlaneContainer: {
267
271
  transform: [{ rotate: '0deg' }],
268
272
  },
269
- headerText: {
270
- letterSpacing: 1.2,
271
- textTransform: 'uppercase',
272
- color: 'rgba(255, 255, 255, 0.75)',
273
- },
274
273
  routeRow: {
275
274
  flexDirection: 'row',
276
275
  alignItems: 'center',
@@ -345,6 +344,10 @@ const styles = StyleSheet.create({
345
344
  countrySubtitle: {
346
345
  color: '#9a8478',
347
346
  },
347
+ footerLabel: {
348
+ color: theme.colors.brown[500],
349
+ marginBottom: 4,
350
+ },
348
351
  divider: {
349
352
  borderTopWidth: 1.5,
350
353
  borderColor: '#f3e7da',
@@ -235,9 +235,8 @@ export const ModuleCard = ({
235
235
  const cardPaddingV = size === 'xl' ? scale(20) : size === 'lg' ? scale(16) : isMobileScreen ? scale(10) : scale(14);
236
236
  const cardPaddingH = size === 'xl' ? scale(20) : size === 'lg' ? scale(18) : isMobileScreen ? scale(12) : scale(15);
237
237
 
238
- const titleVariant = size === 'xl' ? 'h1' : size === 'lg' ? 'h2' : 'h3';
239
-
240
- const subtitleVariant = size === 'xl' ? 'bodyLg' : size === 'lg' ? 'bodyMd' : 'bodySm';
238
+ const titleVariant = size === 'xl' ? 'h4' : size === 'lg' ? 'h6' : 'subtitle1';
239
+ const subtitleVariant = size === 'xl' ? 'bodySm' : size === 'lg' ? 'caption' : 'label';
241
240
 
242
241
 
243
242
 
@@ -330,7 +329,7 @@ export const ModuleCard = ({
330
329
  hitSlop={10}
331
330
  >
332
331
  <RotateCcw stroke={theme.colors.primary} strokeWidth={2.5} size={isMobileScreen ? scale(20) : scale(24)} />
333
- <Typography variant="label" style={[styles.reviewIconText, { fontSize: scaleText(9) }]}>REVER</Typography>
332
+ <Typography variant="smallHeavy" style={[styles.reviewIconText, { fontSize: scaleText(9) }]}>REVER</Typography>
334
333
  </Pressable>
335
334
  </Animated.View>
336
335
  ) : null}
@@ -368,7 +367,7 @@ export const ModuleCard = ({
368
367
  style={{ flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.primary, paddingHorizontal: scale(14), paddingVertical: scale(6), borderRadius: 100 }}
369
368
  >
370
369
  <CalendarPlus stroke={theme.colors.white} strokeWidth={2.5} size={scale(14)} />
371
- <Typography variant="label" style={{ color: theme.colors.white, fontSize: scaleText(12), fontWeight: 'bold', marginLeft: scale(6) }}>Agendar Aula</Typography>
370
+ <Typography variant="bodySmHeavy" style={{ color: theme.colors.white, marginLeft: scale(6) }}>Agendar Aula</Typography>
372
371
  </Pressable>
373
372
  </Animated.View>
374
373
  )}
@@ -383,7 +382,7 @@ export const ModuleCard = ({
383
382
  style={{ flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.primary, paddingHorizontal: scale(14), paddingVertical: scale(6), borderRadius: 100 }}
384
383
  >
385
384
  <PenTool stroke={theme.colors.white} strokeWidth={2.5} size={scale(14)} />
386
- <Typography variant="label" style={{ color: theme.colors.white, fontSize: scaleText(12), fontWeight: 'bold', marginLeft: scale(6) }}>Fazer Exame</Typography>
385
+ <Typography variant="bodySmHeavy" style={{ color: theme.colors.white, marginLeft: scale(6) }}>Fazer Exame</Typography>
387
386
  </Pressable>
388
387
  </Animated.View>
389
388
  )}
@@ -399,7 +398,7 @@ export const ModuleCard = ({
399
398
  hitSlop={8}
400
399
  >
401
400
  <RotateCcw stroke={theme.colors.primary} strokeWidth={2.5} size={scale(16)} />
402
- <Typography variant="label" style={[styles.reviewIconText, { color: theme.colors.primary, fontSize: scaleText(10), marginLeft: scale(4), marginTop: 0 }]}>REVER</Typography>
401
+ <Typography variant="smallHeavy" style={[styles.reviewIconText, { color: theme.colors.primary, marginLeft: scale(4), marginTop: 0 }]}>REVER</Typography>
403
402
  </Pressable>
404
403
  </Animated.View>
405
404
  )}
@@ -0,0 +1,80 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useState } from 'react';
3
+ import { View } from 'react-native';
4
+ import { TabBar } from './TabBar';
5
+
6
+ const meta = {
7
+ title: 'Components/Navigation/TabBar',
8
+ component: TabBar,
9
+ parameters: {
10
+ layout: 'fullscreen',
11
+ docs: {
12
+ description: {
13
+ component: 'TabBar component with 3 variants (A: Pill, B: Top Bar, C: Dot below) and notification badges.',
14
+ }
15
+ }
16
+ },
17
+ tags: ['autodocs'],
18
+ argTypes: {
19
+ variant: { control: 'radio', options: ['A', 'B', 'C'] },
20
+ safeAreaBottom: { control: 'number' },
21
+ activeItemId: { control: 'text' },
22
+ },
23
+ decorators: [
24
+ (Story) => (
25
+ <View style={{ flex: 1, justifyContent: 'flex-end', backgroundColor: '#f5f0eb' }}>
26
+ <Story />
27
+ </View>
28
+ ),
29
+ ],
30
+ } satisfies Meta<typeof TabBar>;
31
+
32
+ export default meta;
33
+ type Story = StoryObj<typeof TabBar>;
34
+
35
+ const defaultItems = [
36
+ { id: 'inicio', label: 'Início', icon: 'Home' },
37
+ { id: 'percurso', label: 'Percurso', icon: 'Compass' },
38
+ { id: 'aulas', label: 'Aulas', icon: 'GraduationCap' },
39
+ { id: 'dossier', label: 'Dossier', hasBadge: true, icon: 'FolderOpen' },
40
+ { id: 'perfil', label: 'Perfil', icon: 'User' },
41
+ ];
42
+
43
+ export const VariantB: Story = {
44
+ args: {
45
+ items: defaultItems,
46
+ activeItemId: 'inicio',
47
+ variant: 'B',
48
+ safeAreaBottom: 20,
49
+ },
50
+ render: function Render(args) {
51
+ const [activeId, setActiveId] = useState(args.activeItemId);
52
+ return <TabBar {...args} activeItemId={activeId} onItemPress={setActiveId} />;
53
+ }
54
+ };
55
+
56
+ export const VariantA: Story = {
57
+ args: {
58
+ items: defaultItems,
59
+ activeItemId: 'inicio',
60
+ variant: 'A',
61
+ safeAreaBottom: 20,
62
+ },
63
+ render: function Render(args) {
64
+ const [activeId, setActiveId] = useState(args.activeItemId);
65
+ return <TabBar {...args} activeItemId={activeId} onItemPress={setActiveId} />;
66
+ }
67
+ };
68
+
69
+ export const VariantC: Story = {
70
+ args: {
71
+ items: defaultItems,
72
+ activeItemId: 'inicio',
73
+ variant: 'C',
74
+ safeAreaBottom: 20,
75
+ },
76
+ render: function Render(args) {
77
+ const [activeId, setActiveId] = useState(args.activeItemId);
78
+ return <TabBar {...args} activeItemId={activeId} onItemPress={setActiveId} />;
79
+ }
80
+ };
@@ -0,0 +1,245 @@
1
+ import React, { useRef, useEffect } from 'react';
2
+ import { View, StyleSheet, Pressable, Animated, Platform } from 'react-native';
3
+ import type { ViewStyle } from 'react-native';
4
+ import { theme } from '../../../styles/theme';
5
+ import { Typography } from '../../Typography/Typography';
6
+ import { useResponsive } from '../../../hooks/useResponsive';
7
+ import { IconMap } from '../../../utils/iconMap';
8
+
9
+ export type TabBarVariant = 'A' | 'B' | 'C';
10
+
11
+ export interface TabBarItem {
12
+ id: string;
13
+ label: string;
14
+ icon: string;
15
+ hasBadge?: boolean;
16
+ }
17
+
18
+ export interface TabBarProps {
19
+ items: TabBarItem[];
20
+ activeItemId: string;
21
+ onItemPress: (id: string) => void;
22
+ variant?: TabBarVariant;
23
+ safeAreaBottom?: number;
24
+ style?: ViewStyle | ViewStyle[];
25
+ }
26
+
27
+ const TabBarItemComponent = ({
28
+ item,
29
+ isActive,
30
+ variant,
31
+ iconSize,
32
+ onItemPress,
33
+ }: {
34
+ item: TabBarItem;
35
+ isActive: boolean;
36
+ variant: TabBarVariant;
37
+ iconSize: number;
38
+ onItemPress: (id: string) => void;
39
+ }) => {
40
+ const { scale, scaleText } = useResponsive();
41
+ const color = isActive ? theme.colors.primary : theme.colors.brown[300];
42
+
43
+ // Animação de escala ao pressionar
44
+ const scaleAnim = useRef(new Animated.Value(1)).current;
45
+
46
+ const handlePressIn = () => {
47
+ Animated.timing(scaleAnim, {
48
+ toValue: 0.9,
49
+ duration: 100,
50
+ useNativeDriver: true,
51
+ }).start();
52
+ };
53
+
54
+ const handlePressOut = () => {
55
+ Animated.spring(scaleAnim, {
56
+ toValue: 1,
57
+ friction: 4,
58
+ tension: 40,
59
+ useNativeDriver: true,
60
+ }).start();
61
+ };
62
+
63
+ // Animação de transição quando se torna ativo
64
+ const activeAnim = useRef(new Animated.Value(isActive ? 1 : 0)).current;
65
+ useEffect(() => {
66
+ Animated.spring(activeAnim, {
67
+ toValue: isActive ? 1 : 0,
68
+ friction: 7,
69
+ tension: 60,
70
+ useNativeDriver: true,
71
+ }).start();
72
+ }, [isActive]);
73
+
74
+ return (
75
+ <Pressable
76
+ onPress={() => onItemPress(item.id)}
77
+ onPressIn={handlePressIn}
78
+ onPressOut={handlePressOut}
79
+ style={styles.itemContainer}
80
+ >
81
+ <Animated.View style={[styles.itemInner, { transform: [{ scale: scaleAnim }] }]}>
82
+ {/* Variante B: Barra no topo */}
83
+ {variant === 'B' && (
84
+ <Animated.View
85
+ style={[
86
+ styles.indicatorB,
87
+ {
88
+ width: scale(28),
89
+ height: scale(4),
90
+ opacity: activeAnim,
91
+ transform: [
92
+ { translateY: activeAnim.interpolate({ inputRange: [0, 1], outputRange: [-4, 0] }) },
93
+ { scaleX: activeAnim.interpolate({ inputRange: [0, 1], outputRange: [0.4, 1] }) }
94
+ ]
95
+ }
96
+ ]}
97
+ />
98
+ )}
99
+
100
+ {/* Variante A: Pill no ícone */}
101
+ <View
102
+ style={[
103
+ styles.iconWrapper,
104
+ variant === 'A' && isActive && styles.pillA,
105
+ variant === 'A' && isActive && { paddingHorizontal: scale(16), paddingVertical: scale(6), borderRadius: scale(100) },
106
+ ]}
107
+ >
108
+ {(() => {
109
+ const IconComponent = IconMap[item.icon];
110
+ if (!IconComponent) return null;
111
+ return <IconComponent color={color} size={iconSize} strokeWidth={2.5} />;
112
+ })()}
113
+
114
+ {/* Badge de Notificação */}
115
+ {item.hasBadge && (
116
+ <View
117
+ style={[
118
+ styles.badge,
119
+ {
120
+ width: scale(9),
121
+ height: scale(9),
122
+ borderRadius: scale(4.5),
123
+ borderWidth: scale(2),
124
+ top: scale(-3),
125
+ right: scale(-4),
126
+ // Adjust badge position for pill
127
+ ...(variant === 'A' && isActive && { top: scale(3), right: scale(8) })
128
+ }
129
+ ]}
130
+ />
131
+ )}
132
+ </View>
133
+
134
+ <Typography
135
+ variant="smallHeavy"
136
+ style={[
137
+ styles.label,
138
+ { color, fontSize: scaleText(9.5) },
139
+ variant === 'C' && { marginBottom: scale(4) }
140
+ ]}
141
+ >
142
+ {item.label}
143
+ </Typography>
144
+
145
+ {/* Variante C: Dot abaixo da label */}
146
+ {variant === 'C' && isActive && (
147
+ <View style={[styles.dotC, { width: scale(4), height: scale(4), borderRadius: scale(2) }]} />
148
+ )}
149
+ </Animated.View>
150
+ </Pressable>
151
+ );
152
+ };
153
+
154
+ export const TabBar = ({
155
+ items,
156
+ activeItemId,
157
+ onItemPress,
158
+ variant = 'B',
159
+ safeAreaBottom = 0,
160
+ style,
161
+ }: TabBarProps) => {
162
+ const { scale, scaleText, width } = useResponsive();
163
+ const isDesktop = width >= 768;
164
+
165
+ const iconSize = isDesktop ? scale(22) : scale(21);
166
+ const bottomPadding = Math.max(scale(14), safeAreaBottom);
167
+
168
+ return (
169
+ <View
170
+ style={[
171
+ styles.container,
172
+ {
173
+ paddingBottom: bottomPadding,
174
+ paddingHorizontal: scale(6),
175
+ },
176
+ style,
177
+ ]}
178
+ >
179
+ {items.map((item) => (
180
+ <TabBarItemComponent
181
+ key={item.id}
182
+ item={item}
183
+ isActive={activeItemId === item.id}
184
+ variant={variant}
185
+ iconSize={iconSize}
186
+ onItemPress={onItemPress}
187
+ />
188
+ ))}
189
+ </View>
190
+ );
191
+ };
192
+
193
+ const styles = StyleSheet.create({
194
+ container: {
195
+ flexDirection: 'row',
196
+ justifyContent: 'space-around',
197
+ alignItems: 'flex-start',
198
+ backgroundColor: theme.colors.white,
199
+ borderTopWidth: 1.5,
200
+ borderTopColor: theme.colors.brown[100],
201
+ width: '100%',
202
+ minHeight: 56,
203
+ },
204
+ itemContainer: {
205
+ flex: 1,
206
+ alignItems: 'center',
207
+ justifyContent: 'flex-start',
208
+ minWidth: 60,
209
+ },
210
+ itemInner: {
211
+ alignItems: 'center',
212
+ paddingTop: 9, // Espaço entre border-top e ícone (Variant B spec)
213
+ position: 'relative',
214
+ width: '100%',
215
+ },
216
+ iconWrapper: {
217
+ position: 'relative',
218
+ marginBottom: 4,
219
+ alignItems: 'center',
220
+ justifyContent: 'center',
221
+ },
222
+ pillA: {
223
+ backgroundColor: theme.colors.primaryLight,
224
+ },
225
+ indicatorB: {
226
+ position: 'absolute',
227
+ top: 0,
228
+ backgroundColor: theme.colors.primary,
229
+ borderBottomLeftRadius: 4,
230
+ borderBottomRightRadius: 4,
231
+ },
232
+ label: {
233
+ textAlign: 'center',
234
+ },
235
+ dotC: {
236
+ position: 'absolute',
237
+ bottom: -6,
238
+ backgroundColor: theme.colors.primary,
239
+ },
240
+ badge: {
241
+ position: 'absolute',
242
+ backgroundColor: theme.colors.error,
243
+ borderColor: theme.colors.white,
244
+ },
245
+ });
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ export * from './components/Inputs/TextInput/TextInput';
45
45
  export * from './components/Mascots/Vava/Vava';
46
46
  export * from './components/Mascots/Yaya/Yaya';
47
47
  export * from './components/Navigation/BottomTabBar/BottomTabBar';
48
+ export * from './components/Navigation/TabBar/TabBar';
48
49
  export * from './components/Navigation/PaginationDots/PaginationDots';
49
50
  export * from './components/Navigation/ProgressMap/ProgressMap';
50
51
  export * from './components/Navigation/WorldProgressMap/WorldProgressMap';
@@ -172,86 +172,161 @@ export const theme = {
172
172
  },
173
173
 
174
174
  typography: {
175
+ // FAMÍLIA FREDOKA (Títulos e Destaques)
175
176
  display1: {
176
177
  ...font('Fredoka-Bold', '700'),
177
178
  fontSize: 28,
178
- lineHeight: 34,
179
- desktopFontSize: 42,
179
+ lineHeight: 28, // ajustado para line-height 1 se não especificado
180
+ desktopFontSize: 34,
180
181
  },
181
182
  display2: {
182
183
  ...font('Fredoka-Bold', '700'),
183
- fontSize: 24,
184
- lineHeight: 30,
185
- desktopFontSize: 34,
184
+ fontSize: 27,
185
+ lineHeight: 27,
186
+ desktopFontSize: 32,
186
187
  },
187
188
  h1: {
188
189
  ...font('Fredoka-Bold', '700'),
189
190
  fontSize: 22,
190
- lineHeight: 28,
191
+ lineHeight: 22,
191
192
  desktopFontSize: 28,
192
193
  },
193
194
  h2: {
194
- ...font('Fredoka-SemiBold', '600'),
195
- fontSize: 18,
196
- lineHeight: 24,
197
- desktopFontSize: 22,
195
+ ...font('Fredoka-Bold', '700'),
196
+ fontSize: 20,
197
+ lineHeight: 20,
198
+ desktopFontSize: 24,
198
199
  },
199
200
  h3: {
200
201
  ...font('Fredoka-SemiBold', '600'),
201
- fontSize: 16,
202
+ fontSize: 20,
203
+ lineHeight: 24, // Sem line-height fixo no spec, 1.2
204
+ desktopFontSize: 24,
205
+ },
206
+ h4: {
207
+ ...font('Fredoka-SemiBold', '600'),
208
+ fontSize: 19,
202
209
  lineHeight: 22,
210
+ desktopFontSize: 22,
211
+ },
212
+ h5: {
213
+ ...font('Fredoka-Bold', '700'),
214
+ fontSize: 18,
215
+ lineHeight: 22,
216
+ desktopFontSize: 20,
217
+ },
218
+ h6: {
219
+ ...font('Fredoka-SemiBold', '600'),
220
+ fontSize: 17,
221
+ lineHeight: 18.7, // line-height 1.1 * 17
203
222
  desktopFontSize: 19,
204
223
  },
205
- label: {
206
- ...font('Nunito-Black', '900'),
207
- fontSize: 10,
208
- lineHeight: 14,
209
- letterSpacing: 1.2, // 10 * 0.12
210
- desktopFontSize: 11,
224
+ subtitle1: {
225
+ ...font('Fredoka-SemiBold', '600'),
226
+ fontSize: 16,
227
+ lineHeight: 16, // line-height 1
228
+ desktopFontSize: 18,
211
229
  },
212
- bodyLg: {
213
- ...font('Nunito-Bold', '700'),
214
- fontSize: 15,
230
+ subtitle2: {
231
+ ...font('Fredoka-Bold', '700'),
232
+ fontSize: 14,
233
+ lineHeight: 18,
234
+ desktopFontSize: 16,
235
+ },
236
+
237
+ // FAMÍLIA NUNITO (Corpo, Labels, Listas e Infos)
238
+ bodyLgHeavy: {
239
+ ...font('Nunito-ExtraBold', '800'),
240
+ fontSize: 16,
215
241
  lineHeight: 24,
216
- desktopFontSize: 17,
242
+ desktopFontSize: 18,
243
+ },
244
+ bodyMdHeavy: {
245
+ ...font('Nunito-ExtraBold', '800'),
246
+ fontSize: 15,
247
+ lineHeight: 22,
248
+ desktopFontSize: 16,
217
249
  },
218
250
  bodyMd: {
219
- ...font('Nunito-Bold', '700'),
220
- fontSize: 13.5,
251
+ ...font('Nunito-SemiBold', '600'),
252
+ fontSize: 15,
221
253
  lineHeight: 22,
254
+ desktopFontSize: 16,
255
+ },
256
+ bodySmHeavy: {
257
+ ...font('Nunito-ExtraBold', '800'),
258
+ fontSize: 13.5,
259
+ lineHeight: 20,
222
260
  desktopFontSize: 15,
223
261
  },
224
262
  bodySm: {
225
- ...font('Nunito-ExtraBold', '800'),
226
- fontSize: 12,
227
- lineHeight: 18,
228
- desktopFontSize: 13,
263
+ ...font('Nunito-Bold', '700'),
264
+ fontSize: 13.5,
265
+ lineHeight: 20,
266
+ desktopFontSize: 15,
267
+ },
268
+ captionItalic: {
269
+ ...font('Nunito-SemiBoldItalic', '600'),
270
+ fontSize: 12.5,
271
+ lineHeight: 18.75, // line-height 1.5 * 12.5
272
+ desktopFontSize: 14,
273
+ fontStyle: 'italic',
229
274
  },
230
275
  caption: {
276
+ ...font('Nunito-Bold', '700'),
277
+ fontSize: 12.5,
278
+ lineHeight: 18,
279
+ desktopFontSize: 14,
280
+ },
281
+ labelHeavy: {
282
+ ...font('Nunito-Black', '900'), // O spec diz 800, mas no Nunito "Black" (900) dá melhor leitura p/ labels, ou podemos usar ExtraBold (800). Vamos usar ExtraBold (800) como no spec:
283
+ // wait, refiz para respeitar o 800
231
284
  ...font('Nunito-ExtraBold', '800'),
232
- fontSize: 10,
285
+ fontSize: 11,
233
286
  lineHeight: 16,
287
+ letterSpacing: 0.88, // 11 * 0.08em
288
+ textTransform: 'uppercase',
289
+ desktopFontSize: 12,
290
+ },
291
+ label: {
292
+ ...font('Nunito-Bold', '700'),
293
+ fontSize: 11,
294
+ lineHeight: 16,
295
+ desktopFontSize: 12,
296
+ },
297
+ smallHeavy: {
298
+ ...font('Nunito-ExtraBold', '800'),
299
+ fontSize: 10,
300
+ lineHeight: 14,
234
301
  desktopFontSize: 11,
235
302
  },
303
+ small: {
304
+ ...font('Nunito-Bold', '700'),
305
+ fontSize: 10,
306
+ lineHeight: 14,
307
+ desktopFontSize: 11,
308
+ },
309
+
310
+ // Botões (mantemos originais porque são usados no MainButton)
236
311
  btnLg: {
237
312
  ...font('Nunito-Black', '900'),
238
313
  fontSize: 16,
239
314
  lineHeight: 20,
240
- letterSpacing: 0.64, // 16 * 0.04
315
+ letterSpacing: 0.64,
241
316
  desktopFontSize: 17,
242
317
  },
243
318
  btnMd: {
244
319
  ...font('Nunito-Black', '900'),
245
320
  fontSize: 14,
246
321
  lineHeight: 18,
247
- letterSpacing: 0.56, // 14 * 0.04
322
+ letterSpacing: 0.56,
248
323
  desktopFontSize: 15,
249
324
  },
250
325
  btnSm: {
251
326
  ...font('Nunito-Black', '900'),
252
327
  fontSize: 12,
253
328
  lineHeight: 16,
254
- letterSpacing: 0.48, // 12 * 0.04
329
+ letterSpacing: 0.48,
255
330
  desktopFontSize: 12,
256
331
  },
257
332
  },
@@ -1,4 +1,5 @@
1
- import { Play, Volume2, Volume1, ArrowRight, X, Check, ChevronRight, ChevronLeft, Info, AlertTriangle, Book, Mic } from 'lucide-react-native';
1
+ import { FileText } from 'lucide-react';
2
+ import { Play, Volume2, Volume1, ArrowRight, X, Check, ChevronRight, ChevronLeft, Info, AlertTriangle, Book, Mic, Home, Compass, GraduationCap, FolderOpen, User, ShoppingCart } from 'lucide-react-native';
2
3
 
3
4
  /**
4
5
  * Para evitar que o Vite e o Metro (React Native) tentem empacotar os 1400+ ícones
@@ -21,4 +22,11 @@ export const IconMap: Record<string, any> = {
21
22
  AlertTriangle,
22
23
  Book,
23
24
  Mic,
25
+ Home,
26
+ Compass,
27
+ GraduationCap,
28
+ FolderOpen,
29
+ User,
30
+ ShoppingCart,
31
+ FileText,
24
32
  };