react-native-elearn-ui 0.1.9 → 0.1.11

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 (52) hide show
  1. package/lib/module/index.js +1 -1
  2. package/lib/module/index.js.map +1 -1
  3. package/lib/module/screens/HomeScreen.js +2 -1
  4. package/lib/module/screens/HomeScreen.js.map +1 -1
  5. package/lib/module/screens/PearlChaptersScreen.js +359 -0
  6. package/lib/module/screens/PearlChaptersScreen.js.map +1 -0
  7. package/lib/module/screens/PearlReaderScreen.js +313 -0
  8. package/lib/module/screens/PearlReaderScreen.js.map +1 -0
  9. package/lib/module/screens/PearlsScreen.js +43 -631
  10. package/lib/module/screens/PearlsScreen.js.map +1 -1
  11. package/lib/module/screens/QbankScreen.js +2 -1
  12. package/lib/module/screens/QbankScreen.js.map +1 -1
  13. package/lib/module/screens/QuestionScreen.js +2 -1
  14. package/lib/module/screens/QuestionScreen.js.map +1 -1
  15. package/lib/module/screens/QuizStartScreen.js +2 -1
  16. package/lib/module/screens/QuizStartScreen.js.map +1 -1
  17. package/lib/module/screens/ResultScreen.js +2 -1
  18. package/lib/module/screens/ResultScreen.js.map +1 -1
  19. package/lib/module/screens/TopicListScreen.js +2 -1
  20. package/lib/module/screens/TopicListScreen.js.map +1 -1
  21. package/lib/module/screens/index.js +2 -0
  22. package/lib/module/screens/index.js.map +1 -1
  23. package/lib/module/screens/pearlsMockData.js +77 -0
  24. package/lib/module/screens/pearlsMockData.js.map +1 -0
  25. package/lib/typescript/src/index.d.ts +1 -1
  26. package/lib/typescript/src/index.d.ts.map +1 -1
  27. package/lib/typescript/src/screens/PearlChaptersScreen.d.ts +13 -0
  28. package/lib/typescript/src/screens/PearlChaptersScreen.d.ts.map +1 -0
  29. package/lib/typescript/src/screens/PearlReaderScreen.d.ts +14 -0
  30. package/lib/typescript/src/screens/PearlReaderScreen.d.ts.map +1 -0
  31. package/lib/typescript/src/screens/PearlsScreen.d.ts +3 -0
  32. package/lib/typescript/src/screens/PearlsScreen.d.ts.map +1 -1
  33. package/lib/typescript/src/screens/index.d.ts +2 -0
  34. package/lib/typescript/src/screens/index.d.ts.map +1 -1
  35. package/lib/typescript/src/screens/pearlsMockData.d.ts +3 -0
  36. package/lib/typescript/src/screens/pearlsMockData.d.ts.map +1 -0
  37. package/lib/typescript/src/types/index.d.ts +15 -0
  38. package/lib/typescript/src/types/index.d.ts.map +1 -1
  39. package/package.json +3 -1
  40. package/src/index.tsx +2 -0
  41. package/src/screens/HomeScreen.tsx +1 -1
  42. package/src/screens/PearlChaptersScreen.tsx +330 -0
  43. package/src/screens/PearlReaderScreen.tsx +306 -0
  44. package/src/screens/PearlsScreen.tsx +30 -603
  45. package/src/screens/QbankScreen.tsx +1 -1
  46. package/src/screens/QuestionScreen.tsx +1 -1
  47. package/src/screens/QuizStartScreen.tsx +1 -1
  48. package/src/screens/ResultScreen.tsx +1 -1
  49. package/src/screens/TopicListScreen.tsx +1 -1
  50. package/src/screens/index.ts +2 -0
  51. package/src/screens/pearlsMockData.ts +70 -0
  52. package/src/types/index.ts +17 -0
@@ -1,189 +1,64 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import {
3
3
  View,
4
4
  ScrollView,
5
5
  StyleSheet,
6
6
  TouchableOpacity,
7
- SafeAreaView,
8
7
  StatusBar,
9
- Modal,
10
- Dimensions,
11
8
  } from 'react-native';
9
+ import { SafeAreaView } from 'react-native-safe-area-context';
12
10
  import { useElearnConfig } from '../context/ElearnConfigContext';
13
11
  import { useTheme } from '../context/ThemeContext';
