react-native-elearn-ui 0.1.0

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.
Files changed (100) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +37 -0
  3. package/lib/module/components/Button.js +82 -0
  4. package/lib/module/components/Button.js.map +1 -0
  5. package/lib/module/components/Card.js +49 -0
  6. package/lib/module/components/Card.js.map +1 -0
  7. package/lib/module/components/CircularProgress.js +80 -0
  8. package/lib/module/components/CircularProgress.js.map +1 -0
  9. package/lib/module/components/Icon.js +268 -0
  10. package/lib/module/components/Icon.js.map +1 -0
  11. package/lib/module/components/ProgressBar.js +39 -0
  12. package/lib/module/components/ProgressBar.js.map +1 -0
  13. package/lib/module/components/Typography.js +102 -0
  14. package/lib/module/components/Typography.js.map +1 -0
  15. package/lib/module/components/index.js +10 -0
  16. package/lib/module/components/index.js.map +1 -0
  17. package/lib/module/context/ElearnConfigContext.js +76 -0
  18. package/lib/module/context/ElearnConfigContext.js.map +1 -0
  19. package/lib/module/context/ThemeContext.js +45 -0
  20. package/lib/module/context/ThemeContext.js.map +1 -0
  21. package/lib/module/index.js +13 -0
  22. package/lib/module/index.js.map +1 -0
  23. package/lib/module/multiply.js +6 -0
  24. package/lib/module/multiply.js.map +1 -0
  25. package/lib/module/package.json +1 -0
  26. package/lib/module/screens/HomeScreen.js +330 -0
  27. package/lib/module/screens/HomeScreen.js.map +1 -0
  28. package/lib/module/screens/QbankScreen.js +200 -0
  29. package/lib/module/screens/QbankScreen.js.map +1 -0
  30. package/lib/module/screens/QuestionScreen.js +383 -0
  31. package/lib/module/screens/QuestionScreen.js.map +1 -0
  32. package/lib/module/screens/QuizStartScreen.js +230 -0
  33. package/lib/module/screens/QuizStartScreen.js.map +1 -0
  34. package/lib/module/screens/ResultScreen.js +318 -0
  35. package/lib/module/screens/ResultScreen.js.map +1 -0
  36. package/lib/module/screens/TopicListScreen.js +222 -0
  37. package/lib/module/screens/TopicListScreen.js.map +1 -0
  38. package/lib/module/screens/index.js +9 -0
  39. package/lib/module/screens/index.js.map +1 -0
  40. package/lib/module/types/index.js +2 -0
  41. package/lib/module/types/index.js.map +1 -0
  42. package/lib/typescript/package.json +1 -0
  43. package/lib/typescript/src/components/Button.d.ts +14 -0
  44. package/lib/typescript/src/components/Button.d.ts.map +1 -0
  45. package/lib/typescript/src/components/Card.d.ts +12 -0
  46. package/lib/typescript/src/components/Card.d.ts.map +1 -0
  47. package/lib/typescript/src/components/CircularProgress.d.ts +15 -0
  48. package/lib/typescript/src/components/CircularProgress.d.ts.map +1 -0
  49. package/lib/typescript/src/components/Icon.d.ts +11 -0
  50. package/lib/typescript/src/components/Icon.d.ts.map +1 -0
  51. package/lib/typescript/src/components/ProgressBar.d.ts +11 -0
  52. package/lib/typescript/src/components/ProgressBar.d.ts.map +1 -0
  53. package/lib/typescript/src/components/Typography.d.ts +12 -0
  54. package/lib/typescript/src/components/Typography.d.ts.map +1 -0
  55. package/lib/typescript/src/components/index.d.ts +9 -0
  56. package/lib/typescript/src/components/index.d.ts.map +1 -0
  57. package/lib/typescript/src/context/ElearnConfigContext.d.ts +22 -0
  58. package/lib/typescript/src/context/ElearnConfigContext.d.ts.map +1 -0
  59. package/lib/typescript/src/context/ThemeContext.d.ts +11 -0
  60. package/lib/typescript/src/context/ThemeContext.d.ts.map +1 -0
  61. package/lib/typescript/src/index.d.ts +6 -0
  62. package/lib/typescript/src/index.d.ts.map +1 -0
  63. package/lib/typescript/src/multiply.d.ts +2 -0
  64. package/lib/typescript/src/multiply.d.ts.map +1 -0
  65. package/lib/typescript/src/screens/HomeScreen.d.ts +3 -0
  66. package/lib/typescript/src/screens/HomeScreen.d.ts.map +1 -0
  67. package/lib/typescript/src/screens/QbankScreen.d.ts +3 -0
  68. package/lib/typescript/src/screens/QbankScreen.d.ts.map +1 -0
  69. package/lib/typescript/src/screens/QuestionScreen.d.ts +11 -0
  70. package/lib/typescript/src/screens/QuestionScreen.d.ts.map +1 -0
  71. package/lib/typescript/src/screens/QuizStartScreen.d.ts +10 -0
  72. package/lib/typescript/src/screens/QuizStartScreen.d.ts.map +1 -0
  73. package/lib/typescript/src/screens/ResultScreen.d.ts +11 -0
  74. package/lib/typescript/src/screens/ResultScreen.d.ts.map +1 -0
  75. package/lib/typescript/src/screens/TopicListScreen.d.ts +9 -0
  76. package/lib/typescript/src/screens/TopicListScreen.d.ts.map +1 -0
  77. package/lib/typescript/src/screens/index.d.ts +7 -0
  78. package/lib/typescript/src/screens/index.d.ts.map +1 -0
  79. package/lib/typescript/src/types/index.d.ts +107 -0
  80. package/lib/typescript/src/types/index.d.ts.map +1 -0
  81. package/package.json +121 -0
  82. package/src/components/Button.tsx +101 -0
  83. package/src/components/Card.tsx +57 -0
  84. package/src/components/CircularProgress.tsx +93 -0
  85. package/src/components/Icon.tsx +338 -0
  86. package/src/components/ProgressBar.tsx +47 -0
  87. package/src/components/Typography.tsx +112 -0
  88. package/src/components/index.ts +8 -0
  89. package/src/context/ElearnConfigContext.tsx +90 -0
  90. package/src/context/ThemeContext.tsx +37 -0
  91. package/src/index.tsx +33 -0
  92. package/src/multiply.tsx +3 -0
  93. package/src/screens/HomeScreen.tsx +291 -0
  94. package/src/screens/QbankScreen.tsx +176 -0
  95. package/src/screens/QuestionScreen.tsx +402 -0
  96. package/src/screens/QuizStartScreen.tsx +215 -0
  97. package/src/screens/ResultScreen.tsx +303 -0
  98. package/src/screens/TopicListScreen.tsx +200 -0
  99. package/src/screens/index.ts +6 -0
  100. package/src/types/index.ts +122 -0
