@studyjoyful/shared 1.0.9 → 1.0.12

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": "@studyjoyful/shared",
3
- "version": "1.0.9",
3
+ "version": "1.0.12",
4
4
  "description": "Shared code for StudyJoyful Web and App (i18n, constants, types, utils)",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -117,7 +117,8 @@
117
117
  },
118
118
  "header": {
119
119
  "newTask": "StudyJoyful",
120
- "creating": "Creating Task"
120
+ "creating": "Creating Task",
121
+ "chat": "Chat with AI"
121
122
  },
122
123
  "time": {
123
124
  "justNow": "Just now",
@@ -0,0 +1,148 @@
1
+ {
2
+ "scan": {
3
+ "title": "Scan Homework",
4
+ "subtitle": "Take a photo and generate practice instantly",
5
+ "cta": "Scan Now"
6
+ },
7
+ "quickStart": {
8
+ "title": "Quick Start",
9
+ "math": {
10
+ "title": "Math Practice",
11
+ "subtitle": "{{grade}} Topics",
12
+ "subtitleNoGrade": "Select topics"
13
+ },
14
+ "english": {
15
+ "title": "English Practice",
16
+ "subtitle": "{{grade}} Topics",
17
+ "subtitleNoGrade": "Select topics"
18
+ }
19
+ },
20
+ "chat": {
21
+ "sectionTitle": "Or describe what you need",
22
+ "title": "Chat with AI",
23
+ "placeholder": "\"Create practice for 2-digit subtraction\""
24
+ },
25
+ "recentTasks": {
26
+ "title": "Recent Tasks",
27
+ "viewAll": "View All",
28
+ "questions": "questions",
29
+ "empty": "No tasks yet",
30
+ "notStarted": "Not started"
31
+ },
32
+ "time": {
33
+ "justNow": "Just now",
34
+ "minutesAgo": "{{count}} min ago",
35
+ "hoursAgo": "{{count}}h ago",
36
+ "daysAgo": "{{count}}d ago"
37
+ },
38
+ "topics": {
39
+ "title": "Select Topic",
40
+ "popular": "Popular",
41
+ "all": "All Topics",
42
+ "math": {
43
+ "addition": {
44
+ "label": "Addition",
45
+ "description": "With & without carrying"
46
+ },
47
+ "subtraction": {
48
+ "label": "Subtraction",
49
+ "description": "With & without borrowing"
50
+ },
51
+ "multiplication": {
52
+ "label": "Multiplication",
53
+ "description": "Times tables & word problems"
54
+ },
55
+ "division": {
56
+ "label": "Division",
57
+ "description": "Basic division concepts"
58
+ },
59
+ "fractions": {
60
+ "label": "Fractions",
61
+ "description": "Halves, quarters, thirds"
62
+ },
63
+ "shapes": {
64
+ "label": "Shapes",
65
+ "description": "2D and 3D shapes"
66
+ },
67
+ "time": {
68
+ "label": "Time",
69
+ "description": "Telling time, duration"
70
+ },
71
+ "money": {
72
+ "label": "Money",
73
+ "description": "Counting, adding money"
74
+ },
75
+ "measurement": {
76
+ "label": "Measurement",
77
+ "description": "Length, mass, volume"
78
+ },
79
+ "wordProblems": {
80
+ "label": "Word Problems",
81
+ "description": "Mixed operations"
82
+ }
83
+ },
84
+ "english": {
85
+ "spelling": {
86
+ "label": "Spelling",
87
+ "description": "Common words & patterns"
88
+ },
89
+ "vocabulary": {
90
+ "label": "Vocabulary",
91
+ "description": "Word meanings & usage"
92
+ },
93
+ "grammar": {
94
+ "label": "Grammar",
95
+ "description": "Sentence structure"
96
+ },
97
+ "reading": {
98
+ "label": "Reading",
99
+ "description": "Comprehension practice"
100
+ },
101
+ "phonics": {
102
+ "label": "Phonics",
103
+ "description": "Sound-letter relationships"
104
+ },
105
+ "punctuation": {
106
+ "label": "Punctuation",
107
+ "description": "Periods, commas, capitals"
108
+ }
109
+ }
110
+ },
111
+ "confirm": {
112
+ "title": "Confirm Practice",
113
+ "settings": "Settings",
114
+ "questions": "Questions",
115
+ "difficulty": "Difficulty",
116
+ "easier": "Easier",
117
+ "balanced": "Balanced",
118
+ "harder": "Harder",
119
+ "generate": "Generate Practice",
120
+ "customizeWithAI": "Customize with AI"
121
+ },
122
+ "scanPage": {
123
+ "title": "Scan Homework",
124
+ "tips": "Tips",
125
+ "tip1": "Make sure text is clear and in focus",
126
+ "tip2": "Good lighting helps accuracy",
127
+ "tip3": "Include the full question",
128
+ "takePhoto": "Take Photo",
129
+ "choosePhoto": "Choose from Gallery",
130
+ "analyzing": "Analyzing...",
131
+ "detected": "Detected",
132
+ "inScope": "Ready to practice",
133
+ "outOfScope": "Out of scope",
134
+ "confidence": {
135
+ "high": "High confidence",
136
+ "medium": "Please verify",
137
+ "low": "Needs clarification"
138
+ },
139
+ "notRecognized": "Could not recognize learning content",
140
+ "tryAgain": "Try Again",
141
+ "switchToChat": "Describe Instead",
142
+ "advancedSettings": "Advanced Settings",
143
+ "generatePractice": "Generate Practice",
144
+ "browseTopics": "Browse Topics",
145
+ "tryInstead": "Try these topics instead:"
146
+ }
147
+ }
148
+
@@ -5,6 +5,7 @@
5
5
  import common from './common.json';
6
6
  import auth from './auth.json';
7
7
  import chat from './chat.json';
8
+ import home from './home.json';
8
9
  import tasks from './tasks.json';
9
10
  import learning from './learning.json';
10
11
  import profile from './profile.json';
@@ -15,6 +16,7 @@ export const en = {
15
16
  common,
16
17
  auth,
17
18
  chat,
19
+ home,
18
20
  tasks,
19
21
  learning,
20
22
  profile,
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "menu": {
3
3
  "home": "StudyJoyful",
4
+ "scan": "Scan Homework",
5
+ "chat": "AI Chat",
4
6
  "tasks": "My Tasks",
5
7
  "admin": "Admin",
6
8
  "settings": "Settings"
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  * - i18n: Internationalization (translations, resources)
8
8
  * - constants: Shared constants (examples, etc.)
9
9
  * - types: Common type definitions
10
+ * - topics: Topic definitions with AI context
10
11
  * - utils: Utility functions
11
12
  */
12
13
 
@@ -41,5 +42,29 @@ export {
41
42
  type PaginationMeta,
42
43
  } from './types';
43
44
 
45
+ // Topics exports
46
+ export {
47
+ // Types
48
+ type TopicDefinition,
49
+ type TopicCategory,
50
+ type TopicIconName,
51
+ // Constants
52
+ ALL_TOPICS,
53
+ MATH_TOPICS,
54
+ ENGLISH_TOPICS,
55
+ ICON_MAP,
56
+ // Functions
57
+ getAllTopics,
58
+ getTopicById,
59
+ getTopicsBySubject,
60
+ getTopicsBySubjectAndGrade,
61
+ getPopularTopicsBySubject,
62
+ getPopularTopicsBySubjectAndGrade,
63
+ getTopicAIContext,
64
+ findTopicsByKeyword,
65
+ getSuggestedAlternatives,
66
+ getIconForPlatform,
67
+ } from './topics';
68
+
44
69
  // Utils exports
45
70
  export { randomSelect, shuffle } from './utils';
@@ -0,0 +1,120 @@
1
+ /**
2
+ * English Topics
3
+ *
4
+ * English topics for P1-P3 based on Singapore MOE syllabus.
5
+ * aiContext provides concise topic description for AI generation.
6
+ * Grade-specific adaptation is handled by the API prompt.
7
+ */
8
+
9
+ import type { TopicDefinition } from './types';
10
+
11
+ /**
12
+ * All English topics
13
+ */
14
+ export const ENGLISH_TOPICS: TopicDefinition[] = [
15
+ // ============================================
16
+ // Phonics & Sounds
17
+ // ============================================
18
+ {
19
+ id: 'english-phonics',
20
+ subject: 'English',
21
+ label: 'Phonics',
22
+ description: 'Letter sounds & blending',
23
+ aiContext: `Phonics practice focusing on letter-sound relationships, blending sounds to read words, and segmenting words for spelling.
24
+ Question types: Match sounds to letters, blend sounds to read words, identify vowel sounds, rhyming words.`,
25
+ keywords: ['phonics', 'sounds', 'letters', 'blend', 'vowels', 'consonants', 'CVC', 'rhyme'],
26
+ gradeRange: ['P1', 'P2', 'P3'],
27
+ category: 'phonics',
28
+ iconName: 'music',
29
+ },
30
+
31
+ // ============================================
32
+ // Vocabulary
33
+ // ============================================
34
+ {
35
+ id: 'english-spelling',
36
+ subject: 'English',
37
+ label: 'Spelling',
38
+ description: 'Common words & patterns',
39
+ aiContext: `Spelling practice focusing on sight words, spelling patterns, and word families.
40
+ Question types: Complete the spelling, correct misspelled words, fill in missing letters, word family exercises.`,
41
+ keywords: ['spelling', 'spell', 'words', 'sight words', 'patterns', 'letters'],
42
+ gradeRange: ['P1', 'P2', 'P3'],
43
+ category: 'vocabulary',
44
+ isPopular: true,
45
+ iconName: 'text',
46
+ },
47
+ {
48
+ id: 'english-vocabulary',
49
+ subject: 'English',
50
+ label: 'Vocabulary',
51
+ description: 'Word meanings & usage',
52
+ aiContext: `Vocabulary practice focusing on word meanings, usage in sentences, and categorizing words.
53
+ Question types: Match word to meaning, use word in sentence, find synonyms/antonyms, complete sentences with correct word.`,
54
+ keywords: ['vocabulary', 'words', 'meanings', 'synonyms', 'antonyms', 'definition'],
55
+ gradeRange: ['P1', 'P2', 'P3'],
56
+ category: 'vocabulary',
57
+ isPopular: true,
58
+ iconName: 'book',
59
+ },
60
+
61
+ // ============================================
62
+ // Grammar
63
+ // ============================================
64
+ {
65
+ id: 'english-grammar',
66
+ subject: 'English',
67
+ label: 'Grammar',
68
+ description: 'Sentence structure & rules',
69
+ aiContext: `Grammar practice focusing on parts of speech (nouns, verbs, adjectives), sentence structure, and correct usage.
70
+ Question types: Identify parts of speech, fill in correct word form, correct the sentence, complete sentences.`,
71
+ keywords: ['grammar', 'nouns', 'verbs', 'adjectives', 'sentences', 'tenses', 'pronouns'],
72
+ gradeRange: ['P1', 'P2', 'P3'],
73
+ category: 'grammar',
74
+ isPopular: true,
75
+ iconName: 'list',
76
+ },
77
+ {
78
+ id: 'english-punctuation',
79
+ subject: 'English',
80
+ label: 'Punctuation',
81
+ description: 'Periods, commas & capitals',
82
+ aiContext: `Punctuation practice focusing on end punctuation, capital letters, and basic comma usage.
83
+ Question types: Add correct punctuation, correct the punctuation, identify punctuation marks, rewrite with correct punctuation.`,
84
+ keywords: ['punctuation', 'period', 'comma', 'capital', 'question mark', 'apostrophe', 'exclamation'],
85
+ gradeRange: ['P1', 'P2', 'P3'],
86
+ category: 'punctuation',
87
+ iconName: 'code',
88
+ },
89
+
90
+ // ============================================
91
+ // Reading
92
+ // ============================================
93
+ {
94
+ id: 'english-reading',
95
+ subject: 'English',
96
+ label: 'Reading Comprehension',
97
+ description: 'Understanding texts',
98
+ aiContext: `Reading comprehension practice with age-appropriate passages about school, family, animals, and everyday life.
99
+ Question types: Multiple choice comprehension, true/false, short answer questions, sequencing events.
100
+ Focus: Understanding main idea, finding information, making connections.`,
101
+ keywords: ['reading', 'comprehension', 'passage', 'understand', 'main idea', 'inference'],
102
+ gradeRange: ['P1', 'P2', 'P3'],
103
+ category: 'reading',
104
+ iconName: 'book',
105
+ },
106
+ ];
107
+
108
+ /**
109
+ * Get English topics filtered by grade
110
+ */
111
+ export function getEnglishTopicsByGrade(grade: 'P1' | 'P2' | 'P3'): TopicDefinition[] {
112
+ return ENGLISH_TOPICS.filter((topic) => topic.gradeRange.includes(grade));
113
+ }
114
+
115
+ /**
116
+ * Get popular English topics
117
+ */
118
+ export function getPopularEnglishTopics(): TopicDefinition[] {
119
+ return ENGLISH_TOPICS.filter((topic) => topic.isPopular);
120
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Topics Module
3
+ *
4
+ * Unified topic definitions for StudyJoyful.
5
+ * Based on Singapore MOE (Ministry of Education) syllabus for P1-P3.
6
+ *
7
+ * Usage:
8
+ * ```ts
9
+ * import { getAllTopics, getTopicById, getTopicsBySubject } from '@studyjoyful/shared';
10
+ *
11
+ * // Get all topics
12
+ * const topics = getAllTopics();
13
+ *
14
+ * // Get topics by subject
15
+ * const mathTopics = getTopicsBySubject('Math');
16
+ *
17
+ * // Get topic by ID
18
+ * const addition = getTopicById('math-addition');
19
+ *
20
+ * // Get AI context for a topic
21
+ * const context = getTopicAIContext('math-addition');
22
+ * ```
23
+ */
24
+
25
+ import type { ChildGrade, Subject } from '../types/child';
26
+ import { ENGLISH_TOPICS, getEnglishTopicsByGrade, getPopularEnglishTopics } from './english-topics';
27
+ import { MATH_TOPICS, getMathTopicsByGrade, getPopularMathTopics } from './math-topics';
28
+ import type { TopicCategory, TopicDefinition, TopicIconName } from './types';
29
+ import { getIconForPlatform, ICON_MAP } from './types';
30
+
31
+ // Re-export types
32
+ export type { TopicCategory, TopicDefinition, TopicIconName };
33
+ export { ICON_MAP, getIconForPlatform };
34
+
35
+ // Re-export topic arrays
36
+ export { ENGLISH_TOPICS, MATH_TOPICS };
37
+
38
+ /**
39
+ * All topics combined
40
+ */
41
+ export const ALL_TOPICS: TopicDefinition[] = [...MATH_TOPICS, ...ENGLISH_TOPICS];
42
+
43
+ /**
44
+ * Get all topics
45
+ */
46
+ export function getAllTopics(): TopicDefinition[] {
47
+ return ALL_TOPICS;
48
+ }
49
+
50
+ /**
51
+ * Get topic by ID
52
+ */
53
+ export function getTopicById(id: string): TopicDefinition | undefined {
54
+ return ALL_TOPICS.find((topic) => topic.id === id);
55
+ }
56
+
57
+ /**
58
+ * Get topics by subject
59
+ */
60
+ export function getTopicsBySubject(subject: Subject): TopicDefinition[] {
61
+ return subject === 'Math' ? MATH_TOPICS : ENGLISH_TOPICS;
62
+ }
63
+
64
+ /**
65
+ * Get topics by subject and grade
66
+ */
67
+ export function getTopicsBySubjectAndGrade(subject: Subject, grade: ChildGrade): TopicDefinition[] {
68
+ return subject === 'Math' ? getMathTopicsByGrade(grade) : getEnglishTopicsByGrade(grade);
69
+ }
70
+
71
+ /**
72
+ * Get popular topics by subject
73
+ */
74
+ export function getPopularTopicsBySubject(subject: Subject): TopicDefinition[] {
75
+ return subject === 'Math' ? getPopularMathTopics() : getPopularEnglishTopics();
76
+ }
77
+
78
+ /**
79
+ * Get popular topics by subject and grade
80
+ */
81
+ export function getPopularTopicsBySubjectAndGrade(subject: Subject, grade: ChildGrade): TopicDefinition[] {
82
+ const topics = getTopicsBySubjectAndGrade(subject, grade);
83
+ return topics.filter((topic) => topic.isPopular);
84
+ }
85
+
86
+ /**
87
+ * Get AI context for a topic
88
+ *
89
+ * @param topicId - Topic ID or label
90
+ * @returns Formatted context string for AI (grade adaptation handled by API prompt)
91
+ */
92
+ export function getTopicAIContext(topicId: string): string {
93
+ // Try to find by ID first
94
+ let topic = getTopicById(topicId);
95
+
96
+ // If not found, try to match by label (case-insensitive)
97
+ if (!topic) {
98
+ const lowerTopicId = topicId.toLowerCase();
99
+ topic = ALL_TOPICS.find(
100
+ (t) =>
101
+ t.label.toLowerCase() === lowerTopicId ||
102
+ t.id.toLowerCase().includes(lowerTopicId) ||
103
+ t.keywords.some((k) => k.toLowerCase() === lowerTopicId)
104
+ );
105
+ }
106
+
107
+ if (!topic) {
108
+ return `Topic: ${topicId}`;
109
+ }
110
+
111
+ return `Topic: ${topic.label}
112
+ Subject: ${topic.subject}
113
+ ${topic.aiContext}`;
114
+ }
115
+
116
+ /**
117
+ * Find topics matching keywords
118
+ */
119
+ export function findTopicsByKeyword(keyword: string, subject?: Subject): TopicDefinition[] {
120
+ const lowerKeyword = keyword.toLowerCase();
121
+ const topics = subject ? getTopicsBySubject(subject) : ALL_TOPICS;
122
+
123
+ return topics.filter(
124
+ (topic) =>
125
+ topic.label.toLowerCase().includes(lowerKeyword) ||
126
+ topic.description.toLowerCase().includes(lowerKeyword) ||
127
+ topic.keywords.some((k) => k.toLowerCase().includes(lowerKeyword))
128
+ );
129
+ }
130
+
131
+ /**
132
+ * Get suggested topics for out-of-scope content
133
+ */
134
+ export function getSuggestedAlternatives(subject: Subject, grade: ChildGrade, count: number = 3): string[] {
135
+ const popularTopics = getPopularTopicsBySubjectAndGrade(subject, grade);
136
+ const topics = popularTopics.length > 0 ? popularTopics : getTopicsBySubjectAndGrade(subject, grade);
137
+ return topics.slice(0, count).map((t) => t.label);
138
+ }
139
+
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Math Topics
3
+ *
4
+ * Math topics for P1-P3 based on Singapore MOE syllabus.
5
+ * aiContext provides concise topic description for AI generation.
6
+ * Grade-specific adaptation is handled by the API prompt.
7
+ */
8
+
9
+ import type { TopicDefinition } from './types';
10
+
11
+ /**
12
+ * All Math topics
13
+ */
14
+ export const MATH_TOPICS: TopicDefinition[] = [
15
+ // ============================================
16
+ // Arithmetic
17
+ // ============================================
18
+ {
19
+ id: 'math-addition',
20
+ subject: 'Math',
21
+ label: 'Addition',
22
+ description: 'With & without carrying',
23
+ aiContext: `Addition practice focusing on number bonds, place value, and step-by-step regrouping (carrying).
24
+ Question types: Fill in blanks, find the sum, word problems with "altogether", "total", "in all".`,
25
+ keywords: ['add', 'plus', 'sum', 'total', 'altogether', 'carrying', 'regrouping', 'number bonds'],
26
+ gradeRange: ['P1', 'P2', 'P3'],
27
+ category: 'arithmetic',
28
+ isPopular: true,
29
+ iconName: 'add',
30
+ },
31
+ {
32
+ id: 'math-subtraction',
33
+ subject: 'Math',
34
+ label: 'Subtraction',
35
+ description: 'With & without borrowing',
36
+ aiContext: `Subtraction practice focusing on relationship with addition, place value, and step-by-step borrowing (regrouping).
37
+ Question types: Find the difference, how many more/fewer, word problems with "left", "remaining", "gave away".`,
38
+ keywords: ['subtract', 'minus', 'difference', 'left', 'remaining', 'borrowing', 'regrouping', 'take away'],
39
+ gradeRange: ['P1', 'P2', 'P3'],
40
+ category: 'arithmetic',
41
+ isPopular: true,
42
+ iconName: 'subtract',
43
+ },
44
+ {
45
+ id: 'math-multiplication',
46
+ subject: 'Math',
47
+ label: 'Multiplication',
48
+ description: 'Times tables & word problems',
49
+ aiContext: `Multiplication practice focusing on equal groups, arrays, times tables, and relationship with repeated addition.
50
+ Question types: Times tables practice, array problems, "groups of", word problems with equal sharing/grouping.`,
51
+ keywords: ['multiply', 'times', 'product', 'groups of', 'times tables', 'arrays', 'repeated addition'],
52
+ gradeRange: ['P2', 'P3'],
53
+ category: 'arithmetic',
54
+ isPopular: true,
55
+ iconName: 'multiply',
56
+ },
57
+ {
58
+ id: 'math-division',
59
+ subject: 'Math',
60
+ label: 'Division',
61
+ description: 'Equal sharing & grouping',
62
+ aiContext: `Division practice focusing on equal sharing, grouping, and inverse relationship with multiplication.
63
+ Question types: Share equally, how many groups, word problems with "each", "equally divided".`,
64
+ keywords: ['divide', 'share', 'equally', 'groups', 'quotient', 'remainder', 'each'],
65
+ gradeRange: ['P2', 'P3'],
66
+ category: 'arithmetic',
67
+ iconName: 'divide',
68
+ },
69
+
70
+ // ============================================
71
+ // Fractions
72
+ // ============================================
73
+ {
74
+ id: 'math-fractions',
75
+ subject: 'Math',
76
+ label: 'Fractions',
77
+ description: 'Halves, quarters, thirds',
78
+ aiContext: `Fractions practice focusing on equal parts, visual models (circles, rectangles), and relating to everyday objects.
79
+ Question types: Shade fractions, identify fractions, compare fractions, word problems with sharing.`,
80
+ keywords: ['fraction', 'half', 'quarter', 'third', 'parts', 'whole', 'numerator', 'denominator'],
81
+ gradeRange: ['P2', 'P3'],
82
+ category: 'fractions',
83
+ iconName: 'fraction',
84
+ },
85
+
86
+ // ============================================
87
+ // Geometry
88
+ // ============================================
89
+ {
90
+ id: 'math-shapes',
91
+ subject: 'Math',
92
+ label: 'Shapes',
93
+ description: '2D and 3D shapes',
94
+ aiContext: `Shapes practice focusing on 2D shapes (circle, triangle, square, rectangle) and 3D shapes (cube, cuboid, cone, cylinder).
95
+ Question types: Identify shapes, count sides/corners, match shapes to objects, spot shapes in pictures.`,
96
+ keywords: ['shapes', 'circle', 'triangle', 'square', 'rectangle', 'sides', 'corners', '3D', 'cube'],
97
+ gradeRange: ['P1', 'P2', 'P3'],
98
+ category: 'geometry',
99
+ iconName: 'shapes',
100
+ },
101
+
102
+ // ============================================
103
+ // Measurement
104
+ // ============================================
105
+ {
106
+ id: 'math-time',
107
+ subject: 'Math',
108
+ label: 'Time',
109
+ description: 'Telling time & duration',
110
+ aiContext: `Time practice focusing on analog clock reading, digital time, duration, and connecting to daily routines.
111
+ Question types: What time is it?, Draw hands on clock, calculate duration, sequence events.`,
112
+ keywords: ['time', 'clock', "o'clock", 'half past', 'quarter', 'minutes', 'hours', 'duration'],
113
+ gradeRange: ['P1', 'P2', 'P3'],
114
+ category: 'measurement',
115
+ iconName: 'time',
116
+ },
117
+ {
118
+ id: 'math-money',
119
+ subject: 'Math',
120
+ label: 'Money',
121
+ description: 'Counting & calculating',
122
+ aiContext: `Money practice using Singapore currency (dollars and cents), focusing on counting, adding, and making change.
123
+ Question types: Count the money, find total cost, calculate change, shopping word problems.`,
124
+ keywords: ['money', 'cents', 'dollars', 'coins', 'change', 'cost', 'price', 'buy', 'pay'],
125
+ gradeRange: ['P1', 'P2', 'P3'],
126
+ category: 'measurement',
127
+ iconName: 'money',
128
+ },
129
+ {
130
+ id: 'math-measurement',
131
+ subject: 'Math',
132
+ label: 'Measurement',
133
+ description: 'Length, mass, volume',
134
+ aiContext: `Measurement practice focusing on length (cm, m), mass (g, kg), volume (ml, L), estimation, and appropriate units.
135
+ Question types: Compare lengths, measure and record, convert units, word problems with measurement.`,
136
+ keywords: ['length', 'mass', 'volume', 'centimeter', 'meter', 'kilogram', 'gram', 'liter', 'measure'],
137
+ gradeRange: ['P1', 'P2', 'P3'],
138
+ category: 'measurement',
139
+ iconName: 'ruler',
140
+ },
141
+
142
+ // ============================================
143
+ // Problem Solving
144
+ // ============================================
145
+ {
146
+ id: 'math-word-problems',
147
+ subject: 'Math',
148
+ label: 'Word Problems',
149
+ description: 'Mixed operations & reasoning',
150
+ aiContext: `Word problems practice using Singapore Math bar model / model drawing method for visualization.
151
+ Question types: One-step, two-step, comparison ("more than", "fewer than"), part-whole problems.
152
+ Focus: Understanding the question, identifying operation, showing working, checking answer.`,
153
+ keywords: ['word problem', 'story problem', 'solve', 'altogether', 'remaining', 'how many', 'model drawing'],
154
+ gradeRange: ['P1', 'P2', 'P3'],
155
+ category: 'problem-solving',
156
+ iconName: 'document',
157
+ },
158
+ ];
159
+
160
+ /**
161
+ * Get Math topics filtered by grade
162
+ */
163
+ export function getMathTopicsByGrade(grade: 'P1' | 'P2' | 'P3'): TopicDefinition[] {
164
+ return MATH_TOPICS.filter((topic) => topic.gradeRange.includes(grade));
165
+ }
166
+
167
+ /**
168
+ * Get popular Math topics
169
+ */
170
+ export function getPopularMathTopics(): TopicDefinition[] {
171
+ return MATH_TOPICS.filter((topic) => topic.isPopular);
172
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Topics Types
3
+ *
4
+ * Type definitions for topic data used across Web and App.
5
+ * Topics are based on Singapore MOE (Ministry of Education) syllabus.
6
+ */
7
+
8
+ import type { ChildGrade, Subject } from '../types/child';
9
+
10
+ /**
11
+ * Topic definition with rich context for AI
12
+ */
13
+ export interface TopicDefinition {
14
+ /** Unique identifier: 'math-addition', 'english-spelling' */
15
+ id: string;
16
+
17
+ /** Subject: Math or English */
18
+ subject: Subject;
19
+
20
+ /** Display label: 'Addition' */
21
+ label: string;
22
+
23
+ /** Short description for UI: 'With & without carrying' */
24
+ description: string;
25
+
26
+ /**
27
+ * Rich context for AI generation
28
+ * Should include:
29
+ * - What the topic covers
30
+ * - Grade-specific variations
31
+ * - Common question types
32
+ */
33
+ aiContext: string;
34
+
35
+ /** Related keywords for matching */
36
+ keywords: string[];
37
+
38
+ /** Applicable grades */
39
+ gradeRange: ChildGrade[];
40
+
41
+ /** Topic category for grouping */
42
+ category: TopicCategory;
43
+
44
+ /** Whether this is a popular/recommended topic */
45
+ isPopular?: boolean;
46
+
47
+ /** Icon name (platform-agnostic) */
48
+ iconName: TopicIconName;
49
+ }
50
+
51
+ /**
52
+ * Topic categories
53
+ */
54
+ export type TopicCategory =
55
+ // Math categories
56
+ | 'arithmetic' // +, -, ×, ÷
57
+ | 'numbers' // Number sense, place value
58
+ | 'fractions' // Fractions, decimals
59
+ | 'geometry' // Shapes, angles
60
+ | 'measurement' // Length, mass, volume, time
61
+ | 'data' // Graphs, charts
62
+ | 'problem-solving' // Word problems
63
+ // English categories
64
+ | 'phonics' // Letter sounds, blending
65
+ | 'vocabulary' // Words, meanings
66
+ | 'grammar' // Parts of speech, sentences
67
+ | 'reading' // Comprehension
68
+ | 'writing' // Composition, sentences
69
+ | 'punctuation'; // Punctuation marks
70
+
71
+ /**
72
+ * Platform-agnostic icon names
73
+ * Maps to:
74
+ * - Ionicons (App): add-outline, remove-outline, etc.
75
+ * - Lucide (Web): Plus, Minus, etc.
76
+ */
77
+ export type TopicIconName =
78
+ | 'add'
79
+ | 'subtract'
80
+ | 'multiply'
81
+ | 'divide'
82
+ | 'fraction'
83
+ | 'shapes'
84
+ | 'time'
85
+ | 'money'
86
+ | 'ruler'
87
+ | 'document'
88
+ | 'text'
89
+ | 'book'
90
+ | 'list'
91
+ | 'music'
92
+ | 'code';
93
+
94
+ /**
95
+ * Icon mappings for different platforms
96
+ */
97
+ export const ICON_MAP = {
98
+ ionicons: {
99
+ add: 'add-outline',
100
+ subtract: 'remove-outline',
101
+ multiply: 'close-outline',
102
+ divide: 'git-compare-outline',
103
+ fraction: 'pie-chart-outline',
104
+ shapes: 'shapes-outline',
105
+ time: 'time-outline',
106
+ money: 'cash-outline',
107
+ ruler: 'resize-outline',
108
+ document: 'document-text-outline',
109
+ text: 'text-outline',
110
+ book: 'book-outline',
111
+ list: 'list-outline',
112
+ music: 'musical-notes-outline',
113
+ code: 'code-outline',
114
+ },
115
+ lucide: {
116
+ add: 'Plus',
117
+ subtract: 'Minus',
118
+ multiply: 'X',
119
+ divide: 'Divide',
120
+ fraction: 'PieChart',
121
+ shapes: 'Shapes',
122
+ time: 'Clock',
123
+ money: 'Coins',
124
+ ruler: 'Ruler',
125
+ document: 'FileText',
126
+ text: 'Type',
127
+ book: 'BookOpen',
128
+ list: 'List',
129
+ music: 'Music',
130
+ code: 'Code',
131
+ },
132
+ } as const;
133
+
134
+ /**
135
+ * Get icon name for a specific platform
136
+ */
137
+ export function getIconForPlatform(
138
+ iconName: TopicIconName,
139
+ platform: 'ionicons' | 'lucide'
140
+ ): string {
141
+ return ICON_MAP[platform][iconName];
142
+ }
143
+