14
12
  import { Typography, Card, Icon } from '../components';
15
-
16
- const { height: SCREEN_HEIGHT } = Dimensions.get('window');
13
+ import { MOCK_PEARLS_TOPICS } from './pearlsMockData';
14
+ import type { PearlTopic } from '../types';
17
15
 
18
16
  interface PearlsScreenProps {
19
17
  onBack?: () => void;
20
18
  hideHeader?: boolean;
19
+ onSelectTopic?: (topic: PearlTopic) => void;
20
+ title?: string;
21
21
  }
22
22
 
23
- // Mock Chapter detail shape
24
- interface PearlChapter {
25
- id: string;
26
- number: number;
27
- title: string;
28
- isFree?: boolean;
29
- isLocked?: boolean;
30
- bullets: string[];
31
- }
32
-
33
- interface PearlTopic {
34
- id: string;
35
- title: string;
36
- sections: {
37
- [sectionName: string]: PearlChapter[];
38
- };
39
- }
40
-
41
- // Mock database matching user images
42
- const MOCK_PEARLS_TOPICS: PearlTopic[] = [
43
- {
44
- id: 'topic_head_neck',
45
- title: 'Head and neck',
46
- sections: {
47
- 'Head and Neck': [
48
- {
49
- id: 'hn_c1',
50
- number: 1,
51
- title: 'Classify sino-nasal neoplasam. Discuss the newer entities',
52
- isFree: true,
53
- bullets: [
54
- 'Benign Neoplasms: Benign sino-nasal tumors are generally slow-growing and less likely to invade surrounding structures. Common benign types include inverted papilloma, oncocytic Schneiderian papilloma, and fungiform papilloma, all of which originate from the Schneiderian mucosa. Inverted papilloma is notable for its local aggressiveness and high recurrence rate, sometimes exhibiting malignant transformation into squamous cell carcinoma.',
55
- 'Malignant Neoplasms: Malignant tumors of the sino-nasal tract are rare but clinically significant due to their aggressive behavior, late presentation, and complex anatomical constraints that limit surgical access. The most common malignant tumor is squamous cell carcinoma, often arising from dysplastic or papillomatous lesions.',
56
- 'Esthesioneuroblastoma: A notable entity originating from the olfactory epithelium and displaying variable degrees of malignancy. Additionally, melanoma, lymphoma, and undifferentiated carcinoma can also occur in the sino-nasal region, often presenting with nasal obstruction, epistaxis, and facial pain.'
57
- ]
58
- },
59
- {
60
- id: 'hn_c2',
61
- number: 2,
62
- title: 'Histologic variants of ameloblastoma',
63
- isLocked: true,
64
- bullets: [
65
- 'Ameloblastoma is a benign but locally aggressive odontogenic neoplasm.',
66
- 'Follicular and plexiform are the most common histologic patterns.',
67
- 'Unicystic variants have a better prognosis and lower recurrence rates.'
68
- ]
69
- },
70
- {
71
- id: 'hn_c3',
72
- number: 3,
73
- title: 'Role of brush ctology in diagnosis of oral cancerous and precancerous lessions',
74
- isLocked: true,
75
- bullets: [
76
- 'Oral brush cytology is a non-invasive screening aid.',
77
- 'High sensitivity for identifying cellular dysplasias.',
78
- 'Must be followed by scalpel biopsy for definitive diagnosis.'
79
- ]
80
- }
81
- ],
82
- 'Eye': [
83
- {
84
- id: 'eye_c1',
85
- number: 1,
86
- title: 'Classify sino-nasal neoplasam. Discuss the newer entities',
87
- isLocked: true,
88
- bullets: []
89
- },
90
- {
91
- id: 'eye_c2',
92
- number: 2,
93
- title: 'Histologic variants of ameloblastoma',
94
- isLocked: true,
95
- bullets: []
96
- }
97
- ]
98
- }
99
- },
100
- { id: 'topic_brain_spine', title: 'Brain, Spine and Meninges', sections: {} },
101
- { id: 'topic_breast', title: 'Breast Pathology', sections: {} },
102
- { id: 'topic_skin', title: 'Skin and Connective Tissue', sections: {} },
103
- { id: 'topic_kidney', title: 'Kidney & Urinary Tract', sections: {} },
104
- { id: 'topic_gastro', title: 'Gastro-Intestinal System', sections: {} },
105
- { id: 'topic_endocrine', title: 'Endocrine Pathology', sections: {} },
106
- { id: 'topic_general', title: 'General Pathology', sections: {} },
107
- { id: 'topic_male_genital', title: 'Male Genital System', sections: {} },
108
- { id: 'topic_thoracic', title: 'Thoracic Pathology', sections: {} }
109
- ];
110
-
111
23
  export const PearlsScreen: React.FC<PearlsScreenProps> = ({
112
24
  onBack,
113
25
  hideHeader = false,
26
+ onSelectTopic,
27
+ title = 'Pearls',
114
28
  }) => {
115
29
  const { callbacks } = useElearnConfig();
116
30
  const theme = useTheme();
117
31
 
118
- // Navigation State
119
- const [currentView, setCurrentView] = useState<'topics' | 'chapters' | 'reader'>('topics');
120
- const [selectedTopic, setSelectedTopic] = useState<PearlTopic | null>(null);
121
-
122
- // Flatten all chapters of a topic to easily paginate inside the reader view
123
- const [flattenedChapters, setFlattenedChapters] = useState<PearlChapter[]>([]);
124
- const [activeChapterIndex, setActiveChapterIndex] = useState<number>(0);
125
-
126
- const [isCompleted, setIsCompleted] = useState(false);
127
- const [bottomSheetVisible, setBottomSheetVisible] = useState(false);
128
-
129
32
  const handleBackPress = () => {
130
- if (currentView === 'reader') {
131
- setCurrentView('chapters');
132
- } else if (currentView === 'chapters') {
133
- setCurrentView('topics');
33
+ if (onBack) {
34
+ onBack();
134
35
  } else {
135
- if (onBack) {
136
- onBack();
137
- } else {
138
- callbacks.onBackToDashboard?.();
139
- }
36
+ callbacks.onBackToDashboard?.();
140
37
  }
141
38
  };
142
39
 
143
- const handleSelectTopic = (topic: typeof MOCK_PEARLS_TOPICS[0]) => {
144
- setSelectedTopic(topic);
145
-
146
- // Flatten chapters for reader mode navigation
147
- const flat: PearlChapter[] = [];
148
- Object.keys(topic.sections || {}).forEach((sectionName) => {
149
- const sectionChapters = topic.sections[sectionName] || [];
150
- flat.push(...sectionChapters);
151
- });
152
- setFlattenedChapters(flat);
153
-
154
- setCurrentView('chapters');
155
- };
156
-
157
- const handleSelectChapter = (chapter: PearlChapter) => {
158
- if (chapter.isLocked) return;
159
-
160
- const index = flattenedChapters.findIndex((c) => c.id === chapter.id);
161
- if (index !== -1) {
162
- setActiveChapterIndex(index);
163
- setIsCompleted(false);
164
- setCurrentView('reader');
165
- }
166
- };
40
+ return (
41
+ <SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
42
+ <StatusBar barStyle="dark-content" />
167
43
 
168
- const handlePrevChapter = () => {
169
- if (activeChapterIndex > 0) {
170
- setActiveChapterIndex(activeChapterIndex - 1);
171
- setIsCompleted(false);
172
- }
173
- };
44
+ {/* Header */}
45
+ {!hideHeader && (
46
+ <View style={styles.header}>
47
+ <TouchableOpacity onPress={handleBackPress} style={styles.backButton}>
48
+ <Icon name="arrow-left" size={20} color={theme.textPrimary} />
49
+ </TouchableOpacity>
174
50
 
175
- const handleNextChapter = () => {
176
- if (activeChapterIndex < flattenedChapters.length - 1) {
177
- setActiveChapterIndex(activeChapterIndex + 1);
178
- setIsCompleted(false);
179
- }
180
- };
51
+ <Typography variant="h2" bold style={styles.headerTitle}>
52
+ {title}
53
+ </Typography>
181
54
 
182
- // --- View Renderers ---
55
+ <TouchableOpacity style={styles.headerRightBtn}>
56
+ <Icon name="search" size={20} color={theme.textPrimary} />
57
+ </TouchableOpacity>
58
+ </View>
59
+ )}
183
60
 
184
- // 1. Topic index list view (Screenshot 1)
185
- const renderTopicsView = () => {
186
- return (
61
+ {/* Topics list view */}
187
62
  <ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
188
63
  <Typography variant="h2" bold color={theme.textPrimary} style={styles.sectionHeaderTitle}>
189
64
  All Topics
@@ -194,7 +69,7 @@ export const PearlsScreen: React.FC<PearlsScreenProps> = ({
194
69
  <TouchableOpacity
195
70
  key={topic.id}
196
71
  activeOpacity={0.8}
197
- onPress={() => handleSelectTopic(topic)}
72
+ onPress={() => onSelectTopic?.(topic)}
198
73
  >
199
74
  <Card bordered style={styles.topicCard}>
200
75
  <View style={styles.topicRow}>
@@ -212,267 +87,6 @@ export const PearlsScreen: React.FC<PearlsScreenProps> = ({
212
87
  ))}
213
88
  </View>
214
89
  </ScrollView>
215
- );
216
- };
217
-
218
- // 2. Chapters list grouped by sections (Screenshot 2)
219
- const renderChaptersView = () => {
220
- if (!selectedTopic) return null;
221
- const sections = Object.keys(selectedTopic.sections || {});
222
-
223
- return (
224
- <ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
225
- {sections.map((sectionName) => {
226
- const list = selectedTopic.sections[sectionName] || [];
227
- return (
228
- <View key={sectionName} style={styles.sectionBlock}>
229
- <Typography variant="h2" bold color={theme.textPrimary} style={styles.sectionHeading}>
230
- {sectionName}
231
- </Typography>
232
-
233
- <View style={styles.chaptersList}>
234
- {list.map((chapter) => (
235
- <TouchableOpacity
236
- key={chapter.id}
237
- activeOpacity={0.8}
238
- onPress={() => handleSelectChapter(chapter)}
239
- disabled={chapter.isLocked}
240
- >
241
- <Card bordered style={styles.chapterCard}>
242
- <View style={styles.chapterRow}>
243
- {/* Left sequential index */}
244
- <Typography variant="body" bold color={theme.textSecondary} style={styles.chapterNumber}>
245
- {chapter.number}
246
- </Typography>
247
-
248
- {/* Middle Text */}
249
- <Typography variant="body" color={theme.textPrimary} style={styles.chapterTitle}>
250
- {chapter.title}
251
- </Typography>
252
-
253
- {/* Right locks/free badges */}
254
- <View style={styles.chapterBadgeCol}>
255
- {chapter.isFree ? (
256
- <View style={[styles.freeBadge, { borderColor: theme.primary }]}>
257
- <Typography variant="caption" bold color={theme.primary} style={styles.freeText}>
258
- FREE
259
- </Typography>
260
- </View>
261
- ) : chapter.isLocked ? (
262
- <View style={styles.lockCircle}>
263
- <Icon name="lock" size={12} color={theme.textSecondary} />
264
- </View>
265
- ) : null}
266
- </View>
267
- </View>
268
- </Card>
269
- </TouchableOpacity>
270
- ))}
271
- </View>
272
- </View>
273
- );
274
- })}
275
- </ScrollView>
276
- );
277
- };
278
-
279
- // 3. Reader view for high-yield content points (Screenshot 4)
280
- const renderReaderView = () => {
281
- const activeChapter = flattenedChapters[activeChapterIndex];
282
- if (!activeChapter) return null;
283
-
284
- return (
285
- <View style={styles.readerContainer}>
286
- {/* Subheader progress banner */}
287
- <View style={styles.readerSubHeader}>
288
- <Typography variant="body" bold color={theme.textPrimary} style={styles.readerSubTitle}>
289
- {activeChapter.title.split('.')[0] || activeChapter.title}
290
- </Typography>
291
- <Typography variant="body" bold color={theme.textSecondary}>
292
- {activeChapterIndex + 1}/{flattenedChapters.length}
293
- </Typography>
294
- </View>
295
-
296
- <ScrollView contentContainerStyle={styles.readerScroll} showsVerticalScrollIndicator={false}>
297
- {activeChapter.bullets.map((bullet, idx) => {
298
- // Find bold title separator in bullet text if exists
299
- const parts = bullet.split(':');
300
- const boldPart = parts[0];
301
- const rest = parts.slice(1).join(':');
302
-
303
- return (
304
- <View key={idx} style={styles.bulletRow}>
305
- <Typography variant="body" color={theme.textPrimary} style={styles.bulletPointDot}>
306
-
307
- </Typography>
308
- <Typography variant="body" color={theme.textPrimary} style={styles.bulletText}>
309
- {rest ? (
310
- <>
311
- <Typography variant="body" bold>{boldPart}:</Typography>
312
- {rest}
313
- </>
314
- ) : (
315
- bullet
316
- )}
317
- </Typography>
318
- </View>
319
- );
320
- })}
321
- </ScrollView>
322
-
323
- {/* Checkbox status bar */}
324
- <View style={styles.checkboxBar}>
325
- <TouchableOpacity
326
- activeOpacity={0.8}
327
- onPress={() => setIsCompleted(!isCompleted)}
328
- style={styles.checkboxRow}
329
- >
330
- <View style={[
331
- styles.checkboxBox,
332
- { borderColor: theme.border },
333
- isCompleted && { backgroundColor: theme.primary, borderColor: theme.primary }
334
- ]}>
335
- {isCompleted && <View style={styles.checkboxInner} />}
336
- </View>
337
- <Typography variant="body" bold color={theme.textPrimary}>
338
- Mark as Complete
339
- </Typography>
340
- </TouchableOpacity>
341
- </View>
342
-
343
- {/* Navigation bottom buttons */}
344
- <View style={styles.footerRow}>
345
- <TouchableOpacity
346
- onPress={handlePrevChapter}
347
- disabled={activeChapterIndex === 0}
348
- style={[styles.footerBtn, activeChapterIndex === 0 && { opacity: 0.4 }]}
349
- >
350
- <Typography variant="body" bold color={theme.textPrimary}>
351
- Prev
352
- </Typography>
353
- </TouchableOpacity>
354
-
355
- <TouchableOpacity
356
- onPress={handleNextChapter}
357
- disabled={activeChapterIndex === flattenedChapters.length - 1}
358
- style={[
359
- styles.nextActionBtn,
360
- { backgroundColor: theme.primary },
361
- activeChapterIndex === flattenedChapters.length - 1 && { opacity: 0.4 }
362
- ]}
363
- >
364
- <Typography variant="body" bold color="#FFFFFF">
365
- Next
366
- </Typography>
367
- </TouchableOpacity>
368
- </View>
369
- </View>
370
- );
371
- };
372
-
373
- // --- Render bottom sheet overlay for topics filter (Screenshot 3) ---
374
- const renderBottomSheet = () => {
375
- const list = [
376
- { name: 'Vertebral Curves', count: 25 },
377
- { name: 'Introduction', count: 15 },
378
- { name: 'Definition and scope', count: 15 },
379
- { name: 'Branches of anatomy', count: 5 },
380
- { name: 'Anatomical terminology', count: 23 },
381
- { name: 'Anatomical positions', count: 25 },
382
- { name: 'CSF', count: 15 },
383
- { name: 'Levels of structural organization', count: 15 },
384
- { name: 'Systems of the human body overview', count: 5 },
385
- { name: 'Tissue types', count: 23 },
386
- ];
387
-
388
- return (
389
- <Modal
390
- visible={bottomSheetVisible}
391
- transparent
392
- animationType="slide"
393
- onRequestClose={() => setBottomSheetVisible(false)}
394
- >
395
- <View style={styles.sheetOverlay}>
396
- {/* Backdrop click closer */}
397
- <TouchableOpacity
398
- activeOpacity={1}
399
- style={styles.sheetBackdrop}
400
- onPress={() => setBottomSheetVisible(false)}
401
- />
402
-
403
- <View style={styles.sheetContent}>
404
- {/* Grabber indicator bar */}
405
- <View style={styles.sheetGrabber} />
406
-
407
- <View style={styles.sheetHeader}>
408
- <Typography variant="h2" bold color={theme.textPrimary}>
409
- Anatomy
410
- </Typography>
411
- </View>
412
-
413
- <ScrollView contentContainerStyle={styles.sheetScroll}>
414
- {list.map((item, idx) => (
415
- <TouchableOpacity
416
- key={idx}
417
- style={styles.sheetItemRow}
418
- onPress={() => {
419
- setBottomSheetVisible(false);
420
- // Filter or change chapters list
421
- }}
422
- >
423
- <Typography variant="body" color={theme.textPrimary}>
424
- {item.name}
425
- </Typography>
426
- <Typography variant="caption" color={theme.textSecondary}>
427
- {item.count} Modules
428
- </Typography>
429
- </TouchableOpacity>
430
- ))}
431
- </ScrollView>
432
- </View>
433
- </View>
434
- </Modal>
435
- );
436
- };
437
-
438
- return (
439
- <SafeAreaView style={[styles.safeArea, { backgroundColor: theme.background }]}>
440
- <StatusBar barStyle="dark-content" />
441
-
442
- {/* Header */}
443
- {!hideHeader && (
444
- <View style={styles.header}>
445
- <TouchableOpacity onPress={handleBackPress} style={styles.backButton}>
446
- <Icon name="arrow-left" size={20} color={theme.textPrimary} />
447
- </TouchableOpacity>
448
-
449
- <Typography variant="h2" bold style={styles.headerTitle}>
450
- Pearls
451
- </Typography>
452
-
453
- {currentView === 'chapters' ? (
454
- <TouchableOpacity onPress={() => setBottomSheetVisible(true)} style={styles.headerRightBtn}>
455
- <Icon name="list" size={20} color={theme.textPrimary} />
456
- </TouchableOpacity>
457
- ) : currentView === 'topics' ? (
458
- <TouchableOpacity style={styles.headerRightBtn}>
459
- <Icon name="search" size={20} color={theme.textPrimary} />
460
- </TouchableOpacity>
461
- ) : (
462
- <View style={styles.headerRightPlaceholder} />
463
- )}
464
- </View>
465
- )}
466
-
467
- {/* Render Active Sub-View */}
468
- <View style={styles.mainViewContainer}>
469
- {currentView === 'topics' && renderTopicsView()}
470
- {currentView === 'chapters' && renderChaptersView()}
471
- {currentView === 'reader' && renderReaderView()}
472
- </View>
473
-
474
- {/* Slide-Up filter bottom sheet overlay */}
475
- {renderBottomSheet()}
476
90
  </SafeAreaView>
477
91
  );
478
92
  };
@@ -498,12 +112,6 @@ const styles = StyleSheet.create({
498
112
  headerRightBtn: {
499
113
  padding: 6,
500
114
  },
501
- headerRightPlaceholder: {
502
- width: 32,
503
- },
504
- mainViewContainer: {
505
- flex: 1,
506
- },
507
115
  scrollContent: {
508
116
  paddingHorizontal: 16,
509
117
  paddingTop: 8,
@@ -536,185 +144,4 @@ const styles = StyleSheet.create({
536
144
  topicLabelText: {
537
145
  fontSize: 14,
538
146
  },
539
- // --- Chapters list design styles ---
540
- sectionBlock: {
541
- marginBottom: 20,
542
- },
543
- sectionHeading: {
544
- fontSize: 16,
545
- marginBottom: 12,
546
- },
547
- chaptersList: {
548
- marginTop: 2,
549
- },
550
- chapterCard: {
551
- padding: 12,
552
- marginBottom: 10,
553
- borderRadius: 12,
554
- },
555
- chapterRow: {
556
- flexDirection: 'row',
557
- alignItems: 'center',
558
- },
559
- chapterNumber: {
560
- fontSize: 14,
561
- width: 24,
562
- textAlign: 'center',
563
- marginRight: 8,
564
- },
565
- chapterTitle: {
566
- flex: 1,
567
- fontSize: 14,
568
- lineHeight: 18,
569
- },
570
- chapterBadgeCol: {
571
- justifyContent: 'center',
572
- alignItems: 'flex-end',
573
- marginLeft: 8,
574
- },
575
- freeBadge: {
576
- borderWidth: 1.5,
577
- borderRadius: 6,
578
- paddingHorizontal: 8,
579
- paddingVertical: 3,
580
- },
581
- freeText: {
582
- fontSize: 9,
583
- },
584
- lockCircle: {
585
- width: 20,
586
- height: 20,
587
- borderRadius: 10,
588
- backgroundColor: '#F1F5F9',
589
- justifyContent: 'center',
590
- alignItems: 'center',
591
- },
592
- // --- Reader view design styles ---
593
- readerContainer: {
594
- flex: 1,
595
- },
596
- readerSubHeader: {
597
- flexDirection: 'row',
598
- justifyContent: 'space-between',
599
- alignItems: 'center',
600
- paddingHorizontal: 16,
601
- paddingVertical: 12,
602
- borderBottomWidth: 1,
603
- borderBottomColor: '#E2E8F0',
604
- },
605
- readerSubTitle: {
606
- flex: 1,
607
- fontSize: 14,
608
- marginRight: 16,
609
- },
610
- readerScroll: {
611
- paddingHorizontal: 16,
612
- paddingVertical: 16,
613
- },
614
- bulletRow: {
615
- flexDirection: 'row',
616
- alignItems: 'flex-start',
617
- marginBottom: 16,
618
- },
619
- bulletPointDot: {
620
- fontSize: 18,
621
- marginRight: 10,
622
- lineHeight: 20,
623
- },
624
- bulletText: {
625
- flex: 1,
626
- fontSize: 14,
627
- lineHeight: 22,
628
- },
629
- checkboxBar: {
630
- paddingHorizontal: 16,
631
- paddingVertical: 14,
632
- borderTopWidth: 1,
633
- borderTopColor: '#E2E8F0',
634
- backgroundColor: '#F8FAFC',
635
- },
636
- checkboxRow: {
637
- flexDirection: 'row',
638
- alignItems: 'center',
639
- },
640
- checkboxBox: {
641
- width: 20,
642
- height: 20,
643
- borderWidth: 2,
644
- borderRadius: 4,
645
- justifyContent: 'center',
646
- alignItems: 'center',
647
- marginRight: 10,
648
- },
649
- checkboxInner: {
650
- width: 10,
651
- height: 10,
652
- borderRadius: 2,
653
- backgroundColor: '#FFFFFF',
654
- },
655
- footerRow: {
656
- flexDirection: 'row',
657
- alignItems: 'center',
658
- paddingHorizontal: 16,
659
- paddingVertical: 12,
660
- backgroundColor: '#FFFFFF',
661
- borderTopWidth: 1,
662
- borderTopColor: '#E2E8F0',
663
- justifyContent: 'space-between',
664
- },
665
- footerBtn: {
666
- paddingVertical: 8,
667
- paddingHorizontal: 12,
668
- },
669
- nextActionBtn: {
670
- paddingHorizontal: 24,
671
- paddingVertical: 10,
672
- borderRadius: 8,
673
- minWidth: 80,
674
- justifyContent: 'center',
675
- alignItems: 'center',
676
- },
677
- // --- Slide-up Sheet styling details ---
678
- sheetOverlay: {
679
- flex: 1,
680
- backgroundColor: 'rgba(0, 0, 0, 0.4)',
681
- justifyContent: 'flex-end',
682
- },
683
- sheetBackdrop: {
684
- ...StyleSheet.absoluteFillObject,
685
- },
686
- sheetContent: {
687
- backgroundColor: '#FFFFFF',
688
- borderTopLeftRadius: 20,
689
- borderTopRightRadius: 20,
690
- maxHeight: SCREEN_HEIGHT * 0.7,
691
- paddingBottom: 20,
692
- },
693
- sheetGrabber: {
694
- width: 40,
695
- height: 4,
696
- backgroundColor: '#E2E8F0',
697
- borderRadius: 2,
698
- alignSelf: 'center',
699
- marginTop: 8,
700
- marginBottom: 16,
701
- },
702
- sheetHeader: {
703
- paddingHorizontal: 20,
704
- paddingBottom: 12,
705
- borderBottomWidth: 1,
706
- borderBottomColor: '#F1F5F9',
707
- },
708
- sheetScroll: {
709
- paddingHorizontal: 20,
710
- paddingVertical: 8,
711
- },
712
- sheetItemRow: {
713
- flexDirection: 'row',
714
- justifyContent: 'space-between',
715
- alignItems: 'center',
716
- paddingVertical: 14,
717
- borderBottomWidth: 1,
718
- borderBottomColor: '#F8FAFC',
719
- },
720
147
  });
@@ -4,10 +4,10 @@ import {
4
4
  ScrollView,
5
5
  StyleSheet,
6
6
  TouchableOpacity,
7
- SafeAreaView,
8
7
  StatusBar,
9
8
  Image,
10
9
  } from 'react-native';
10
+ import { SafeAreaView } from 'react-native-safe-area-context';
11
11
  import { useElearnConfig } from '../context/ElearnConfigContext';
12
12
  import { useTheme } from '../context/ThemeContext';
13
13
  import { Typography, Card, ProgressBar, Icon } from '../components';