@xetwa/design-system 1.0.33 → 1.0.35

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.33",
3
+ "version": "1.0.35",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -24,6 +24,7 @@ const meta = {
24
24
  tagLabel: { control: 'text' },
25
25
  progress: { control: 'number' },
26
26
  segments: { control: 'number' },
27
+ size: { control: 'radio', options: ['md', 'lg', 'xl'] },
27
28
  },
28
29
  decorators: [
29
30
  (Story) => (
@@ -94,7 +95,6 @@ export const Grid: Story = {
94
95
  />
95
96
  <ModuleCard
96
97
  status="locked"
97
- number={3}
98
98
  title="A minha família"
99
99
  subtitle="5 lições"
100
100
  />
@@ -106,3 +106,37 @@ export const Grid: Story = {
106
106
  </View>
107
107
  ),
108
108
  };
109
+
110
+ export const Sizes: Story = {
111
+ args: {
112
+ status: 'active',
113
+ number: 1,
114
+ title: 'Tamanhos do Card',
115
+ subtitle: 'Compara os tamanhos disponíveis',
116
+ },
117
+ render: () => (
118
+ <View style={{ gap: 16, width: '100%' }}>
119
+ <ModuleCard
120
+ status="active"
121
+ number={1}
122
+ title="Tamanho Médio (md)"
123
+ subtitle="O padrão para a maioria das listas"
124
+ size="md"
125
+ />
126
+ <ModuleCard
127
+ status="active"
128
+ number={2}
129
+ title="Tamanho Grande (lg)"
130
+ subtitle="Destaque moderado para ecrãs com espaço"
131
+ size="lg"
132
+ />
133
+ <ModuleCard
134
+ status="active"
135
+ number={3}
136
+ title="Tamanho Extra (xl)"
137
+ subtitle="Máxima legibilidade e presença"
138
+ size="xl"
139
+ />
140
+ </View>
141
+ ),
142
+ };
@@ -30,6 +30,8 @@ export interface ModuleCardProps {
30
30
  progress?: number;
31
31
  /** Número de segmentos na barra de progresso. */
32
32
  segments?: number;
33
+ /** Tamanho do cartão (controla paddings, ícones e fontes). */
34
+ size?: 'md' | 'lg' | 'xl';
33
35
  onPress?: () => void;
34
36
  /** Cor customizada para o título. */
35
37
  titleColor?: string;
@@ -47,6 +49,7 @@ export const ModuleCard = ({
47
49
  tagLabel,
48
50
  progress,
49
51
  segments,
52
+ size = 'md',
50
53
  titleColor,
51
54
  subtitleColor,
52
55
  onPress,
@@ -112,7 +115,7 @@ export const ModuleCard = ({
112
115
  } : {};
113
116
 
114
117
  const renderLeftIconBox = () => {
115
- const bSize = isMobileScreen ? 'xl' : 'xxl';
118
+ const bSize = size === 'xl' ? 'xxxl' : size === 'lg' ? 'xxl' : isMobileScreen ? 'xl' : 'xxl';
116
119
  if (status === 'locked') {
117
120
  return (
118
121
  <Badge
@@ -133,8 +136,8 @@ export const ModuleCard = ({
133
136
  );
134
137
  }
135
138
  if (status === 'dark') {
136
- const boxSize = isMobileScreen ? scale(34) : scale(44);
137
- const capSize = isMobileScreen ? scale(18) : scale(24);
139
+ const boxSize = size === 'xl' ? scale(54) : size === 'lg' ? scale(48) : isMobileScreen ? scale(34) : scale(44);
140
+ const capSize = size === 'xl' ? scale(30) : size === 'lg' ? scale(28) : isMobileScreen ? scale(18) : scale(24);
138
141
  return (
139
142
  <View style={[
140
143
  styles.darkIconBox,
@@ -148,16 +151,21 @@ export const ModuleCard = ({
148
151
  </View>
149
152
  );
150
153
  }
154
+
151
155
  return (
152
156
  <Badge
153
157
  variant="primary"
154
- size={bSize}
158
+ size={bSize as any}
155
159
  content={number}
156
160
  />
157
161
  );
158
162
  };
159
163
 
160
- const colGap = isMobileScreen ? scale(8) : scale(12);
164
+ const colGap = size === 'xl' ? scale(16) : size === 'lg' ? scale(14) : isMobileScreen ? scale(8) : scale(12);
165
+ const cardPaddingV = size === 'xl' ? scale(20) : size === 'lg' ? scale(16) : isMobileScreen ? scale(10) : scale(14);
166
+ const cardPaddingH = size === 'xl' ? scale(20) : size === 'lg' ? scale(18) : isMobileScreen ? scale(12) : scale(15);
167
+ const titleFontSize = size === 'xl' ? scaleText(18) : size === 'lg' ? scaleText(16) : isMobileScreen ? scaleText(14) : scaleText(16);
168
+ const subtitleFontSize = size === 'xl' ? scaleText(14) : size === 'lg' ? scaleText(13) : isMobileScreen ? scaleText(10) : scaleText(12);
161
169
 
162
170
  return (
163
171
  <Pressable
@@ -166,8 +174,8 @@ export const ModuleCard = ({
166
174
  containerStyle,
167
175
  status === 'active' && activeShadow,
168
176
  {
169
- paddingVertical: isMobileScreen ? scale(10) : scale(14),
170
- paddingHorizontal: isMobileScreen ? scale(12) : scale(15),
177
+ paddingVertical: cardPaddingV,
178
+ paddingHorizontal: cardPaddingH,
171
179
  borderRadius: scale(18),
172
180
  },
173
181
  style,
@@ -181,11 +189,11 @@ export const ModuleCard = ({
181
189
  </View>
182
190
 
183
191
  <View style={[styles.content, { marginLeft: colGap }]}>
184
- <Typography style={[
192
+ <Typography variant="h2" style={[
185
193
  styles.title,
186
194
  {
187
195
  color: titleStyleColor,
188
- fontSize: isMobileScreen ? scaleText(14) : scaleText(16),
196
+ fontSize: titleFontSize,
189
197
  marginBottom: scale(2),
190
198
  }
191
199
  ]}>
@@ -193,11 +201,11 @@ export const ModuleCard = ({
193
201
  </Typography>
194
202
 
195
203
  {(subtitle || subtext) && (
196
- <Typography style={[
204
+ <Typography variant="bodyMd" style={[
197
205
  styles.subtitle,
198
206
  {
199
207
  color: subtitleStyleColor,
200
- fontSize: isMobileScreen ? scaleText(10) : scaleText(12),
208
+ fontSize: subtitleFontSize,
201
209
  }
202
210
  ]}>
203
211
  {subtitle}
@@ -58,6 +58,15 @@ export const Success: Story = {
58
58
  },
59
59
  };
60
60
 
61
+ export const WithLabels: Story = {
62
+ args: {
63
+ progress: 0.82,
64
+ size: 'sm',
65
+ labelTopLeft: 'Compreensão',
66
+ labelTopRight: '82%',
67
+ },
68
+ };
69
+
61
70
  export const Sizes: Story = {
62
71
  args: { progress: 0 },
63
72
  render: () => (
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
2
2
  import { View, StyleSheet, Animated, Easing } from 'react-native';
3
3
  import type { ViewStyle } from 'react-native';
4
4
  import { theme } from '../../../styles/theme';
5
+ import { Typography } from '../../Typography/Typography';
5
6
 
6
7
  /**
7
8
  * Barra de progresso para exibir a percentagem de conclusão de uma tarefa ou módulo.
@@ -21,6 +22,10 @@ export interface ProgressBarProps {
21
22
  fillColor?: string;
22
23
  /** Cor customizada forçada do trilho vazio */
23
24
  trackColor?: string;
25
+ /** Label apresentada no canto superior esquerdo */
26
+ labelTopLeft?: string;
27
+ /** Label apresentada no canto superior direito (ex: percentagem) */
28
+ labelTopRight?: string;
24
29
  style?: ViewStyle | ViewStyle[];
25
30
  }
26
31
 
@@ -31,6 +36,8 @@ export const ProgressBar = ({
31
36
  segments = 1,
32
37
  fillColor,
33
38
  trackColor,
39
+ labelTopLeft,
40
+ labelTopRight,
34
41
  style,
35
42
  }: ProgressBarProps) => {
36
43
  const [animatedProgress] = useState(() => new Animated.Value(0));
@@ -60,8 +67,19 @@ export const ProgressBar = ({
60
67
  const segmentRange = 1 / safeSegments;
61
68
 
62
69
  return (
63
- <View style={[styles.container, style]}>
64
- {segmentsArray.map((_, index) => {
70
+ <View style={style}>
71
+ {(labelTopLeft || labelTopRight) && (
72
+ <View style={styles.labelsWrapper}>
73
+ {labelTopLeft ? (
74
+ <Typography variant="btnSm">{labelTopLeft}</Typography>
75
+ ) : <View />}
76
+ {labelTopRight ? (
77
+ <Typography variant="btnSm" color={defaultFillColor}>{labelTopRight}</Typography>
78
+ ) : <View />}
79
+ </View>
80
+ )}
81
+ <View style={styles.container}>
82
+ {segmentsArray.map((_, index) => {
65
83
  const start = index * segmentRange;
66
84
  const end = (index + 1) * segmentRange;
67
85
 
@@ -92,11 +110,18 @@ export const ProgressBar = ({
92
110
  </View>
93
111
  );
94
112
  })}
113
+ </View>
95
114
  </View>
96
115
  );
97
116
  };
98
117
 
99
118
  const styles = StyleSheet.create({
119
+ labelsWrapper: {
120
+ flexDirection: 'row',
121
+ justifyContent: 'space-between',
122
+ alignItems: 'center',
123
+ marginBottom: 6,
124
+ },
100
125
  container: {
101
126
  flexDirection: 'row',
102
127
  width: '100%',
@@ -1,8 +1,8 @@
1
- import { useEffect, useRef } from 'react';
2
- import { View, StyleSheet, Animated } from 'react-native';
3
- import { theme } from '../../../styles/theme';
4
1
  import { Flame, Heart } from 'lucide-react-native';
2
+ import { useEffect, useRef } from 'react';
3
+ import { Animated, StyleSheet, View } from 'react-native';
5
4
  import { useResponsive } from '../../../hooks/useResponsive';
5
+ import { theme } from '../../../styles/theme';
6
6
  import { Typography } from '../../Typography/Typography';
7
7
 
8
8
  export type StatBadgeVariant = 'streak' | 'xp' | 'lives';