Eliminate all remaining text-kodo-content-dim from user-facing source files. This legacy token (hardcoded Gray-400) is now fully replaced by the theme-aware text-muted-foreground token across UI primitives, settings, social features, playlists, modals, inventory, and admin views. Only story files (.stories.tsx) retain the old token for reference. Total migration: ~345 instances across 87 files (this + previous commit). Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
4.9 KiB
TypeScript
143 lines
4.9 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Button } from '../ui/button';
|
|
import { Course } from '../../types';
|
|
import { CourseCard } from './CourseCard';
|
|
import { GraduationCap, PlayCircle, Clock } from 'lucide-react';
|
|
|
|
// Mock Enrolled Courses
|
|
const MY_COURSES: Course[] = [
|
|
{
|
|
id: 'c1',
|
|
title: 'Mastering with Ozone 10',
|
|
level: 'Advanced',
|
|
duration: '3h 45m',
|
|
progress: 75,
|
|
thumbnailUrl: 'https://picsum.photos/id/200/400/250',
|
|
instructor: 'Luca Pretellesi',
|
|
lastAccessed: '2 days ago',
|
|
},
|
|
{
|
|
id: 'c2',
|
|
title: 'Music Theory for Producers',
|
|
level: 'Beginner',
|
|
duration: '5h 10m',
|
|
progress: 10,
|
|
thumbnailUrl: 'https://picsum.photos/id/201/400/250',
|
|
instructor: 'Sarah Devine',
|
|
lastAccessed: '1 week ago',
|
|
},
|
|
{
|
|
id: 'c3',
|
|
title: 'Ableton Live 11 Fundamentals',
|
|
level: 'Beginner',
|
|
duration: '8h 20m',
|
|
progress: 100,
|
|
thumbnailUrl: 'https://picsum.photos/id/203/400/250',
|
|
instructor: 'Ableton Certified',
|
|
lastAccessed: '1 month ago',
|
|
certificateAvailable: true,
|
|
},
|
|
];
|
|
|
|
interface MyCoursesViewProps {
|
|
onContinue: (course: Course) => void;
|
|
}
|
|
|
|
export const MyCoursesView: React.FC<MyCoursesViewProps> = ({ onContinue }) => {
|
|
const [activeTab, setActiveTab] = useState<'in_progress' | 'completed'>(
|
|
'in_progress',
|
|
);
|
|
|
|
const filteredCourses = MY_COURSES.filter((c) =>
|
|
activeTab === 'in_progress'
|
|
? (c.progress || 0) < 100
|
|
: (c.progress || 0) === 100,
|
|
);
|
|
|
|
const lastActiveCourse = MY_COURSES.find(
|
|
(c) => (c.progress || 0) > 0 && (c.progress || 0) < 100,
|
|
);
|
|
|
|
return (
|
|
<div className="animate-fadeIn space-y-8 pb-20">
|
|
<div className="flex items-center gap-4 mb-6">
|
|
<GraduationCap className="w-8 h-8 text-kodo-steel" />
|
|
<h1 className="text-3xl font-display font-bold text-white">
|
|
My Learning
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Continue Learning Banner */}
|
|
{lastActiveCourse && activeTab === 'in_progress' && (
|
|
<div className="bg-kodo-ink p-6 rounded-2xl border border-kodo-steel flex flex-col md:flex-row gap-6 items-center shadow-2xl">
|
|
<div
|
|
className="relative w-full md:w-64 aspect-video rounded-lg overflow-hidden group cursor-pointer"
|
|
onClick={() => onContinue(lastActiveCourse)}
|
|
>
|
|
<img
|
|
src={lastActiveCourse.thumbnailUrl}
|
|
className="w-full h-full object-cover opacity-80 group-hover:scale-105 transition-transform"
|
|
/>
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<PlayCircle className="w-12 h-12 text-white fill-current drop-shadow-lg" />
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 text-center md:text-left">
|
|
<div className="text-xs text-kodo-gold font-bold uppercase mb-2 flex items-center justify-center md:justify-start gap-2">
|
|
<Clock className="w-3 h-3" /> Last accessed{' '}
|
|
{lastActiveCourse.lastAccessed}
|
|
</div>
|
|
<h2 className="text-2xl font-bold text-white mb-2">
|
|
{lastActiveCourse.title}
|
|
</h2>
|
|
<div className="w-full bg-kodo-steel h-2 rounded-full mb-4 max-w-md mx-auto md:mx-0">
|
|
<div
|
|
className="bg-kodo-cyan h-full rounded-full"
|
|
style={{ width: `${lastActiveCourse.progress}%` }}
|
|
></div>
|
|
</div>
|
|
<Button
|
|
variant="primary"
|
|
onClick={() => onContinue(lastActiveCourse)}
|
|
>
|
|
Continue Lesson
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Tabs */}
|
|
<div className="border-b border-kodo-steel flex gap-6">
|
|
<button
|
|
onClick={() => setActiveTab('in_progress')}
|
|
className={`pb-3 text-sm font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === 'in_progress' ? 'border-kodo-cyan text-white' : 'border-transparent text-muted-foreground hover:text-kodo-text-main'}`}
|
|
>
|
|
In Progress
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('completed')}
|
|
className={`pb-3 text-sm font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === 'completed' ? 'border-kodo-lime text-white' : 'border-transparent text-muted-foreground hover:text-kodo-text-main'}`}
|
|
>
|
|
Completed
|
|
</button>
|
|
</div>
|
|
|
|
{/* Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
|
{filteredCourses.map((course) => (
|
|
<CourseCard
|
|
key={course.id}
|
|
course={course}
|
|
onClick={onContinue}
|
|
showProgress={true}
|
|
/>
|
|
))}
|
|
{filteredCourses.length === 0 && (
|
|
<div className="col-span-full text-center py-24 text-muted-foreground">
|
|
<p>No courses found in this category.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|