@academy-sdk/sdk 0.2.1 → 0.2.3

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/dist/styles.css CHANGED
@@ -1364,8 +1364,8 @@
1364
1364
  .bg-center {
1365
1365
  background-position: center;
1366
1366
  }
1367
- .fill-gray-300 {
1368
- fill: var(--color-gray-300);
1367
+ .fill-theme-border-primary {
1368
+ fill: var(--color-theme-border-primary);
1369
1369
  }
1370
1370
  .fill-yellow-400 {
1371
1371
  fill: var(--color-yellow-400);
@@ -1704,6 +1704,9 @@
1704
1704
  .text-theme-accent-primary {
1705
1705
  color: var(--color-theme-accent-primary);
1706
1706
  }
1707
+ .text-theme-border-primary {
1708
+ color: var(--color-theme-border-primary);
1709
+ }
1707
1710
  .text-theme-text-muted {
1708
1711
  color: var(--color-theme-text-muted);
1709
1712
  }
@@ -2091,13 +2094,6 @@
2091
2094
  }
2092
2095
  }
2093
2096
  }
2094
- .hover\:bg-gray-100 {
2095
- &:hover {
2096
- @media (hover: hover) {
2097
- background-color: var(--color-gray-100);
2098
- }
2099
- }
2100
- }
2101
2097
  .hover\:bg-green-600 {
2102
2098
  &:hover {
2103
2099
  @media (hover: hover) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@academy-sdk/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "SDK for building custom learner templates for the Academy platform",
5
5
  "files": [
6
6
  "dist",
@@ -203,7 +203,7 @@ export function CourseCard({
203
203
  {!isFree && originalPrice && originalPrice > price && (
204
204
  <span className="text-sm text-gray-400 line-through">${originalPrice}</span>
205
205
  )}
206
- <span className="text-lg font-bold text-[rgb(var(--accent-primary))]">
206
+ <span className="text-xl font-bold text-[rgb(var(--accent-primary))]">
207
207
  {isFree ? 'Free' : `$${price}`}
208
208
  </span>
209
209
  </div>
@@ -102,7 +102,7 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
102
102
  };
103
103
 
104
104
  const renderEnrollmentCard = () => (
105
- <div className="bg-white p-4 rounded-xl shadow-lg border border-gray-100">
105
+ <div className="bg-theme-bg-secondary p-4 rounded-xl shadow-lg border border-theme-border-primary">
106
106
  {thumbnail && !imgError && (
107
107
  <img
108
108
  src={thumbnail}
@@ -124,23 +124,23 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
124
124
  <div className="text-center mb-4">
125
125
  {appliedCoupon && discountedPrice !== undefined ? (
126
126
  <div className="space-y-1">
127
- <div className="text-2xl font-bold text-gray-900">
127
+ <div className="text-2xl font-bold text-theme-text-primary">
128
128
  {formatCoursePrice(discountedPrice, false, currency)}
129
129
  </div>
130
- <div className="text-base line-through text-gray-400">
130
+ <div className="text-base line-through text-theme-text-muted">
131
131
  {formatCoursePrice(price, isFree, currency)}
132
132
  </div>
133
- <div className="text-sm font-semibold text-gray-900">
133
+ <div className="text-sm font-semibold text-theme-text-primary">
134
134
  {(appliedCoupon as any).discountType === 'PERCENTAGE'
135
135
  ? `${(appliedCoupon as any).discountValue}% Off`
136
136
  : formatCoursePrice((appliedCoupon as any).discountValue, false, currency)}
137
137
  </div>
138
138
  </div>
139
139
  ) : (
140
- <div className="text-2xl font-bold text-gray-900">
140
+ <div className="text-2xl font-bold text-theme-text-primary">
141
141
  {formatCoursePrice(price, isFree, currency)}
142
142
  {pricingType === 'SUBSCRIPTION' && (
143
- <span className="text-lg font-normal text-gray-500"> / month</span>
143
+ <span className="text-lg font-normal text-theme-text-secondary"> / month</span>
144
144
  )}
145
145
  </div>
146
146
  )}
@@ -197,7 +197,7 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
197
197
  placeholder="Enter coupon code"
198
198
  value={couponCode}
199
199
  onChange={(e) => onCouponCodeChange(e.target.value.toUpperCase())}
200
- className={`flex-1 text-sm border rounded-md px-3 py-2 focus:outline-none focus:border-[#49BBBD] ${couponError ? 'border-red-500' : 'border-gray-300'}`}
200
+ className={`flex-1 text-sm border rounded-md px-3 py-2 focus:outline-none focus:border-[#49BBBD] ${couponError ? 'border-red-500' : 'border-theme-border-primary'}`}
201
201
  />
202
202
  <button
203
203
  onClick={onApplyCoupon as any}
@@ -222,22 +222,22 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
222
222
  )}
223
223
 
224
224
  {/* This course included */}
225
- <div className="border-t border-gray-200 pt-4">
226
- <h3 className="font-semibold text-gray-900 mb-3 text-sm">This course included</h3>
225
+ <div className="border-t border-theme-border-primary pt-4">
226
+ <h3 className="font-semibold text-theme-text-primary mb-3 text-sm">This course included</h3>
227
227
  <div className="space-y-2.5">
228
- <div className="flex items-center gap-2.5 text-gray-700">
228
+ <div className="flex items-center gap-2.5 text-theme-text-secondary">
229
229
  <div className="w-4 h-4 rounded-full bg-theme-accent-primary flex items-center justify-center flex-shrink-0">
230
230
  <FileText className="h-2.5 w-2.5 text-white" />
231
231
  </div>
232
232
  <span className="text-sm">{totalLessons} lessons</span>
233
233
  </div>
234
- <div className="flex items-center gap-2.5 text-gray-700">
234
+ <div className="flex items-center gap-2.5 text-theme-text-secondary">
235
235
  <div className="w-4 h-4 rounded-full bg-theme-accent-primary flex items-center justify-center flex-shrink-0">
236
236
  <Clock className="h-2.5 w-2.5 text-white" />
237
237
  </div>
238
238
  <span className="text-sm">Self-paced learning</span>
239
239
  </div>
240
- <div className="flex items-center gap-2.5 text-gray-700">
240
+ <div className="flex items-center gap-2.5 text-theme-text-secondary">
241
241
  <div className="w-4 h-4 rounded-full bg-theme-accent-primary flex items-center justify-center flex-shrink-0">
242
242
  <Monitor className="h-2.5 w-2.5 text-white" />
243
243
  </div>
@@ -302,7 +302,7 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
302
302
  className={`px-6 py-2.5 rounded-full text-sm font-medium transition-all cursor-pointer ${
303
303
  activeTab === tab
304
304
  ? 'bg-theme-accent-primary text-white shadow-md'
305
- : 'bg-white text-gray-600 border border-gray-200 hover:border-[#49BBBD] hover:text-[#49BBBD]'
305
+ : 'bg-theme-bg-secondary text-theme-text-secondary border border-theme-border-primary hover:border-[#49BBBD] hover:text-[#49BBBD]'
306
306
  }`}
307
307
  >
308
308
  {tab.charAt(0).toUpperCase() + tab.slice(1)}
@@ -317,17 +317,17 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
317
317
  {activeTab === 'overview' && (
318
318
  <div className="lg:pr-110">
319
319
  {/* About This Course */}
320
- <div className="mb-8 pb-8 border-b border-gray-300">
321
- <h2 className="text-xl font-bold text-gray-900 mb-4">About This Course</h2>
320
+ <div className="mb-8 pb-8 border-b border-theme-border-primary">
321
+ <h2 className="text-xl font-bold text-theme-text-primary mb-4">About This Course</h2>
322
322
  {course.summary && (
323
323
  <div
324
- className="text-gray-700 text-sm leading-relaxed mb-6"
324
+ className="text-theme-text-secondary text-sm leading-relaxed mb-6"
325
325
  dangerouslySetInnerHTML={{ __html: course.summary }}
326
326
  />
327
327
  )}
328
328
  {course.description && (
329
329
  <div
330
- className="text-gray-700 text-sm leading-relaxed"
330
+ className="text-theme-text-secondary text-sm leading-relaxed"
331
331
  dangerouslySetInnerHTML={{ __html: course.description }}
332
332
  />
333
333
  )}
@@ -335,13 +335,13 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
335
335
 
336
336
  {/* What You'll Learn */}
337
337
  {course.whatYouWillLearn && course.whatYouWillLearn.length > 0 && (
338
- <div className="mb-8 pb-8 border-b border-gray-300">
339
- <h2 className="text-xl font-bold text-gray-900 mb-4">What You'll Learn</h2>
338
+ <div className="mb-8 pb-8 border-b border-theme-border-primary">
339
+ <h2 className="text-xl font-bold text-theme-text-primary mb-4">What You'll Learn</h2>
340
340
  <div className="grid md:grid-cols-2 gap-3">
341
341
  {course.whatYouWillLearn.map((item: string, i: number) => (
342
342
  <div key={i} className="flex items-start gap-3">
343
343
  <CheckCircle2 className="h-5 w-5 text-green-600 flex-shrink-0" />
344
- <span className="text-sm text-gray-700">{item}</span>
344
+ <span className="text-sm text-theme-text-secondary">{item}</span>
345
345
  </div>
346
346
  ))}
347
347
  </div>
@@ -350,13 +350,13 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
350
350
 
351
351
  {/* Requirements */}
352
352
  {course.requirements && course.requirements.length > 0 && (
353
- <div className="mb-8 pb-8 border-b border-gray-300">
354
- <h2 className="text-xl font-bold text-gray-900 mb-4">Requirements</h2>
353
+ <div className="mb-8 pb-8 border-b border-theme-border-primary">
354
+ <h2 className="text-xl font-bold text-theme-text-primary mb-4">Requirements</h2>
355
355
  <ul className="space-y-2">
356
356
  {course.requirements.map((item: string, i: number) => (
357
357
  <li key={i} className="flex items-start gap-2">
358
- <span className="text-gray-400 text-sm">•</span>
359
- <span className="text-sm text-gray-700">{item}</span>
358
+ <span className="text-theme-text-muted text-sm">•</span>
359
+ <span className="text-sm text-theme-text-secondary">{item}</span>
360
360
  </li>
361
361
  ))}
362
362
  </ul>
@@ -365,13 +365,13 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
365
365
 
366
366
  {/* Target Audience */}
367
367
  {course.targetAudience && course.targetAudience.length > 0 && (
368
- <div className="mb-8 pb-8 border-b border-gray-300">
369
- <h2 className="text-xl font-bold text-gray-900 mb-4">Who This Course Is For</h2>
368
+ <div className="mb-8 pb-8 border-b border-theme-border-primary">
369
+ <h2 className="text-xl font-bold text-theme-text-primary mb-4">Who This Course Is For</h2>
370
370
  <ul className="space-y-2">
371
371
  {course.targetAudience.map((item: string, i: number) => (
372
372
  <li key={i} className="flex items-start gap-2">
373
- <span className="text-gray-400 text-sm">•</span>
374
- <span className="text-sm text-gray-700">{item}</span>
373
+ <span className="text-theme-text-muted text-sm">•</span>
374
+ <span className="text-sm text-theme-text-secondary">{item}</span>
375
375
  </li>
376
376
  ))}
377
377
  </ul>
@@ -390,21 +390,21 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
390
390
  {[1, 2, 3, 4, 5].map((star) => (
391
391
  <svg
392
392
  key={star}
393
- className={`w-4 h-4 ${star <= Math.round(ratingSummary.averageRating || 0) ? 'text-yellow-400 fill-yellow-400' : 'text-gray-300 fill-gray-300'}`}
393
+ className={`w-4 h-4 ${star <= Math.round(ratingSummary.averageRating || 0) ? 'text-yellow-400 fill-yellow-400' : 'text-theme-border-primary fill-theme-border-primary'}`}
394
394
  viewBox="0 0 24 24"
395
395
  >
396
396
  <path 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" />
397
397
  </svg>
398
398
  ))}
399
399
  </div>
400
- <p className="text-sm text-gray-600">
400
+ <p className="text-sm text-theme-text-secondary">
401
401
  Course Rating • {ratingSummary.totalRatings} ratings
402
402
  </p>
403
403
  </div>
404
404
  </div>
405
405
 
406
406
  {ratings && ratings.slice(0, 2).map((review: any) => (
407
- <div key={review.id} className="mb-4 p-4 border border-gray-200 rounded-lg">
407
+ <div key={review.id} className="mb-4 p-4 border border-theme-border-primary rounded-lg">
408
408
  <div className="flex items-center gap-3 mb-2">
409
409
  <div className="w-9 h-9 rounded-full bg-theme-accent-primary flex items-center justify-center text-white font-semibold text-sm">
410
410
  {(review.reviewerName || 'U').charAt(0)}
@@ -415,7 +415,7 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
415
415
  {[1, 2, 3, 4, 5].map((star) => (
416
416
  <svg
417
417
  key={star}
418
- className={`w-3 h-3 ${star <= (review.rating || 0) ? 'text-yellow-400 fill-yellow-400' : 'text-gray-300 fill-gray-300'}`}
418
+ className={`w-3 h-3 ${star <= (review.rating || 0) ? 'text-yellow-400 fill-yellow-400' : 'text-theme-border-primary fill-theme-border-primary'}`}
419
419
  viewBox="0 0 24 24"
420
420
  >
421
421
  <path 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" />
@@ -425,7 +425,7 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
425
425
  </div>
426
426
  </div>
427
427
  {review.review && (
428
- <p className="text-sm text-gray-700">{review.review}</p>
428
+ <p className="text-sm text-theme-text-secondary">{review.review}</p>
429
429
  )}
430
430
  </div>
431
431
  ))}
@@ -437,53 +437,53 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
437
437
  {/* Curriculum Tab */}
438
438
  {activeTab === 'curriculum' && (
439
439
  <div className="mb-8">
440
- <h2 className="text-xl font-bold text-gray-900 mb-4">Curriculum</h2>
440
+ <h2 className="text-xl font-bold text-theme-text-primary mb-4">Curriculum</h2>
441
441
  <div className="space-y-1">
442
442
  {sections.map((section: any) => (
443
- <div key={section.id} className="border border-gray-200 rounded overflow-hidden">
443
+ <div key={section.id} className="border border-theme-border-primary rounded overflow-hidden">
444
444
  <button
445
445
  onClick={() => toggleSection(section.id)}
446
- className="w-full flex items-center justify-between p-3 hover:bg-gray-50 transition-colors text-left cursor-pointer"
446
+ className="w-full flex items-center justify-between p-3 hover:bg-theme-bg-tertiary transition-colors text-left cursor-pointer"
447
447
  >
448
448
  <div className="flex items-center gap-2">
449
449
  {expandedSections.has(section.id) ? (
450
- <ChevronDown className="h-4 w-4 text-gray-600" />
450
+ <ChevronDown className="h-4 w-4 text-theme-text-secondary" />
451
451
  ) : (
452
- <ChevronRight className="h-4 w-4 text-gray-600" />
452
+ <ChevronRight className="h-4 w-4 text-theme-text-secondary" />
453
453
  )}
454
454
  <div>
455
- <span className="text-sm font-medium text-gray-900">{section.title}</span>
455
+ <span className="text-sm font-medium text-theme-text-primary">{section.title}</span>
456
456
  {section.description && (
457
- <p className="text-xs text-gray-500 mt-0.5">{section.description}</p>
457
+ <p className="text-xs text-theme-text-muted mt-0.5">{section.description}</p>
458
458
  )}
459
459
  </div>
460
460
  </div>
461
- <span className="text-xs text-gray-500">
461
+ <span className="text-xs text-theme-text-muted">
462
462
  {section.activities?.length || 0} lessons
463
463
  </span>
464
464
  </button>
465
465
 
466
466
  {expandedSections.has(section.id) && (
467
- <div className="bg-gray-50 border-t border-gray-200">
467
+ <div className="bg-theme-bg-tertiary border-t border-theme-border-primary">
468
468
  {section.activities?.map((activity: any) => {
469
469
  const isSelected = selectedLesson === activity.id;
470
470
  return (
471
471
  <button
472
472
  key={activity.id}
473
473
  onClick={() => setSelectedLesson(activity.id)}
474
- className={`w-full flex items-start justify-between gap-3 px-10 py-3 border-b border-gray-100 last:border-b-0 transition-colors text-left cursor-pointer ${
474
+ className={`w-full flex items-start justify-between gap-3 px-10 py-3 border-b border-theme-border-primary last:border-b-0 transition-colors text-left cursor-pointer ${
475
475
  isSelected
476
476
  ? 'bg-blue-50 border-l-4 border-l-blue-600'
477
- : 'hover:bg-gray-100'
477
+ : 'hover:bg-theme-bg-secondary'
478
478
  }`}
479
479
  >
480
480
  <div className="flex items-start gap-3 flex-1">
481
481
  <PlayCircle
482
- className={`h-4 w-4 flex-shrink-0 mt-0.5 ${isSelected ? 'text-blue-600' : 'text-gray-400'}`}
482
+ className={`h-4 w-4 flex-shrink-0 mt-0.5 ${isSelected ? 'text-blue-600' : 'text-theme-text-muted'}`}
483
483
  />
484
484
  <div className="flex-1">
485
485
  <div className="flex items-center gap-2">
486
- <span className={`text-xs font-medium ${isSelected ? 'text-blue-600' : 'text-gray-700'}`}>
486
+ <span className={`text-xs font-medium ${isSelected ? 'text-blue-600' : 'text-theme-text-secondary'}`}>
487
487
  {activity.title}
488
488
  </span>
489
489
  {activity.freePreview && (
@@ -496,10 +496,10 @@ export function CourseDetailPage(props: Partial<CourseDetailPageProps>) {
496
496
  </div>
497
497
  <div className="flex items-center gap-3 flex-shrink-0">
498
498
  {activity.downloadable && (
499
- <Download className="h-3 w-3 text-gray-400" />
499
+ <Download className="h-3 w-3 text-theme-text-muted" />
500
500
  )}
501
501
  {activity.duration && (
502
- <span className="text-xs text-gray-500">
502
+ <span className="text-xs text-theme-text-muted">
503
503
  {typeof activity.duration === 'number'
504
504
  ? formatDuration(activity.duration)
505
505
  : activity.duration}
@@ -57,7 +57,7 @@ export function CoursePlayerPage(props: Partial<CoursePlayerPageProps> & {
57
57
 
58
58
  const [currentLessonIdx, setCurrentLessonIdx] = useState(0);
59
59
  const [expandedModules, setExpandedModules] = useState<Set<string>>(
60
- () => new Set(course?.modules?.[0]?.id ? [course.modules[0].id] : []),
60
+ () => new Set(course?.modules?.map((m) => m.id) ?? []),
61
61
  );
62
62
  const [activeTab, setActiveTab] = useState('overview');
63
63
  const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);