@xetwa/design-system 1.0.37 → 1.0.39
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
|
@@ -75,6 +75,19 @@ export const ActiveDark: Story = {
|
|
|
75
75
|
subtitle: 'Regatear, números, comida',
|
|
76
76
|
subtext: '• 3/5',
|
|
77
77
|
tagLabel: 'AULA MARCADA',
|
|
78
|
+
onSchedulePress: () => console.log('Agendar Aula'),
|
|
79
|
+
onReviewPress: () => console.log('Rever'),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const ExamMode: Story = {
|
|
84
|
+
args: {
|
|
85
|
+
status: 'active-dark',
|
|
86
|
+
title: 'No mercado de Dakar',
|
|
87
|
+
subtitle: 'Exame de módulo',
|
|
88
|
+
subtext: '• 3/5',
|
|
89
|
+
tagLabel: 'POR FAZER',
|
|
90
|
+
onExamPress: () => console.log('Fazer Exame'),
|
|
78
91
|
},
|
|
79
92
|
};
|
|
80
93
|
|
|
@@ -129,6 +142,16 @@ export const Grid: Story = {
|
|
|
129
142
|
subtitle="Conversação e prática"
|
|
130
143
|
subtext="• 4/4"
|
|
131
144
|
tagLabel="AULA MARCADA"
|
|
145
|
+
onSchedulePress={() => {}}
|
|
146
|
+
onReviewPress={() => {}}
|
|
147
|
+
/>
|
|
148
|
+
<ModuleCard
|
|
149
|
+
status="active-dark"
|
|
150
|
+
title="No mercado de Dakar"
|
|
151
|
+
subtitle="Exame de módulo"
|
|
152
|
+
subtext="• 3/5"
|
|
153
|
+
tagLabel="POR FAZER"
|
|
154
|
+
onExamPress={() => {}}
|
|
132
155
|
/>
|
|
133
156
|
</View>
|
|
134
157
|
),
|
|
@@ -4,7 +4,7 @@ import { theme } from '../../../styles/theme';
|
|
|
4
4
|
import { Tag } from '../../DataDisplay/Tag/Tag';
|
|
5
5
|
import { ProgressBar } from '../../DataDisplay/ProgressBar/ProgressBar';
|
|
6
6
|
import { Badge } from '../../DataDisplay/Badge/Badge';
|
|
7
|
-
import { Lock, Check, GraduationCap, RotateCcw, CalendarPlus } from 'lucide-react-native';
|
|
7
|
+
import { Lock, Check, GraduationCap, RotateCcw, CalendarPlus, PenTool } from 'lucide-react-native';
|
|
8
8
|
import { useResponsive } from '../../../hooks/useResponsive';
|
|
9
9
|
import { Typography } from '../../Typography/Typography';
|
|
10
10
|
import React, { useRef } from 'react';
|
|
@@ -16,7 +16,7 @@ export type ModuleCardStatus = 'active' | 'locked' | 'completed' | 'dark' | 'act
|
|
|
16
16
|
*
|
|
17
17
|
* Regras de Animação e Clique:
|
|
18
18
|
* - `active`: O cartão como um todo tem animação de escala e é clicável via `onPress`.
|
|
19
|
-
* - `active-dark`: O cartão é estático. Apenas os botões internos de "Agendar" (`onSchedulePress`) e "Rever" (`onReviewPress`) têm animação individual.
|
|
19
|
+
* - `active-dark`: O cartão é estático. Apenas os botões internos de "Agendar" (`onSchedulePress`), "Exame" (`onExamPress`) e "Rever" (`onReviewPress`) têm animação individual quando fornecidos.
|
|
20
20
|
* - `completed`: O cartão é estático. Apenas o ícone/botão superior direito de "Rever" (`onReviewPress`) tem animação individual.
|
|
21
21
|
* - `locked` / `dark`: O cartão não é interativo.
|
|
22
22
|
*/
|
|
@@ -47,6 +47,8 @@ export interface ModuleCardProps {
|
|
|
47
47
|
style?: ViewStyle | ViewStyle[];
|
|
48
48
|
/** Função de clique no botão de Agendar (modo active/dark). */
|
|
49
49
|
onSchedulePress?: () => void;
|
|
50
|
+
/** Função de clique no botão principal de Exame (modo active/dark). */
|
|
51
|
+
onExamPress?: () => void;
|
|
50
52
|
/** Função de clique no botão de Rever (modo completed/active/dark). */
|
|
51
53
|
onReviewPress?: () => void;
|
|
52
54
|
}
|
|
@@ -66,12 +68,14 @@ export const ModuleCard = ({
|
|
|
66
68
|
onPress,
|
|
67
69
|
style,
|
|
68
70
|
onSchedulePress,
|
|
71
|
+
onExamPress,
|
|
69
72
|
onReviewPress,
|
|
70
73
|
}: ModuleCardProps) => {
|
|
71
74
|
const { scale, scaleText, width } = useResponsive();
|
|
72
75
|
const isMobileScreen = width < 400;
|
|
73
76
|
|
|
74
77
|
const scheduleScale = useRef(new Animated.Value(1)).current;
|
|
78
|
+
const examScale = useRef(new Animated.Value(1)).current;
|
|
75
79
|
const reviewScale = useRef(new Animated.Value(1)).current;
|
|
76
80
|
const completedReviewScale = useRef(new Animated.Value(1)).current;
|
|
77
81
|
const scaleAnim = useRef(new Animated.Value(1)).current;
|
|
@@ -226,18 +230,7 @@ export const ModuleCard = ({
|
|
|
226
230
|
|
|
227
231
|
const subtitleVariant = size === 'xl' ? 'bodyLg' : size === 'lg' ? 'bodyMd' : 'bodySm';
|
|
228
232
|
|
|
229
|
-
|
|
230
|
-
if (status === 'active-dark') {
|
|
231
|
-
if (subtext) {
|
|
232
|
-
if (subtext.trim().startsWith('•')) {
|
|
233
|
-
displaySubtext = `Aula de revisão ${subtext.trim()}`;
|
|
234
|
-
} else {
|
|
235
|
-
displaySubtext = `Aula de revisão • ${subtext}`;
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
displaySubtext = 'Aula de revisão';
|
|
239
|
-
}
|
|
240
|
-
}
|
|
233
|
+
|
|
241
234
|
|
|
242
235
|
return (
|
|
243
236
|
<Animated.View style={[{ transform: [{ scale: scaleAnim }] }, style]}>
|
|
@@ -276,7 +269,7 @@ export const ModuleCard = ({
|
|
|
276
269
|
{title}
|
|
277
270
|
</Typography>
|
|
278
271
|
|
|
279
|
-
{(subtitle || subtext
|
|
272
|
+
{(subtitle || subtext) && (
|
|
280
273
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginTop: scale(2) }}>
|
|
281
274
|
<Typography variant={subtitleVariant} style={[
|
|
282
275
|
styles.subtitle,
|
|
@@ -285,9 +278,9 @@ export const ModuleCard = ({
|
|
|
285
278
|
flexShrink: 1, // Para o texto encolher se a tag ocupar espaço
|
|
286
279
|
}
|
|
287
280
|
]}>
|
|
288
|
-
{
|
|
289
|
-
{
|
|
290
|
-
{
|
|
281
|
+
{subtitle}
|
|
282
|
+
{subtitle && subtext && ' '}
|
|
283
|
+
{subtext && <Typography variant={subtitleVariant} style={styles.subtext}>{subtext}</Typography>}
|
|
291
284
|
</Typography>
|
|
292
285
|
{tagLabel && (status === 'active-dark' || status === 'active') && (
|
|
293
286
|
<Tag
|
|
@@ -340,31 +333,52 @@ export const ModuleCard = ({
|
|
|
340
333
|
|
|
341
334
|
{status === 'active-dark' && (
|
|
342
335
|
<View style={styles.compactDarkFooter}>
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
336
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: scale(8) }}>
|
|
337
|
+
{onSchedulePress && (
|
|
338
|
+
<Animated.View style={{ transform: [{ scale: scheduleScale }] }}>
|
|
339
|
+
<Pressable
|
|
340
|
+
onPress={onSchedulePress}
|
|
341
|
+
onPressIn={() => animateBtnIn(scheduleScale)}
|
|
342
|
+
onPressOut={() => animateBtnOut(scheduleScale)}
|
|
343
|
+
hitSlop={8}
|
|
344
|
+
style={{ flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.primary, paddingHorizontal: scale(14), paddingVertical: scale(6), borderRadius: 100 }}
|
|
345
|
+
>
|
|
346
|
+
<CalendarPlus stroke={theme.colors.white} strokeWidth={2.5} size={scale(14)} />
|
|
347
|
+
<Typography variant="label" style={{ color: theme.colors.white, fontSize: scaleText(12), fontWeight: 'bold', marginLeft: scale(6) }}>Agendar Aula</Typography>
|
|
348
|
+
</Pressable>
|
|
349
|
+
</Animated.View>
|
|
350
|
+
)}
|
|
355
351
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
352
|
+
{onExamPress && (
|
|
353
|
+
<Animated.View style={{ transform: [{ scale: examScale }] }}>
|
|
354
|
+
<Pressable
|
|
355
|
+
onPress={onExamPress}
|
|
356
|
+
onPressIn={() => animateBtnIn(examScale)}
|
|
357
|
+
onPressOut={() => animateBtnOut(examScale)}
|
|
358
|
+
hitSlop={8}
|
|
359
|
+
style={{ flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.primary, paddingHorizontal: scale(14), paddingVertical: scale(6), borderRadius: 100 }}
|
|
360
|
+
>
|
|
361
|
+
<PenTool stroke={theme.colors.white} strokeWidth={2.5} size={scale(14)} />
|
|
362
|
+
<Typography variant="label" style={{ color: theme.colors.white, fontSize: scaleText(12), fontWeight: 'bold', marginLeft: scale(6) }}>Fazer Exame</Typography>
|
|
363
|
+
</Pressable>
|
|
364
|
+
</Animated.View>
|
|
365
|
+
)}
|
|
366
|
+
</View>
|
|
367
|
+
|
|
368
|
+
{onReviewPress && (
|
|
369
|
+
<Animated.View style={{ transform: [{ scale: reviewScale }] }}>
|
|
370
|
+
<Pressable
|
|
371
|
+
style={styles.compactReviewBtn}
|
|
372
|
+
onPress={onReviewPress}
|
|
373
|
+
onPressIn={() => animateBtnIn(reviewScale)}
|
|
374
|
+
onPressOut={() => animateBtnOut(reviewScale)}
|
|
375
|
+
hitSlop={8}
|
|
376
|
+
>
|
|
377
|
+
<RotateCcw stroke={theme.colors.primary} strokeWidth={2.5} size={scale(16)} />
|
|
378
|
+
<Typography variant="label" style={[styles.reviewIconText, { color: theme.colors.primary, fontSize: scaleText(10), marginLeft: scale(4), marginTop: 0 }]}>REVER</Typography>
|
|
379
|
+
</Pressable>
|
|
380
|
+
</Animated.View>
|
|
381
|
+
)}
|
|
368
382
|
</View>
|
|
369
383
|
)}
|
|
370
384
|
|