@@ -0,0 +1,338 @@
1
+ import React from 'react';
2
+ import Svg, { Path, Circle, G } from 'react-native-svg';
3
+ import { useTheme } from '../context/ThemeContext';
4
+
5
+ export type IconName =
6
+ | 'bell'
7
+ | 'user'
8
+ | 'chevron-right'
9
+ | 'chevron-left'
10
+ | 'arrow-left'
11
+ | 'book-open'
12
+ | 'check-circle'
13
+ | 'x-circle'
14
+ | 'clock'
15
+ | 'award'
16
+ | 'search'
17
+ | 'flask' // Chemistry
18
+ | 'atom' // Physics
19
+ | 'dna' // Biology
20
+ | 'folder' // Subject folder
21
+ | 'info'
22
+ | 'play'
23
+ | 'star';
24
+
25
+ interface IconProps {
26
+ name: IconName;
27
+ size?: number;
28
+ color?: string;
29
+ strokeWidth?: number;
30
+ }
31
+
32
+ export const Icon: React.FC<IconProps> = ({
33
+ name,
34
+ size = 24,
35
+ color,
36
+ strokeWidth = 2,
37
+ }) => {
38
+ const theme = useTheme();
39
+ const iconColor = color || theme.textPrimary;
40
+
41
+ const renderIconContent = () => {
42
+ switch (name) {
43
+ case 'bell':
44
+ return (
45
+ <Path
46
+ d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0"
47
+ stroke={iconColor}
48
+ strokeWidth={strokeWidth}
49
+ strokeLinecap="round"
50
+ strokeLinejoin="round"
51
+ fill="none"
52
+ />
53
+ );
54
+ case 'user':
55
+ return (
56
+ <G>
57
+ <Path
58
+ d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
59
+ stroke={iconColor}
60
+ strokeWidth={strokeWidth}
61
+ strokeLinecap="round"
62
+ strokeLinejoin="round"
63
+ fill="none"
64
+ />
65
+ <Circle
66
+ cx="12"
67
+ cy="7"
68
+ r="4"
69
+ stroke={iconColor}
70
+ strokeWidth={strokeWidth}
71
+ strokeLinecap="round"
72
+ strokeLinejoin="round"
73
+ fill="none"
74
+ />
75
+ </G>
76
+ );
77
+ case 'chevron-right':
78
+ return (
79
+ <Path
80
+ d="M9 18l6-6-6-6"
81
+ stroke={iconColor}
82
+ strokeWidth={strokeWidth}
83
+ strokeLinecap="round"
84
+ strokeLinejoin="round"
85
+ fill="none"
86
+ />
87
+ );
88
+ case 'chevron-left':
89
+ return (
90
+ <Path
91
+ d="M15 18l-6-6 6-6"
92
+ stroke={iconColor}
93
+ strokeWidth={strokeWidth}
94
+ strokeLinecap="round"
95
+ strokeLinejoin="round"
96
+ fill="none"
97
+ />
98
+ );
99
+ case 'arrow-left':
100
+ return (
101
+ <Path
102
+ d="M19 12H5M12 19l-7-7 7-7"
103
+ stroke={iconColor}
104
+ strokeWidth={strokeWidth}
105
+ strokeLinecap="round"
106
+ strokeLinejoin="round"
107
+ fill="none"
108
+ />
109
+ );
110
+ case 'book-open':
111
+ return (
112
+ <Path
113
+ d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2zM22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"
114
+ stroke={iconColor}
115
+ strokeWidth={strokeWidth}
116
+ strokeLinecap="round"
117
+ strokeLinejoin="round"
118
+ fill="none"
119
+ />
120
+ );
121
+ case 'check-circle':
122
+ return (
123
+ <G>
124
+ <Circle
125
+ cx="12"
126
+ cy="12"
127
+ r="10"
128
+ stroke={iconColor}
129
+ strokeWidth={strokeWidth}
130
+ fill="none"
131
+ />
132
+ <Path
133
+ d="M9 11l3 3 6-6"
134
+ stroke={iconColor}
135
+ strokeWidth={strokeWidth}
136
+ strokeLinecap="round"
137
+ strokeLinejoin="round"
138
+ fill="none"
139
+ />
140
+ </G>
141
+ );
142
+ case 'x-circle':
143
+ return (
144
+ <G>
145
+ <Circle
146
+ cx="12"
147
+ cy="12"
148
+ r="10"
149
+ stroke={iconColor}
150
+ strokeWidth={strokeWidth}
151
+ fill="none"
152
+ />
153
+ <Path
154
+ d="M15 9l-6 6M9 9l6 6"
155
+ stroke={iconColor}
156
+ strokeWidth={strokeWidth}
157
+ strokeLinecap="round"
158
+ strokeLinejoin="round"
159
+ fill="none"
160
+ />
161
+ </G>
162
+ );
163
+ case 'clock':
164
+ return (
165
+ <G>
166
+ <Circle
167
+ cx="12"
168
+ cy="12"
169
+ r="10"
170
+ stroke={iconColor}
171
+ strokeWidth={strokeWidth}
172
+ fill="none"
173
+ />
174
+ <Path
175
+ d="M12 6v6l4 2"
176
+ stroke={iconColor}
177
+ strokeWidth={strokeWidth}
178
+ strokeLinecap="round"
179
+ strokeLinejoin="round"
180
+ fill="none"
181
+ />
182
+ </G>
183
+ );
184
+ case 'award':
185
+ return (
186
+ <G>
187
+ <Circle
188
+ cx="12"
189
+ cy="8"
190
+ r="7"
191
+ stroke={iconColor}
192
+ strokeWidth={strokeWidth}
193
+ fill="none"
194
+ />
195
+ <Path
196
+ d="M8.21 13.89L7 23l5-3 5 3-1.21-9.12"
197
+ stroke={iconColor}
198
+ strokeWidth={strokeWidth}
199
+ strokeLinecap="round"
200
+ strokeLinejoin="round"
201
+ fill="none"
202
+ />
203
+ </G>
204
+ );
205
+ case 'search':
206
+ return (
207
+ <G>
208
+ <Circle
209
+ cx="11"
210
+ cy="11"
211
+ r="8"
212
+ stroke={iconColor}
213
+ strokeWidth={strokeWidth}
214
+ fill="none"
215
+ />
216
+ <Path
217
+ d="M21 21l-4.35-4.35"
218
+ stroke={iconColor}
219
+ strokeWidth={strokeWidth}
220
+ strokeLinecap="round"
221
+ strokeLinejoin="round"
222
+ fill="none"
223
+ />
224
+ </G>
225
+ );
226
+ case 'flask':
227
+ return (
228
+ <Path
229
+ d="M6 3h12M12 3v11M9 3v11M15 3v11M10 9h4M12 21a7 7 0 0 1-7-7c0-2 1-3.9 3-5V3h8v6c2 1.1 3 3 3 5a7 7 0 0 1-7 7z"
230
+ stroke={iconColor}
231
+ strokeWidth={strokeWidth}
232
+ strokeLinecap="round"
233
+ strokeLinejoin="round"
234
+ fill="none"
235
+ />
236
+ );
237
+ case 'atom':
238
+ return (
239
+ <G>
240
+ <Circle
241
+ cx="12"
242
+ cy="12"
243
+ r="2"
244
+ stroke={iconColor}
245
+ strokeWidth={strokeWidth}
246
+ fill={iconColor}
247
+ />
248
+ <Path
249
+ d="M12 22C4 22 2 17 2 12S4 2 12 2s10 5 10 10-2 10-10 10z"
250
+ stroke={iconColor}
251
+ strokeWidth={strokeWidth}
252
+ strokeDasharray="4 4"
253
+ fill="none"
254
+ />
255
+ <Path
256
+ d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"
257
+ stroke={iconColor}
258
+ strokeWidth={strokeWidth}
259
+ fill="none"
260
+ />
261
+ </G>
262
+ );
263
+ case 'dna':
264
+ return (
265
+ <Path
266
+ d="M4.5 10.5C6 12 8 13.5 10 15s4.5 3 6.5 4.5M19.5 4.5C18 3 16 1.5 14 0s-4.5 1.5-6.5 3M4.5 4.5c3 3 6 6 9 9m-9 0c3-3 6-6 9-9M12 12l2.5 2.5m-5 0L12 12"
267
+ stroke={iconColor}
268
+ strokeWidth={strokeWidth}
269
+ strokeLinecap="round"
270
+ strokeLinejoin="round"
271
+ fill="none"
272
+ />
273
+ );
274
+ case 'folder':
275
+ return (
276
+ <Path
277
+ d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
278
+ stroke={iconColor}
279
+ strokeWidth={strokeWidth}
280
+ strokeLinecap="round"
281
+ strokeLinejoin="round"
282
+ fill="none"
283
+ />
284
+ );
285
+ case 'info':
286
+ return (
287
+ <G>
288
+ <Circle
289
+ cx="12"
290
+ cy="12"
291
+ r="10"
292
+ stroke={iconColor}
293
+ strokeWidth={strokeWidth}
294
+ fill="none"
295
+ />
296
+ <Path
297
+ d="M12 16v-4M12 8h.01"
298
+ stroke={iconColor}
299
+ strokeWidth={strokeWidth + 0.5}
300
+ strokeLinecap="round"
301
+ strokeLinejoin="round"
302
+ fill="none"
303
+ />
304
+ </G>
305
+ );
306
+ case 'play':
307
+ return (
308
+ <Path
309
+ d="M5 3l14 9-14 9V3z"
310
+ stroke={iconColor}
311
+ strokeWidth={strokeWidth}
312
+ strokeLinecap="round"
313
+ strokeLinejoin="round"
314
+ fill="none"
315
+ />
316
+ );
317
+ case 'star':
318
+ return (
319
+ <Path
320
+ d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
321
+ stroke={iconColor}
322
+ strokeWidth={strokeWidth}
323
+ strokeLinecap="round"
324
+ strokeLinejoin="round"
325
+ fill="none"
326
+ />
327
+ );
328
+ default:
329
+ return null;
330
+ }
331
+ };
332
+
333
+ return (
334
+ <Svg width={size} height={size} viewBox="0 0 24 24">
335
+ {renderIconContent()}
336
+ </Svg>
337
+ );
338
+ };
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import type { StyleProp, ViewStyle } from 'react-native';
4
+ import { useTheme } from '../context/ThemeContext';
5
+
6
+ interface ProgressBarProps {
7
+ progress: number; // 0 to 1
8
+ color?: string;
9
+ height?: number;
10
+ style?: StyleProp<ViewStyle>;
11
+ }
12
+
13
+ export const ProgressBar: React.FC<ProgressBarProps> = ({
14
+ progress,
15
+ color,
16
+ height = 8,
17
+ style,
18
+ }) => {
19
+ const theme = useTheme();
20
+ const cappedProgress = Math.max(0, Math.min(1, progress));
21
+
22
+ return (
23
+ <View style={[styles.container, { height, backgroundColor: theme.border }, style]}>
24
+ <View
25
+ style={[
26
+ styles.fill,
27
+ {
28
+ width: `${cappedProgress * 100}%`,
29
+ backgroundColor: color || theme.primary,
30
+ borderRadius: height / 2,
31
+ },
32
+ ]}
33
+ />
34
+ </View>
35
+ );
36
+ };
37
+
38
+ const styles = StyleSheet.create({
39
+ container: {
40
+ width: '100%',
41
+ borderRadius: 999,
42
+ overflow: 'hidden',
43
+ },
44
+ fill: {
45
+ height: '100%',
46
+ },
47
+ });
@@ -0,0 +1,112 @@
1
+ import React from 'react';
2
+ import { Text } from 'react-native';
3
+ import type { TextProps } from 'react-native';
4
+ import { useTheme } from '../context/ThemeContext';
5
+
6
+ interface TypographyProps extends TextProps {
7
+ variant?: 'h1' | 'h2' | 'h3' | 'body' | 'bodyLight' | 'caption' | 'button' | 'label';
8
+ color?: string;
9
+ align?: 'auto' | 'left' | 'right' | 'center' | 'justify';
10
+ bold?: boolean;
11
+ medium?: boolean;
12
+ }
13
+
14
+ export const Typography: React.FC<TypographyProps> = ({
15
+ variant = 'body',
16
+ color,
17
+ align = 'auto',
18
+ bold = false,
19
+ medium = false,
20
+ style,
21
+ children,
22
+ ...props
23
+ }) => {
24
+ const theme = useTheme();
25
+
26
+ const getStyleForVariant = () => {
27
+ switch (variant) {
28
+ case 'h1':
29
+ return {
30
+ fontSize: 24,
31
+ lineHeight: 32,
32
+ fontWeight: '700' as const,
33
+ fontFamily: theme.fontBold,
34
+ };
35
+ case 'h2':
36
+ return {
37
+ fontSize: 18,
38
+ lineHeight: 24,
39
+ fontWeight: '600' as const,
40
+ fontFamily: theme.fontMedium,
41
+ };
42
+ case 'h3':
43
+ return {
44
+ fontSize: 16,
45
+ lineHeight: 22,
46
+ fontWeight: '600' as const,
47
+ fontFamily: theme.fontMedium,
48
+ };
49
+ case 'body':
50
+ return {
51
+ fontSize: 14,
52
+ lineHeight: 20,
53
+ fontWeight: '400' as const,
54
+ fontFamily: theme.fontRegular,
55
+ };
56
+ case 'bodyLight':
57
+ return {
58
+ fontSize: 14,
59
+ lineHeight: 20,
60
+ fontWeight: '300' as const,
61
+ fontFamily: theme.fontRegular,
62
+ };
63
+ case 'caption':
64
+ return {
65
+ fontSize: 12,
66
+ lineHeight: 16,
67
+ fontWeight: '400' as const,
68
+ fontFamily: theme.fontRegular,
69
+ };
70
+ case 'button':
71
+ return {
72
+ fontSize: 15,
73
+ lineHeight: 20,
74
+ fontWeight: '600' as const,
75
+ fontFamily: theme.fontMedium,
76
+ };
77
+ case 'label':
78
+ return {
79
+ fontSize: 13,
80
+ lineHeight: 18,
81
+ fontWeight: '500' as const,
82
+ fontFamily: theme.fontMedium,
83
+ };
84
+ default:
85
+ return {};
86
+ }
87
+ };
88
+
89
+ const defaultColor = () => {
90
+ if (variant === 'caption' || variant === 'bodyLight') {
91
+ return theme.textSecondary;
92
+ }
93
+ return theme.textPrimary;
94
+ };
95
+
96
+ const textStyle = [
97
+ getStyleForVariant(),
98
+ {
99
+ color: color || defaultColor(),
100
+ textAlign: align,
101
+ },
102
+ bold && { fontWeight: '700' as const, fontFamily: theme.fontBold },
103
+ medium && { fontWeight: '500' as const, fontFamily: theme.fontMedium },
104
+ style,
105
+ ];
106
+
107
+ return (
108
+ <Text style={textStyle} {...props}>
109
+ {children}
110
+ </Text>
111
+ );
112
+ };
@@ -0,0 +1,8 @@
1
+ export { Typography } from './Typography';
2
+ export { Button } from './Button';
3
+ export { Card } from './Card';
4
+ export { ProgressBar } from './ProgressBar';
5
+ export { CircularProgress } from './CircularProgress';
6
+ export { Icon } from './Icon';
7
+ export type { IconName } from './Icon';
8
+ export { DEFAULT_THEME, useTheme, ThemeProvider } from '../context/ThemeContext';
@@ -0,0 +1,90 @@
1
+ import React, { createContext, useContext, useMemo } from 'react';
2
+ import type { ElearnConfig, ElearnCallbacks, StringsConfig, Course, DailyQuizConfig } from '../types';
3
+ import { ThemeProvider } from './ThemeContext';
4
+
5
+ export const DEFAULT_STRINGS: Required<StringsConfig> = {
6
+ homeHeaderTitle: "Ready to learn?",
7
+ homeHeaderSubtitle: "Practice daily & improve scores",
8
+ dailyQuizTitle: "One step learnings - Daily quiz",
9
+ dailyQuizSubtitle: "Attempt daily prep check!",
10
+ dailyQuizProgressLabel: "Track Progress",
11
+ trackQuickLabel: "Track Quick",
12
+ subjectsTitle: "Subjects",
13
+ popularTopicsTitle: "Popular Topics",
14
+ qbankTitle: "Qbank",
15
+ qbankSubtitle: "All subjects folder & question bank",
16
+ topicsLabel: "Topics",
17
+ questionsCountLabel: "Questions",
18
+ startQuizButton: "Start QBank",
19
+ topicsAndItemsLabel: "Topics and items",
20
+ infoTitle: "Info",
21
+ questionLabel: "Question",
22
+ explanationLabel: "Explanation",
23
+ nextButtonLabel: "Next",
24
+ submitButtonLabel: "Submit",
25
+ correctAnswerLabel: "Correct Answer",
26
+ incorrectAnswerLabel: "Incorrect Answer",
27
+ resultsTitle: "QBank Analysis",
28
+ resultsSubtitle: "Here is your QBank performance summary!",
29
+ accuracyLabel: "Accuracy",
30
+ timeSpentLabel: "Time Spent",
31
+ correctAnswersCountLabel: "Correct Answers",
32
+ reviewAnswersButton: "Review Answers",
33
+ goHomeButton: "Back to Dashboard",
34
+ scorecardTitle: "Quiz Analysis",
35
+ };
36
+
37
+ interface ConfigContextValue {
38
+ config: ElearnConfig;
39
+ callbacks: ElearnCallbacks;
40
+ getString: (key: keyof StringsConfig) => string;
41
+ getCourses: () => Course[];
42
+ getDailyQuiz: () => DailyQuizConfig | undefined;
43
+ }
44
+
45
+ const ConfigContext = createContext<ConfigContextValue | null>(null);
46
+
47
+ interface ElearnConfigProviderProps {
48
+ config?: ElearnConfig;
49
+ callbacks?: ElearnCallbacks;
50
+ children: React.ReactNode;
51
+ }
52
+
53
+ export const ElearnConfigProvider: React.FC<ElearnConfigProviderProps> = ({
54
+ config = {},
55
+ callbacks = {},
56
+ children,
57
+ }) => {
58
+ const mergedStrings = useMemo(() => {
59
+ return { ...DEFAULT_STRINGS, ...config.strings };
60
+ }, [config.strings]);
61
+
62
+ const value = useMemo<ConfigContextValue>(() => {
63
+ return {
64
+ config,
65
+ callbacks,
66
+ getString: (key) => mergedStrings[key] || DEFAULT_STRINGS[key] || '',
67
+ getCourses: () => config.courses || [],
68
+ getDailyQuiz: () => config.dailyQuiz,
69
+ };
70
+ }, [config, callbacks, mergedStrings]);
71
+
72
+ return (
73
+ <ConfigContext.Provider value={value}>
74
+ <ThemeProvider theme={config.theme}>
75
+ {children}
76
+ </ThemeProvider>
77
+ </ConfigContext.Provider>
78
+ );
79
+ };
80
+
81
+ export const useElearnConfig = () => {
82
+ const context = useContext(ConfigContext);
83
+ if (!context) {
84
+ throw new Error('useElearnConfig must be used within an ElearnConfigProvider');
85
+ }
86
+ return context;
87
+ };
88
+ export { ThemeProvider };
89
+ export { useTheme } from './ThemeContext';
90
+ export { DEFAULT_THEME } from './ThemeContext';
@@ -0,0 +1,37 @@
1
+ import React, { createContext, useContext, useMemo } from 'react';
2
+ import type { ThemeConfig } from '../types';
3
+
4
+ export const DEFAULT_THEME: ThemeConfig = {
5
+ primary: '#007A87', // Dark Teal
6
+ secondary: '#E6F4F5', // Soft Teal Accent
7
+ success: '#10B981', // Emerald Green for correct answers
8
+ danger: '#EF4444', // Red for incorrect answers
9
+ warning: '#F59E0B', // Amber
10
+ background: '#F8FAFC', // Sleek slate grey-white background
11
+ cardBackground: '#FFFFFF', // Pure White
12
+ textPrimary: '#1E293B', // Slate 800
13
+ textSecondary: '#64748B', // Slate 500
14
+ textInverse: '#FFFFFF', // White
15
+ border: '#E2E8F0', // Slate 200
16
+ };
17
+
18
+ const ThemeContext = createContext<ThemeConfig>(DEFAULT_THEME);
19
+
20
+ interface ThemeProviderProps {
21
+ theme?: Partial<ThemeConfig>;
22
+ children: React.ReactNode;
23
+ }
24
+
25
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {
26
+ const mergedTheme = useMemo(() => {
27
+ return { ...DEFAULT_THEME, ...theme };
28
+ }, [theme]);
29
+
30
+ return (
31
+ <ThemeContext.Provider value={mergedTheme}>
32
+ {children}
33
+ </ThemeContext.Provider>
34
+ );
35
+ };
36
+
37
+ export const useTheme = () => useContext(ThemeContext);
package/src/index.tsx ADDED
@@ -0,0 +1,33 @@
1
+ // Types export
2
+ export * from './types';
3
+
4
+ // Contexts & Providers
5
+ export {
6
+ ElearnConfigProvider,
7
+ useElearnConfig,
8
+ ThemeProvider,
9
+ useTheme,
10
+ DEFAULT_THEME,
11
+ DEFAULT_STRINGS,
12
+ } from './context/ElearnConfigContext';
13
+
14
+ // Atomic Components
15
+ export {
16
+ Typography,
17
+ Button,
18
+ Card,
19
+ ProgressBar,
20
+ CircularProgress,
21
+ Icon,
22
+ } from './components';
23
+ export type { IconName } from './components';
24
+
25
+ // Screens
26
+ export {
27
+ HomeScreen,
28
+ QbankScreen,
29
+ TopicListScreen,
30
+ QuizStartScreen,
31
+ QuestionScreen,
32
+ ResultScreen,
33
+ } from './screens';
@@ -0,0 +1,3 @@
1
+ export function multiply(a: number, b: number): number {
2
+ return a * b;
3
+ }