Entities/Study_Material/Problems.txt ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Problem",
3
+ "type": "object",
4
+ "properties": {
5
+ "title": {
6
+ "type": "string",
7
+ "description": "Problem title"
8
+ },
9
+ "question": {
10
+ "type": "string",
11
+ "description": "The chemistry problem statement"
12
+ },
13
+ "topic": {
14
+ "type": "string",
15
+ "enum": [
16
+ "organic_chemistry",
17
+ "inorganic_chemistry",
18
+ "physical_chemistry",
19
+ "analytical_chemistry",
20
+ "biochemistry",
21
+ "quantum_chemistry",
22
+ "materials_science"
23
+ ],
24
+ "description": "Chemistry topic category"
25
+ },
26
+ "difficulty": {
27
+ "type": "string",
28
+ "enum": [
29
+ "beginner",
30
+ "intermediate",
31
+ "advanced"
32
+ ],
33
+ "description": "Problem difficulty level"
34
+ },
35
+ "solution": {
36
+ "type": "string",
37
+ "description": "Step-by-step solution explanation"
38
+ },
39
+ "molecular_formula": {
40
+ "type": "string",
41
+ "description": "Chemical formula if applicable"
42
+ },
43
+ "molecular_structure": {
44
+ "type": "string",
45
+ "description": "3D molecular structure data for visualization"
46
+ },
47
+ "concepts": {
48
+ "type": "array",
49
+ "items": {
50
+ "type": "string"
51
+ },
52
+ "description": "Key chemistry concepts covered"
53
+ },
54
+ "hints": {
55
+ "type": "array",
56
+ "items": {
57
+ "type": "string"
58
+ },
59
+ "description": "Progressive hints for problem solving"
60
+ }
61
+ },
62
+ "required": [
63
+ "title",
64
+ "question",
65
+ "topic",
66
+ "difficulty",
67
+ "solution"
68
+ ],
69
+ "rls": {
70
+ "read": {
71
+ "$or": [
72
+ {
73
+ "created_by": "{{user.email}}"
74
+ },
75
+ {
76
+ "user_condition": {
77
+ "role": "admin"
78
+ }
79
+ }
80
+ ]
81
+ },
82
+ "write": {
83
+ "$or": [
84
+ {
85
+ "created_by": "{{user.email}}"
86
+ },
87
+ {
88
+ "user_condition": {
89
+ "role": "admin"
90
+ }
91
+ }
92
+ ]
93
+ }
94
+ }
95
+ }
Entities/Study_Material/Study_Sessions.txt ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "StudySession",
3
+ "type": "object",
4
+ "properties": {
5
+ "user_email": {
6
+ "type": "string",
7
+ "description": "Email of the student"
8
+ },
9
+ "problem_id": {
10
+ "type": "string",
11
+ "description": "ID of the problem attempted"
12
+ },
13
+ "completed": {
14
+ "type": "boolean",
15
+ "default": false,
16
+ "description": "Whether the problem was successfully solved"
17
+ },
18
+ "time_spent": {
19
+ "type": "number",
20
+ "description": "Time spent on problem in minutes"
21
+ },
22
+ "hints_used": {
23
+ "type": "number",
24
+ "default": 0,
25
+ "description": "Number of hints the student used"
26
+ },
27
+ "score": {
28
+ "type": "number",
29
+ "minimum": 0,
30
+ "maximum": 100,
31
+ "description": "Score achieved on the problem"
32
+ },
33
+ "session_date": {
34
+ "type": "string",
35
+ "format": "date",
36
+ "description": "Date of the study session"
37
+ }
38
+ },
39
+ "required": [
40
+ "user_email",
41
+ "problem_id"
42
+ ],
43
+ "rls": {
44
+ "read": {
45
+ "$or": [
46
+ {
47
+ "user_email": "{{user.email}}"
48
+ },
49
+ {
50
+ "user_condition": {
51
+ "role": "admin"
52
+ }
53
+ }
54
+ ]
55
+ },
56
+ "write": {
57
+ "$or": [
58
+ {
59
+ "user_email": "{{user.email}}"
60
+ },
61
+ {
62
+ "user_condition": {
63
+ "role": "admin"
64
+ }
65
+ }
66
+ ]
67
+ }
68
+ }
69
+ }
Layouts/Layouts.txt ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from "react";
2
+ import { Link, useLocation } from "react-router-dom";
3
+ import { createPageUrl } from "@/utils";
4
+ import {
5
+ BookOpen,
6
+ Brain,
7
+ Target,
8
+ BarChart3,
9
+ Atom,
10
+ User,
11
+ Menu,
12
+ X,
13
+ Sparkles,
14
+ Trophy
15
+ } from "lucide-react";
16
+ import { User as UserEntity } from "@/entities/User";
17
+ import {
18
+ Sidebar,
19
+ SidebarContent,
20
+ SidebarGroup,
21
+ SidebarGroupContent,
22
+ SidebarGroupLabel,
23
+ SidebarMenu,
24
+ SidebarMenuButton,
25
+ SidebarMenuItem,
26
+ SidebarHeader,
27
+ SidebarFooter,
28
+ SidebarProvider,
29
+ SidebarTrigger,
30
+ } from "@/components/ui/sidebar";
31
+
32
+ const navigationItems = [
33
+ {
34
+ title: "Dashboard",
35
+ url: createPageUrl("Dashboard"),
36
+ icon: BarChart3,
37
+ description: "Overview & Progress"
38
+ },
39
+ {
40
+ title: "Practice",
41
+ url: createPageUrl("Practice"),
42
+ icon: Brain,
43
+ description: "AI-Generated Problems"
44
+ },
45
+ {
46
+ title: "Molecular Viewer",
47
+ url: createPageUrl("MolecularViewer"),
48
+ icon: Atom,
49
+ description: "3D Visualizations"
50
+ },
51
+ {
52
+ title: "Study Materials",
53
+ url: createPageUrl("StudyMaterials"),
54
+ icon: BookOpen,
55
+ description: "Custom Learning Resources"
56
+ }
57
+ ];
58
+
59
+ export default function Layout({ children, currentPageName }) {
60
+ const location = useLocation();
61
+ const [user, setUser] = useState(null);
62
+ const [loading, setLoading] = useState(true);
63
+
64
+ useEffect(() => {
65
+ loadUser();
66
+ }, []);
67
+
68
+ const loadUser = async () => {
69
+ try {
70
+ const userData = await UserEntity.me();
71
+ setUser(userData);
72
+ } catch (error) {
73
+ console.log("User not logged in");
74
+ }
75
+ setLoading(false);
76
+ };
77
+
78
+ if (loading) {
79
+ return (
80
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center">
81
+ <div className="flex items-center gap-3">
82
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
83
+ <span className="text-slate-600 font-medium">Loading ChemTutor AI...</span>
84
+ </div>
85
+ </div>
86
+ );
87
+ }
88
+
89
+ return (
90
+ <SidebarProvider>
91
+ <div className="min-h-screen flex w-full bg-gradient-to-br from-slate-50 to-blue-50">
92
+ <Sidebar className="border-r border-slate-200 bg-white/80 backdrop-blur-sm">
93
+ <SidebarHeader className="border-b border-slate-200 p-6">
94
+ <div className="flex items-center gap-3">
95
+ <div className="relative w-10 h-10 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-xl flex items-center justify-center shadow-lg">
96
+ <Atom className="w-6 h-6 text-white" />
97
+ <div className="absolute -top-1 -right-1 w-4 h-4 bg-gradient-to-r from-emerald-400 to-teal-500 rounded-full flex items-center justify-center">
98
+ <Sparkles className="w-2.5 h-2.5 text-white" />
99
+ </div>
100
+ </div>
101
+ <div>
102
+ <h2 className="text-xl font-bold bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent">
103
+ ChemTutor AI
104
+ </h2>
105
+ <p className="text-sm text-slate-500">Intelligent Chemistry Learning</p>
106
+ </div>
107
+ </div>
108
+ </SidebarHeader>
109
+
110
+ <SidebarContent className="p-4">
111
+ <SidebarGroup>
112
+ <SidebarGroupLabel className="text-xs font-semibold text-slate-500 uppercase tracking-wider px-3 py-2">
113
+ Learning Hub
114
+ </SidebarGroupLabel>
115
+ <SidebarGroupContent>
116
+ <SidebarMenu>
117
+ {navigationItems.map((item) => (
118
+ <SidebarMenuItem key={item.title}>
119
+ <SidebarMenuButton
120
+ asChild
121
+ className={`group hover:bg-blue-50 hover:text-blue-700 transition-all duration-200 rounded-xl mb-1 ${
122
+ location.pathname === item.url
123
+ ? 'bg-gradient-to-r from-blue-50 to-indigo-50 text-blue-700 shadow-sm border border-blue-100'
124
+ : ''
125
+ }`}
126
+ >
127
+ <Link to={item.url} className="flex items-center gap-4 px-4 py-3">
128
+ <item.icon className="w-5 h-5 group-hover:scale-110 transition-transform duration-200" />
129
+ <div>
130
+ <span className="font-semibold">{item.title}</span>
131
+ <p className="text-xs text-slate-500 group-hover:text-blue-600 transition-colors">
132
+ {item.description}
133
+ </p>
134
+ </div>
135
+ </Link>
136
+ </SidebarMenuButton>
137
+ </SidebarMenuItem>
138
+ ))}
139
+ </SidebarMenu>
140
+ </SidebarGroupContent>
141
+ </SidebarGroup>
142
+
143
+ {user && (
144
+ <SidebarGroup className="mt-6">
145
+ <SidebarGroupLabel className="text-xs font-semibold text-slate-500 uppercase tracking-wider px-3 py-2">
146
+ Your Progress
147
+ </SidebarGroupLabel>
148
+ <SidebarGroupContent>
149
+ <div className="px-4 py-3 space-y-3">
150
+ <div className="flex items-center justify-between">
151
+ <div className="flex items-center gap-2">
152
+ <Trophy className="w-4 h-4 text-amber-500" />
153
+ <span className="text-sm font-medium text-slate-700">Problems Solved</span>
154
+ </div>
155
+ <span className="text-lg font-bold text-blue-600">
156
+ {user.total_problems_solved || 0}
157
+ </span>
158
+ </div>
159
+ <div className="flex items-center justify-between">
160
+ <div className="flex items-center gap-2">
161
+ <Target className="w-4 h-4 text-emerald-500" />
162
+ <span className="text-sm font-medium text-slate-700">Current Streak</span>
163
+ </div>
164
+ <span className="text-lg font-bold text-emerald-600">
165
+ {user.current_streak || 0} days
166
+ </span>
167
+ </div>
168
+ <div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg p-3 border border-blue-100">
169
+ <p className="text-xs font-medium text-blue-700 mb-1">Learning Level</p>
170
+ <p className="text-sm font-bold text-blue-900 capitalize">
171
+ {user.learning_level || 'Beginner'}
172
+ </p>
173
+ </div>
174
+ </div>
175
+ </SidebarGroupContent>
176
+ </SidebarGroup>
177
+ )}
178
+ </SidebarContent>
179
+
180
+ <SidebarFooter className="border-t border-slate-200 p-4">
181
+ {user ? (
182
+ <div className="flex items-center gap-3 p-3 rounded-xl bg-gradient-to-r from-slate-50 to-blue-50 border border-slate-200">
183
+ <div className="w-10 h-10 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-full flex items-center justify-center">
184
+ <User className="w-5 h-5 text-white" />
185
+ </div>
186
+ <div className="flex-1 min-w-0">
187
+ <p className="font-semibold text-slate-900 text-sm truncate">
188
+ {user.full_name || 'Student'}
189
+ </p>
190
+ <p className="text-xs text-slate-500 truncate">{user.email}</p>
191
+ </div>
192
+ </div>
193
+ ) : (
194
+ <button
195
+ onClick={() => UserEntity.login()}
196
+ className="w-full bg-gradient-to-r from-blue-600 to-indigo-700 text-white font-semibold py-3 px-4 rounded-xl hover:from-blue-700 hover:to-indigo-800 transition-all duration-200 shadow-lg hover:shadow-xl"
197
+ >
198
+ Start Learning
199
+ </button>
200
+ )}
201
+ </SidebarFooter>
202
+ </Sidebar>
203
+
204
+ <main className="flex-1 flex flex-col">
205
+ {/* Mobile header */}
206
+ <header className="bg-white/80 backdrop-blur-sm border-b border-slate-200 px-6 py-4 md:hidden">
207
+ <div className="flex items-center gap-4">
208
+ <SidebarTrigger className="hover:bg-slate-100 p-2 rounded-lg transition-colors duration-200" />
209
+ <div className="flex items-center gap-2">
210
+ <Atom className="w-6 h-6 text-blue-600" />
211
+ <h1 className="text-lg font-bold text-slate-900">ChemTutor AI</h1>
212
+ </div>
213
+ </div>
214
+ </header>
215
+
216
+ {/* Main content area */}
217
+ <div className="flex-1 overflow-auto">
218
+ {children}
219
+ </div>
220
+ </main>
221
+ </div>
222
+ </SidebarProvider>
223
+ );
224
+ }
Pages/Items/Dashboard.txt ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from "react";
2
+ import { User } from "@/entities/User";
3
+ import { Problem } from "@/entities/Problem";
4
+ import { StudySession } from "@/entities/StudySession";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7
+ import { Progress } from "@/components/ui/progress";
8
+ import { Badge } from "@/components/ui/badge";
9
+ import { Link } from "react-router-dom";
10
+ import { createPageUrl } from "@/utils";
11
+ import {
12
+ Brain,
13
+ Target,
14
+ TrendingUp,
15
+ BookOpen,
16
+ Trophy,
17
+ Clock,
18
+ Atom,
19
+ Sparkles,
20
+ Play,
21
+ ChevronRight,
22
+ Calendar,
23
+ Award
24
+ } from "lucide-react";
25
+ import { format, startOfWeek, endOfWeek } from "date-fns";
26
+
27
+ export default function Dashboard() {
28
+ const [user, setUser] = useState(null);
29
+ const [recentSessions, setRecentSessions] = useState([]);
30
+ const [weeklyStats, setWeeklyStats] = useState({ solved: 0, timeSpent: 0 });
31
+ const [isLoading, setIsLoading] = useState(true);
32
+
33
+ useEffect(() => {
34
+ loadDashboardData();
35
+ }, []);
36
+
37
+ const loadDashboardData = async () => {
38
+ try {
39
+ const userData = await User.me();
40
+ if (!userData) {
41
+ await User.login();
42
+ return;
43
+ }
44
+
45
+ setUser(userData);
46
+
47
+ // Load recent study sessions
48
+ const sessions = await StudySession.filter(
49
+ { user_email: userData.email },
50
+ '-session_date',
51
+ 10
52
+ );
53
+ setRecentSessions(sessions);
54
+
55
+ // Calculate weekly stats
56
+ const weekStart = startOfWeek(new Date());
57
+ const weekEnd = endOfWeek(new Date());
58
+ const weeklySessions = sessions.filter(session => {
59
+ const sessionDate = new Date(session.session_date);
60
+ return sessionDate >= weekStart && sessionDate <= weekEnd;
61
+ });
62
+
63
+ setWeeklyStats({
64
+ solved: weeklySessions.filter(s => s.completed).length,
65
+ timeSpent: weeklySessions.reduce((total, s) => total + (s.time_spent || 0), 0)
66
+ });
67
+
68
+ } catch (error) {
69
+ console.error("Error loading dashboard:", error);
70
+ }
71
+ setIsLoading(false);
72
+ };
73
+
74
+ const handleGetStarted = async () => {
75
+ if (!user) {
76
+ await User.login();
77
+ }
78
+ };
79
+
80
+ if (isLoading) {
81
+ return (
82
+ <div className="flex items-center justify-center min-h-screen">
83
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
84
+ </div>
85
+ );
86
+ }
87
+
88
+ if (!user) {
89
+ return (
90
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-6">
91
+ <Card className="max-w-2xl w-full border-0 shadow-2xl bg-white/80 backdrop-blur-sm">
92
+ <CardHeader className="text-center pb-8">
93
+ <div className="w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-full flex items-center justify-center shadow-xl">
94
+ <Atom className="w-10 h-10 text-white" />
95
+ </div>
96
+ <CardTitle className="text-4xl font-bold bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent mb-4">
97
+ Welcome to ChemTutor AI
98
+ </CardTitle>
99
+ <p className="text-xl text-slate-600 leading-relaxed">
100
+ Your intelligent chemistry learning companion. Master chemistry concepts through AI-powered personalized problems, interactive 3D molecular visualization, and adaptive tutoring.
101
+ </p>
102
+ </CardHeader>
103
+ <CardContent className="pt-0">
104
+ <div className="grid md:grid-cols-3 gap-6 mb-8">
105
+ <div className="text-center p-4">
106
+ <Brain className="w-12 h-12 mx-auto mb-3 text-blue-600" />
107
+ <h3 className="font-semibold text-slate-900 mb-2">AI-Generated Problems</h3>
108
+ <p className="text-sm text-slate-600">Custom chemistry problems tailored to your skill level</p>
109
+ </div>
110
+ <div className="text-center p-4">
111
+ <Atom className="w-12 h-12 mx-auto mb-3 text-indigo-600" />
112
+ <h3 className="font-semibold text-slate-900 mb-2">3D Molecular Models</h3>
113
+ <p className="text-sm text-slate-600">Interactive visualizations to understand molecular structures</p>
114
+ </div>
115
+ <div className="text-center p-4">
116
+ <TrendingUp className="w-12 h-12 mx-auto mb-3 text-emerald-600" />
117
+ <h3 className="font-semibold text-slate-900 mb-2">Adaptive Learning</h3>
118
+ <p className="text-sm text-slate-600">Personalized difficulty adjustment based on your progress</p>
119
+ </div>
120
+ </div>
121
+ <Button
122
+ onClick={handleGetStarted}
123
+ className="w-full bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-semibold py-4 px-8 text-lg shadow-lg hover:shadow-xl transition-all duration-200"
124
+ >
125
+ <Play className="w-5 h-5 mr-2" />
126
+ Start Learning Now
127
+ </Button>
128
+ </CardContent>
129
+ </Card>
130
+ </div>
131
+ );
132
+ }
133
+
134
+ const dailyGoalProgress = user.study_goals?.daily_problems
135
+ ? Math.min(100, (weeklyStats.solved / 7) / user.study_goals.daily_problems * 100)
136
+ : 0;
137
+
138
+ return (
139
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 p-4 md:p-8">
140
+ <div className="max-w-7xl mx-auto">
141
+ {/* Welcome Header */}
142
+ <div className="mb-8">
143
+ <div className="flex items-center gap-3 mb-2">
144
+ <h1 className="text-3xl md:text-4xl font-bold text-slate-900">
145
+ Welcome back, {user.full_name?.split(' ')[0]}!
146
+ </h1>
147
+ <Sparkles className="w-8 h-8 text-amber-500" />
148
+ </div>
149
+ <p className="text-lg text-slate-600">Ready to explore chemistry today? Let's continue your learning journey.</p>
150
+ </div>
151
+
152
+ {/* Stats Cards */}
153
+ <div className="grid md:grid-cols-4 gap-6 mb-8">
154
+ <Card className="border-0 shadow-lg bg-gradient-to-br from-blue-600 to-indigo-700 text-white">
155
+ <CardContent className="p-6">
156
+ <div className="flex items-center justify-between">
157
+ <div>
158
+ <p className="text-blue-100 text-sm font-medium">Problems Solved</p>
159
+ <p className="text-3xl font-bold">{user.total_problems_solved || 0}</p>
160
+ </div>
161
+ <Trophy className="w-12 h-12 text-blue-200" />
162
+ </div>
163
+ </CardContent>
164
+ </Card>
165
+
166
+ <Card className="border-0 shadow-lg bg-gradient-to-br from-emerald-600 to-teal-700 text-white">
167
+ <CardContent className="p-6">
168
+ <div className="flex items-center justify-between">
169
+ <div>
170
+ <p className="text-emerald-100 text-sm font-medium">Current Streak</p>
171
+ <p className="text-3xl font-bold">{user.current_streak || 0} days</p>
172
+ </div>
173
+ <Target className="w-12 h-12 text-emerald-200" />
174
+ </div>
175
+ </CardContent>
176
+ </Card>
177
+
178
+ <Card className="border-0 shadow-lg bg-gradient-to-br from-purple-600 to-pink-700 text-white">
179
+ <CardContent className="p-6">
180
+ <div className="flex items-center justify-between">
181
+ <div>
182
+ <p className="text-purple-100 text-sm font-medium">This Week</p>
183
+ <p className="text-3xl font-bold">{weeklyStats.solved}</p>
184
+ </div>
185
+ <Calendar className="w-12 h-12 text-purple-200" />
186
+ </div>
187
+ </CardContent>
188
+ </Card>
189
+
190
+ <Card className="border-0 shadow-lg bg-gradient-to-br from-orange-600 to-red-700 text-white">
191
+ <CardContent className="p-6">
192
+ <div className="flex items-center justify-between">
193
+ <div>
194
+ <p className="text-orange-100 text-sm font-medium">Study Time</p>
195
+ <p className="text-3xl font-bold">{Math.round(weeklyStats.timeSpent)}m</p>
196
+ </div>
197
+ <Clock className="w-12 h-12 text-orange-200" />
198
+ </div>
199
+ </CardContent>
200
+ </Card>
201
+ </div>
202
+
203
+ <div className="grid lg:grid-cols-3 gap-8">
204
+ {/* Quick Actions */}
205
+ <div className="lg:col-span-2 space-y-6">
206
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
207
+ <CardHeader>
208
+ <CardTitle className="flex items-center gap-2 text-2xl">
209
+ <Brain className="w-6 h-6 text-blue-600" />
210
+ Quick Start
211
+ </CardTitle>
212
+ </CardHeader>
213
+ <CardContent>
214
+ <div className="grid md:grid-cols-2 gap-4">
215
+ <Link to={createPageUrl("Practice")}>
216
+ <Card className="hover:shadow-lg transition-all duration-200 cursor-pointer group bg-gradient-to-br from-blue-50 to-indigo-50 border-blue-200">
217
+ <CardContent className="p-6">
218
+ <div className="flex items-center justify-between mb-4">
219
+ <Brain className="w-8 h-8 text-blue-600 group-hover:scale-110 transition-transform" />
220
+ <ChevronRight className="w-5 h-5 text-blue-400 group-hover:translate-x-1 transition-transform" />
221
+ </div>
222
+ <h3 className="font-semibold text-slate-900 mb-2">Practice Problems</h3>
223
+ <p className="text-sm text-slate-600">Solve AI-generated chemistry problems</p>
224
+ </CardContent>
225
+ </Card>
226
+ </Link>
227
+
228
+ <Link to={createPageUrl("MolecularViewer")}>
229
+ <Card className="hover:shadow-lg transition-all duration-200 cursor-pointer group bg-gradient-to-br from-purple-50 to-pink-50 border-purple-200">
230
+ <CardContent className="p-6">
231
+ <div className="flex items-center justify-between mb-4">
232
+ <Atom className="w-8 h-8 text-purple-600 group-hover:scale-110 transition-transform" />
233
+ <ChevronRight className="w-5 h-5 text-purple-400 group-hover:translate-x-1 transition-transform" />
234
+ </div>
235
+ <h3 className="font-semibold text-slate-900 mb-2">3D Molecules</h3>
236
+ <p className="text-sm text-slate-600">Explore molecular structures in 3D</p>
237
+ </CardContent>
238
+ </Card>
239
+ </Link>
240
+ </div>
241
+ </CardContent>
242
+ </Card>
243
+
244
+ {/* Daily Progress */}
245
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
246
+ <CardHeader>
247
+ <CardTitle className="flex items-center gap-2">
248
+ <Target className="w-5 h-5 text-emerald-600" />
249
+ Daily Progress
250
+ </CardTitle>
251
+ </CardHeader>
252
+ <CardContent>
253
+ <div className="space-y-4">
254
+ <div className="flex justify-between items-center">
255
+ <span className="font-medium text-slate-700">Daily Goal Progress</span>
256
+ <span className="text-sm text-slate-500">
257
+ {Math.round(dailyGoalProgress)}%
258
+ </span>
259
+ </div>
260
+ <Progress value={dailyGoalProgress} className="h-3" />
261
+ <p className="text-sm text-slate-600">
262
+ Goal: {user.study_goals?.daily_problems || 5} problems per day
263
+ </p>
264
+ </div>
265
+ </CardContent>
266
+ </Card>
267
+ </div>
268
+
269
+ {/* Learning Level & Recent Activity */}
270
+ <div className="space-y-6">
271
+ <Card className="border-0 shadow-xl bg-gradient-to-br from-slate-900 to-slate-800 text-white">
272
+ <CardContent className="p-6">
273
+ <div className="flex items-center gap-3 mb-4">
274
+ <Award className="w-6 h-6 text-amber-400" />
275
+ <h3 className="font-semibold text-lg">Learning Level</h3>
276
+ </div>
277
+ <Badge className="bg-amber-500 hover:bg-amber-600 text-amber-950 font-semibold text-lg px-4 py-2 mb-4">
278
+ {(user.learning_level || 'beginner').charAt(0).toUpperCase() + (user.learning_level || 'beginner').slice(1)}
279
+ </Badge>
280
+ <p className="text-slate-300 text-sm leading-relaxed">
281
+ {user.learning_level === 'advanced'
282
+ ? "You're mastering advanced chemistry concepts! Keep pushing your limits."
283
+ : user.learning_level === 'intermediate'
284
+ ? "You're building solid chemistry fundamentals. Ready for more challenges?"
285
+ : "Welcome to your chemistry journey! Let's start with the basics and build up your confidence."
286
+ }
287
+ </p>
288
+ </CardContent>
289
+ </Card>
290
+
291
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
292
+ <CardHeader>
293
+ <CardTitle className="flex items-center gap-2 text-lg">
294
+ <BookOpen className="w-5 h-5 text-slate-600" />
295
+ Recent Activity
296
+ </CardTitle>
297
+ </CardHeader>
298
+ <CardContent>
299
+ {recentSessions.length > 0 ? (
300
+ <div className="space-y-3">
301
+ {recentSessions.slice(0, 5).map((session, index) => (
302
+ <div key={session.id} className="flex items-center gap-3 p-3 rounded-lg bg-slate-50 hover:bg-slate-100 transition-colors">
303
+ <div className={`w-3 h-3 rounded-full ${session.completed ? 'bg-emerald-500' : 'bg-slate-400'}`} />
304
+ <div className="flex-1">
305
+ <p className="text-sm font-medium text-slate-900">
306
+ Problem #{session.problem_id?.slice(-4)}
307
+ </p>
308
+ <p className="text-xs text-slate-500">
309
+ {session.session_date && format(new Date(session.session_date), "MMM d")}
310
+ </p>
311
+ </div>
312
+ {session.score && (
313
+ <Badge variant="secondary" className="text-xs">
314
+ {session.score}%
315
+ </Badge>
316
+ )}
317
+ </div>
318
+ ))}
319
+ </div>
320
+ ) : (
321
+ <div className="text-center py-8">
322
+ <BookOpen className="w-12 h-12 mx-auto text-slate-400 mb-3" />
323
+ <p className="text-slate-500 mb-4">No recent activity yet</p>
324
+ <Link to={createPageUrl("Practice")}>
325
+ <Button variant="outline" size="sm">
326
+ Start Your First Problem
327
+ </Button>
328
+ </Link>
329
+ </div>
330
+ )}
331
+ </CardContent>
332
+ </Card>
333
+ </div>
334
+ </div>
335
+ </div>
336
+ </div>
337
+ );
338
+ }
Pages/Items/Molecular_View.txt ADDED
@@ -0,0 +1,850 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useRef } from "react";
2
+ import * as THREE from "three";
3
+ import { Button } from "@/components/ui/button";
4
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Input } from "@/components/ui/input";
6
+ import { Badge } from "@/components/ui/badge";
7
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
8
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
9
+ import {
10
+ Atom,
11
+ RotateCcw,
12
+ Search,
13
+ Play,
14
+ Pause,
15
+ Info,
16
+ Filter
17
+ } from "lucide-react";
18
+
19
+ // Comprehensive molecules database organized by category
20
+ const MOLECULES = [
21
+ // Simple Molecules
22
+ {
23
+ name: "Hydrogen Gas (H₂)",
24
+ formula: "H2",
25
+ category: "simple",
26
+ atoms: [
27
+ { element: "H", position: [-0.37, 0, 0], color: "#ffffff" },
28
+ { element: "H", position: [0.37, 0, 0], color: "#ffffff" }
29
+ ],
30
+ bonds: [{ from: 0, to: 1 }],
31
+ description: "The simplest and most abundant element in the universe, existing as diatomic molecules under normal conditions."
32
+ },
33
+ {
34
+ name: "Oxygen Gas (O₂)",
35
+ formula: "O2",
36
+ category: "simple",
37
+ atoms: [
38
+ { element: "O", position: [-0.60, 0, 0], color: "#ff0000" },
39
+ { element: "O", position: [0.60, 0, 0], color: "#ff0000" }
40
+ ],
41
+ bonds: [{ from: 0, to: 1 }],
42
+ description: "Essential for respiration and combustion, making up about 21% of Earth's atmosphere."
43
+ },
44
+ {
45
+ name: "Nitrogen Gas (N₂)",
46
+ formula: "N2",
47
+ category: "simple",
48
+ atoms: [
49
+ { element: "N", position: [-0.55, 0, 0], color: "#0000ff" },
50
+ { element: "N", position: [0.55, 0, 0], color: "#0000ff" }
51
+ ],
52
+ bonds: [{ from: 0, to: 1 }],
53
+ description: "Makes up about 78% of Earth's atmosphere. The triple bond makes it very stable."
54
+ },
55
+ {
56
+ name: "Carbon Dioxide (CO₂)",
57
+ formula: "CO2",
58
+ category: "simple",
59
+ atoms: [
60
+ { element: "C", position: [0, 0, 0], color: "#404040" },
61
+ { element: "O", position: [-1.16, 0, 0], color: "#ff0000" },
62
+ { element: "O", position: [1.16, 0, 0], color: "#ff0000" }
63
+ ],
64
+ bonds: [{ from: 0, to: 1 }, { from: 0, to: 2 }],
65
+ description: "A greenhouse gas produced by combustion and respiration, absorbed by plants during photosynthesis."
66
+ },
67
+ {
68
+ name: "Water (H₂O)",
69
+ formula: "H2O",
70
+ category: "simple",
71
+ atoms: [
72
+ { element: "O", position: [0, 0, 0], color: "#ff0000" },
73
+ { element: "H", position: [0.96, 0, 0], color: "#ffffff" },
74
+ { element: "H", position: [-0.24, 0.93, 0], color: "#ffffff" }
75
+ ],
76
+ bonds: [{ from: 0, to: 1 }, { from: 0, to: 2 }],
77
+ description: "The most essential compound for life, consisting of two hydrogen atoms bonded to one oxygen atom."
78
+ },
79
+ {
80
+ name: "Ammonia (NH₃)",
81
+ formula: "NH3",
82
+ category: "simple",
83
+ atoms: [
84
+ { element: "N", position: [0, 0, 0], color: "#0000ff" },
85
+ { element: "H", position: [0.94, 0, 0.33], color: "#ffffff" },
86
+ { element: "H", position: [-0.47, 0.82, 0.33], color: "#ffffff" },
87
+ { element: "H", position: [-0.47, -0.82, 0.33], color: "#ffffff" }
88
+ ],
89
+ bonds: [{ from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }],
90
+ description: "A basic compound used in fertilizers and cleaning products, with a trigonal pyramidal shape."
91
+ },
92
+
93
+ // Hydrocarbons - Alkanes
94
+ {
95
+ name: "Methane (CH₄)",
96
+ formula: "CH4",
97
+ category: "hydrocarbons",
98
+ atoms: [
99
+ { element: "C", position: [0, 0, 0], color: "#404040" },
100
+ { element: "H", position: [0.63, 0.63, 0.63], color: "#ffffff" },
101
+ { element: "H", position: [-0.63, -0.63, 0.63], color: "#ffffff" },
102
+ { element: "H", position: [-0.63, 0.63, -0.63], color: "#ffffff" },
103
+ { element: "H", position: [0.63, -0.63, -0.63], color: "#ffffff" }
104
+ ],
105
+ bonds: [{ from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 0, to: 4 }],
106
+ description: "The simplest hydrocarbon and main component of natural gas, featuring a tetrahedral geometry."
107
+ },
108
+ {
109
+ name: "Ethane (C₂H₆)",
110
+ formula: "C2H6",
111
+ category: "hydrocarbons",
112
+ atoms: [
113
+ { element: "C", position: [-0.77, 0, 0], color: "#404040" },
114
+ { element: "C", position: [0.77, 0, 0], color: "#404040" },
115
+ { element: "H", position: [-1.17, 0.89, 0.51], color: "#ffffff" },
116
+ { element: "H", position: [-1.17, -0.89, 0.51], color: "#ffffff" },
117
+ { element: "H", position: [-1.17, 0, -1.03], color: "#ffffff" },
118
+ { element: "H", position: [1.17, 0.89, 0.51], color: "#ffffff" },
119
+ { element: "H", position: [1.17, -0.89, 0.51], color: "#ffffff" },
120
+ { element: "H", position: [1.17, 0, -1.03], color: "#ffffff" }
121
+ ],
122
+ bonds: [
123
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 0, to: 4 },
124
+ { from: 1, to: 5 }, { from: 1, to: 6 }, { from: 1, to: 7 }
125
+ ],
126
+ description: "A simple alkane used as fuel, with free rotation around the C-C single bond."
127
+ },
128
+ {
129
+ name: "Propane (C₃H₈)",
130
+ formula: "C3H8",
131
+ category: "hydrocarbons",
132
+ atoms: [
133
+ { element: "C", position: [-1.27, 0, 0], color: "#404040" },
134
+ { element: "C", position: [0, 0, 0], color: "#404040" },
135
+ { element: "C", position: [1.27, 0, 0], color: "#404040" },
136
+ { element: "H", position: [-1.67, 0.89, 0.51], color: "#ffffff" },
137
+ { element: "H", position: [-1.67, -0.89, 0.51], color: "#ffffff" },
138
+ { element: "H", position: [-1.67, 0, -1.03], color: "#ffffff" },
139
+ { element: "H", position: [0, 0.89, 0.51], color: "#ffffff" },
140
+ { element: "H", position: [0, -0.89, 0.51], color: "#ffffff" },
141
+ { element: "H", position: [1.67, 0.89, 0.51], color: "#ffffff" },
142
+ { element: "H", position: [1.67, -0.89, 0.51], color: "#ffffff" },
143
+ { element: "H", position: [1.67, 0, -1.03], color: "#ffffff" }
144
+ ],
145
+ bonds: [
146
+ { from: 0, to: 1 }, { from: 1, to: 2 },
147
+ { from: 0, to: 3 }, { from: 0, to: 4 }, { from: 0, to: 5 },
148
+ { from: 1, to: 6 }, { from: 1, to: 7 },
149
+ { from: 2, to: 8 }, { from: 2, to: 9 }, { from: 2, to: 10 }
150
+ ],
151
+ description: "A common fuel gas used for heating, grilling, and as vehicle fuel (LPG)."
152
+ },
153
+
154
+ // Alkenes
155
+ {
156
+ name: "Ethene (C₂H₄)",
157
+ formula: "C2H4",
158
+ category: "hydrocarbons",
159
+ atoms: [
160
+ { element: "C", position: [-0.67, 0, 0], color: "#404040" },
161
+ { element: "C", position: [0.67, 0, 0], color: "#404040" },
162
+ { element: "H", position: [-1.23, 0.93, 0], color: "#ffffff" },
163
+ { element: "H", position: [-1.23, -0.93, 0], color: "#ffffff" },
164
+ { element: "H", position: [1.23, 0.93, 0], color: "#ffffff" },
165
+ { element: "H", position: [1.23, -0.93, 0], color: "#ffffff" }
166
+ ],
167
+ bonds: [
168
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 },
169
+ { from: 1, to: 4 }, { from: 1, to: 5 }
170
+ ],
171
+ description: "The simplest alkene with a C=C double bond, used to make polyethylene plastic."
172
+ },
173
+
174
+ // Aromatic Compounds
175
+ {
176
+ name: "Benzene (C₆H₆)",
177
+ formula: "C6H6",
178
+ category: "aromatics",
179
+ atoms: [
180
+ { element: "C", position: [1.40, 0, 0], color: "#404040" },
181
+ { element: "C", position: [0.70, 1.21, 0], color: "#404040" },
182
+ { element: "C", position: [-0.70, 1.21, 0], color: "#404040" },
183
+ { element: "C", position: [-1.40, 0, 0], color: "#404040" },
184
+ { element: "C", position: [-0.70, -1.21, 0], color: "#404040" },
185
+ { element: "C", position: [0.70, -1.21, 0], color: "#404040" },
186
+ { element: "H", position: [2.48, 0, 0], color: "#ffffff" },
187
+ { element: "H", position: [1.24, 2.15, 0], color: "#ffffff" },
188
+ { element: "H", position: [-1.24, 2.15, 0], color: "#ffffff" },
189
+ { element: "H", position: [-2.48, 0, 0], color: "#ffffff" },
190
+ { element: "H", position: [-1.24, -2.15, 0], color: "#ffffff" },
191
+ { element: "H", position: [1.24, -2.15, 0], color: "#ffffff" }
192
+ ],
193
+ bonds: [
194
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 },
195
+ { from: 3, to: 4 }, { from: 4, to: 5 }, { from: 5, to: 0 },
196
+ { from: 0, to: 6 }, { from: 1, to: 7 }, { from: 2, to: 8 },
197
+ { from: 3, to: 9 }, { from: 4, to: 10 }, { from: 5, to: 11 }
198
+ ],
199
+ description: "An aromatic hydrocarbon with a ring of six carbon atoms, fundamental in organic chemistry."
200
+ },
201
+ {
202
+ name: "Toluene (C₇H₈)",
203
+ formula: "C7H8",
204
+ category: "aromatics",
205
+ atoms: [
206
+ { element: "C", position: [1.40, 0, 0], color: "#404040" },
207
+ { element: "C", position: [0.70, 1.21, 0], color: "#404040" },
208
+ { element: "C", position: [-0.70, 1.21, 0], color: "#404040" },
209
+ { element: "C", position: [-1.40, 0, 0], color: "#404040" },
210
+ { element: "C", position: [-0.70, -1.21, 0], color: "#404040" },
211
+ { element: "C", position: [0.70, -1.21, 0], color: "#404040" },
212
+ { element: "C", position: [-2.87, 0, 0], color: "#404040" }, // methyl group
213
+ { element: "H", position: [2.48, 0, 0], color: "#ffffff" },
214
+ { element: "H", position: [1.24, 2.15, 0], color: "#ffffff" },
215
+ { element: "H", position: [-1.24, 2.15, 0], color: "#ffffff" },
216
+ { element: "H", position: [-1.24, -2.15, 0], color: "#ffffff" },
217
+ { element: "H", position: [1.24, -2.15, 0], color: "#ffffff" },
218
+ { element: "H", position: [-3.27, 0.89, 0.51], color: "#ffffff" },
219
+ { element: "H", position: [-3.27, -0.89, 0.51], color: "#ffffff" },
220
+ { element: "H", position: [-3.27, 0, -1.03], color: "#ffffff" }
221
+ ],
222
+ bonds: [
223
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 },
224
+ { from: 3, to: 4 }, { from: 4, to: 5 }, { from: 5, to: 0 },
225
+ { from: 3, to: 6 }, { from: 0, to: 7 }, { from: 1, to: 8 },
226
+ { from: 2, to: 9 }, { from: 4, to: 10 }, { from: 5, to: 11 },
227
+ { from: 6, to: 12 }, { from: 6, to: 13 }, { from: 6, to: 14 }
228
+ ],
229
+ description: "Methylbenzene, used as a solvent and in the production of other chemicals."
230
+ },
231
+
232
+ // Alcohols
233
+ {
234
+ name: "Methanol (CH₄O)",
235
+ formula: "CH4O",
236
+ category: "alcohols",
237
+ atoms: [
238
+ { element: "C", position: [0, 0, 0], color: "#404040" },
239
+ { element: "O", position: [1.43, 0, 0], color: "#ff0000" },
240
+ { element: "H", position: [-0.51, 0.89, 0.51], color: "#ffffff" },
241
+ { element: "H", position: [-0.51, -0.89, 0.51], color: "#ffffff" },
242
+ { element: "H", position: [-0.51, 0, -1.03], color: "#ffffff" },
243
+ { element: "H", position: [1.83, 0, 0.96], color: "#ffffff" }
244
+ ],
245
+ bonds: [
246
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 },
247
+ { from: 0, to: 4 }, { from: 1, to: 5 }
248
+ ],
249
+ description: "The simplest alcohol, used as fuel additive and solvent. Highly toxic to humans."
250
+ },
251
+ {
252
+ name: "Ethanol (C₂H₆O)",
253
+ formula: "C2H6O",
254
+ category: "alcohols",
255
+ atoms: [
256
+ { element: "C", position: [-0.77, 0.36, 0], color: "#404040" },
257
+ { element: "C", position: [0.77, 0.36, 0], color: "#404040" },
258
+ { element: "O", position: [1.2, -0.8, 0], color: "#ff0000" },
259
+ { element: "H", position: [-1.1, 0.7, 1], color: "#ffffff" },
260
+ { element: "H", position: [-1.1, 0.7, -1], color: "#ffffff" },
261
+ { element: "H", position: [-1.2, -0.6, 0], color: "#ffffff" },
262
+ { element: "H", position: [1.1, 1.3, 0], color: "#ffffff" },
263
+ { element: "H", position: [1.1, -0.2, 1], color: "#ffffff" },
264
+ { element: "H", position: [2.1, -0.6, 0], color: "#ffffff" }
265
+ ],
266
+ bonds: [
267
+ { from: 0, to: 1 }, { from: 1, to: 2 },
268
+ { from: 0, to: 3 }, { from: 0, to: 4 }, { from: 0, to: 5 },
269
+ { from: 1, to: 6 }, { from: 1, to: 7 },
270
+ { from: 2, to: 8 }
271
+ ],
272
+ description: "The alcohol found in beverages, also used as fuel and solvent."
273
+ },
274
+
275
+ // Acids
276
+ {
277
+ name: "Formic Acid (HCOOH)",
278
+ formula: "HCOOH",
279
+ category: "acids",
280
+ atoms: [
281
+ { element: "C", position: [0, 0, 0], color: "#404040" },
282
+ { element: "O", position: [1.23, -0.67, 0], color: "#ff0000" },
283
+ { element: "O", position: [0.31, 1.34, 0], color: "#ff0000" },
284
+ { element: "H", position: [-1.08, 0.11, 0], color: "#ffffff" },
285
+ { element: "H", position: [1.19, 1.14, 0], color: "#ffffff" }
286
+ ],
287
+ bonds: [
288
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 2, to: 4 }
289
+ ],
290
+ description: "The simplest carboxylic acid, found in ant stings and used as a preservative."
291
+ },
292
+ {
293
+ name: "Acetic Acid (CH₃COOH)",
294
+ formula: "CH3COOH",
295
+ category: "acids",
296
+ atoms: [
297
+ { element: "C", position: [-1.27, 0, 0], color: "#404040" },
298
+ { element: "C", position: [0, 0, 0], color: "#404040" },
299
+ { element: "O", position: [1.23, -0.67, 0], color: "#ff0000" },
300
+ { element: "O", position: [0.31, 1.34, 0], color: "#ff0000" },
301
+ { element: "H", position: [-1.67, 0.89, 0.51], color: "#ffffff" },
302
+ { element: "H", position: [-1.67, -0.89, 0.51], color: "#ffffff" },
303
+ { element: "H", position: [-1.67, 0, -1.03], color: "#ffffff" },
304
+ { element: "H", position: [1.19, 1.14, 0], color: "#ffffff" }
305
+ ],
306
+ bonds: [
307
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 1, to: 3 },
308
+ { from: 0, to: 4 }, { from: 0, to: 5 }, { from: 0, to: 6 }, { from: 3, to: 7 }
309
+ ],
310
+ description: "Found in vinegar, used as food preservative and in chemical synthesis."
311
+ },
312
+
313
+ // Biomolecules - Amino Acids
314
+ {
315
+ name: "Glycine (NH₂CH₂COOH)",
316
+ formula: "C2H5NO2",
317
+ category: "biomolecules",
318
+ atoms: [
319
+ { element: "N", position: [-2.14, 0, 0], color: "#0000ff" },
320
+ { element: "C", position: [-0.67, 0, 0], color: "#404040" },
321
+ { element: "C", position: [0.67, 0, 0], color: "#404040" },
322
+ { element: "O", position: [1.23, -1.15, 0], color: "#ff0000" },
323
+ { element: "O", position: [1.23, 1.15, 0], color: "#ff0000" },
324
+ { element: "H", position: [-2.54, 0.81, 0.41], color: "#ffffff" },
325
+ { element: "H", position: [-2.54, -0.81, 0.41], color: "#ffffff" },
326
+ { element: "H", position: [-0.67, 0.89, 0.51], color: "#ffffff" },
327
+ { element: "H", position: [-0.67, -0.89, 0.51], color: "#ffffff" },
328
+ { element: "H", position: [2.17, 1.08, 0], color: "#ffffff" }
329
+ ],
330
+ bonds: [
331
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 }, { from: 2, to: 4 },
332
+ { from: 0, to: 5 }, { from: 0, to: 6 }, { from: 1, to: 7 }, { from: 1, to: 8 }, { from: 4, to: 9 }
333
+ ],
334
+ description: "The simplest amino acid, essential for protein synthesis and neurotransmitter function."
335
+ },
336
+
337
+ // Sugars
338
+ {
339
+ name: "Glucose (C₆H₁₂O₆)",
340
+ formula: "C6H12O6",
341
+ category: "biomolecules",
342
+ atoms: [
343
+ { element: "C", position: [0, 0, 0], color: "#404040" },
344
+ { element: "C", position: [1.25, 0.72, 0], color: "#404040" },
345
+ { element: "C", position: [1.25, 2.17, 0], color: "#404040" },
346
+ { element: "C", position: [0, 2.89, 0], color: "#404040" },
347
+ { element: "C", position: [-1.25, 2.17, 0], color: "#404040" },
348
+ { element: "O", position: [-1.25, 0.72, 0], color: "#ff0000" },
349
+ { element: "O", position: [2.5, 0, 0], color: "#ff0000" },
350
+ { element: "O", position: [2.5, 2.89, 0], color: "#ff0000" },
351
+ { element: "O", position: [0, 4.34, 0], color: "#ff0000" },
352
+ { element: "O", position: [-2.5, 2.89, 0], color: "#ff0000" },
353
+ { element: "C", position: [-2.5, 4.34, 0], color: "#404040" },
354
+ { element: "O", position: [-3.75, 5.06, 0], color: "#ff0000" }
355
+ ],
356
+ bonds: [
357
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 }, { from: 3, to: 4 },
358
+ { from: 4, to: 5 }, { from: 5, to: 0 }, { from: 1, to: 6 }, { from: 2, to: 7 },
359
+ { from: 3, to: 8 }, { from: 4, to: 9 }, { from: 9, to: 10 }, { from: 10, to: 11 }
360
+ ],
361
+ description: "The primary source of energy for cells, essential for metabolism in all living organisms."
362
+ },
363
+
364
+ // Inorganic Compounds
365
+ {
366
+ name: "Hydrogen Chloride (HCl)",
367
+ formula: "HCl",
368
+ category: "inorganic",
369
+ atoms: [
370
+ { element: "H", position: [-0.63, 0, 0], color: "#ffffff" },
371
+ { element: "Cl", position: [0.63, 0, 0], color: "#00ff00" }
372
+ ],
373
+ bonds: [{ from: 0, to: 1 }],
374
+ description: "A strong acid when dissolved in water (hydrochloric acid), found in stomach acid."
375
+ },
376
+ {
377
+ name: "Sodium Chloride (NaCl)",
378
+ formula: "NaCl",
379
+ category: "inorganic",
380
+ atoms: [
381
+ { element: "Na", position: [-1.4, 0, 0], color: "#ab5cf2" },
382
+ { element: "Cl", position: [1.4, 0, 0], color: "#00ff00" }
383
+ ],
384
+ bonds: [{ from: 0, to: 1 }],
385
+ description: "Common table salt, essential for life and widely used in food preservation."
386
+ },
387
+ {
388
+ name: "Sulfuric Acid (H₂SO₄)",
389
+ formula: "H2SO4",
390
+ category: "inorganic",
391
+ atoms: [
392
+ { element: "S", position: [0, 0, 0], color: "#ffff00" },
393
+ { element: "O", position: [0, 1.5, 0], color: "#ff0000" },
394
+ { element: "O", position: [1.3, -0.75, 0], color: "#ff0000" },
395
+ { element: "O", position: [-1.3, -0.75, 0], color: "#ff0000" },
396
+ { element: "O", position: [0, 0, 1.5], color: "#ff0000" },
397
+ { element: "H", position: [0, 2.4, 0], color: "#ffffff" },
398
+ { element: "H", position: [0, 0, 2.4], color: "#ffffff" }
399
+ ],
400
+ bonds: [
401
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 0, to: 4 },
402
+ { from: 1, to: 5 }, { from: 4, to: 6 }
403
+ ],
404
+ description: "One of the most important industrial chemicals, used in batteries and chemical synthesis."
405
+ },
406
+
407
+ // Pharmaceuticals
408
+ {
409
+ name: "Aspirin (C₉H₈O₄)",
410
+ formula: "C9H8O4",
411
+ category: "pharmaceuticals",
412
+ atoms: [
413
+ { element: "C", position: [0, 0, 0], color: "#404040" },
414
+ { element: "C", position: [1.4, 0, 0.8], color: "#404040" },
415
+ { element: "C", position: [1.4, 0, 2.2], color: "#404040" },
416
+ { element: "C", position: [0, 0, 3], color: "#404040" },
417
+ { element: "C", position: [-1.4, 0, 2.2], color: "#404040" },
418
+ { element: "C", position: [-1.4, 0, 0.8], color: "#404040" },
419
+ { element: "C", position: [0, 1.5, 4.5], color: "#404040" },
420
+ { element: "C", position: [-1.5, 1.5, 6], color: "#404040" },
421
+ { element: "O", position: [0, 0, 4.5], color: "#ff0000" },
422
+ { element: "O", position: [1.5, 1.5, 4.5], color: "#ff0000" },
423
+ { element: "O", position: [-3, 1.5, 6], color: "#ff0000" },
424
+ { element: "O", position: [-1.5, 3, 6], color: "#ff0000" }
425
+ ],
426
+ bonds: [
427
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 }, { from: 3, to: 4 },
428
+ { from: 4, to: 5 }, { from: 5, to: 0 }, { from: 3, to: 8 }, { from: 8, to: 6 },
429
+ { from: 6, to: 9 }, { from: 6, to: 7 }, { from: 7, to: 10 }, { from: 7, to: 11 }
430
+ ],
431
+ description: "A widely used pain reliever and anti-inflammatory drug, first synthesized in 1897."
432
+ },
433
+ {
434
+ name: "Caffeine (C₈H₁₀N₄O₂)",
435
+ formula: "C8H10N4O2",
436
+ category: "pharmaceuticals",
437
+ atoms: [
438
+ { element: "N", position: [0, 0, 0], color: "#0000ff" },
439
+ { element: "C", position: [1.4, 0, 0], color: "#404040" },
440
+ { element: "N", position: [2.1, 1.2, 0], color: "#0000ff" },
441
+ { element: "C", position: [1.4, 2.4, 0], color: "#404040" },
442
+ { element: "C", position: [0, 2.4, 0], color: "#404040" },
443
+ { element: "N", position: [-0.7, 1.2, 0], color: "#0000ff" },
444
+ { element: "C", position: [0, 3.8, 0], color: "#404040" },
445
+ { element: "N", position: [1.4, 3.8, 0], color: "#0000ff" },
446
+ { element: "O", position: [2.1, -1.2, 0], color: "#ff0000" },
447
+ { element: "O", position: [-0.7, 4.6, 0], color: "#ff0000" },
448
+ { element: "C", position: [-2.1, 1.2, 0], color: "#404040" },
449
+ { element: "C", position: [2.8, 4.6, 0], color: "#404040" },
450
+ { element: "C", position: [-0.7, -1.2, 0], color: "#404040" }
451
+ ],
452
+ bonds: [
453
+ { from: 0, to: 1 }, { from: 1, to: 2 }, { from: 2, to: 3 }, { from: 3, to: 4 },
454
+ { from: 4, to: 5 }, { from: 5, to: 0 }, { from: 4, to: 6 }, { from: 6, to: 7 },
455
+ { from: 7, to: 3 }, { from: 1, to: 8 }, { from: 6, to: 9 }, { from: 5, to: 10 },
456
+ { from: 7, to: 11 }, { from: 0, to: 12 }
457
+ ],
458
+ description: "A natural stimulant found in coffee, tea, and chocolate, widely consumed worldwide."
459
+ },
460
+
461
+ // Environmental/Atmospheric
462
+ {
463
+ name: "Ozone (O₃)",
464
+ formula: "O3",
465
+ category: "environmental",
466
+ atoms: [
467
+ { element: "O", position: [0, 0, 0], color: "#ff0000" },
468
+ { element: "O", position: [1.3, 0, 0], color: "#ff0000" },
469
+ { element: "O", position: [0.65, 1.13, 0], color: "#ff0000" }
470
+ ],
471
+ bonds: [{ from: 0, to: 1 }, { from: 1, to: 2 }],
472
+ description: "An atmospheric molecule that protects Earth from UV radiation but is toxic at ground level."
473
+ },
474
+ {
475
+ name: "Methyl Chloride (CH₃Cl)",
476
+ formula: "CH3Cl",
477
+ category: "environmental",
478
+ atoms: [
479
+ { element: "C", position: [0, 0, 0], color: "#404040" },
480
+ { element: "Cl", position: [1.78, 0, 0], color: "#00ff00" },
481
+ { element: "H", position: [-0.51, 0.89, 0.51], color: "#ffffff" },
482
+ { element: "H", position: [-0.51, -0.89, 0.51], color: "#ffffff" },
483
+ { element: "H", position: [-0.51, 0, -1.03], color: "#ffffff" }
484
+ ],
485
+ bonds: [
486
+ { from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 }, { from: 0, to: 4 }
487
+ ],
488
+ description: "A chlorinated compound that contributes to ozone depletion in the stratosphere."
489
+ },
490
+
491
+ // Additional Important Molecules
492
+ {
493
+ name: "Hydrogen Peroxide (H₂O₂)",
494
+ formula: "H2O2",
495
+ category: "simple",
496
+ atoms: [
497
+ { element: "O", position: [-0.74, 0, 0], color: "#ff0000" },
498
+ { element: "O", position: [0.74, 0, 0], color: "#ff0000" },
499
+ { element: "H", position: [-1.21, 0.93, 0], color: "#ffffff" },
500
+ { element: "H", position: [1.21, -0.93, 0], color: "#ffffff" }
501
+ ],
502
+ bonds: [{ from: 0, to: 1 }, { from: 0, to: 2 }, { from: 1, to: 3 }],
503
+ description: "A strong oxidizing agent used as disinfectant and bleaching agent."
504
+ },
505
+ {
506
+ name: "Nitrous Oxide (N₂O)",
507
+ formula: "N2O",
508
+ category: "simple",
509
+ atoms: [
510
+ { element: "N", position: [-1.13, 0, 0], color: "#0000ff" },
511
+ { element: "N", position: [0, 0, 0], color: "#0000ff" },
512
+ { element: "O", position: [1.19, 0, 0], color: "#ff0000" }
513
+ ],
514
+ bonds: [{ from: 0, to: 1 }, { from: 1, to: 2 }],
515
+ description: "Laughing gas, used as anesthetic and greenhouse gas contributing to climate change."
516
+ }
517
+ ];
518
+
519
+ const CATEGORIES = [
520
+ { value: "all", label: "All Categories", count: MOLECULES.length },
521
+ { value: "simple", label: "Simple Molecules", count: MOLECULES.filter(m => m.category === "simple").length },
522
+ { value: "hydrocarbons", label: "Hydrocarbons", count: MOLECULES.filter(m => m.category === "hydrocarbons").length },
523
+ { value: "aromatics", label: "Aromatics", count: MOLECULES.filter(m => m.category === "aromatics").length },
524
+ { value: "alcohols", label: "Alcohols", count: MOLECULES.filter(m => m.category === "alcohols").length },
525
+ { value: "acids", label: "Acids", count: MOLECULES.filter(m => m.category === "acids").length },
526
+ { value: "biomolecules", label: "Biomolecules", count: MOLECULES.filter(m => m.category === "biomolecules").length },
527
+ { value: "inorganic", label: "Inorganic", count: MOLECULES.filter(m => m.category === "inorganic").length },
528
+ { value: "pharmaceuticals", label: "Pharmaceuticals", count: MOLECULES.filter(m => m.category === "pharmaceuticals").length },
529
+ { value: "environmental", label: "Environmental", count: MOLECULES.filter(m => m.category === "environmental").length }
530
+ ];
531
+
532
+ const ThreeCanvas = ({ molecule, isAnimating }) => {
533
+ const mountRef = useRef(null);
534
+
535
+ useEffect(() => {
536
+ if (!molecule || !mountRef.current) return;
537
+
538
+ const currentMount = mountRef.current;
539
+
540
+ // Scene, Camera, Renderer
541
+ const scene = new THREE.Scene();
542
+ scene.background = new THREE.Color(0x1e293b); // slate-800
543
+ const camera = new THREE.PerspectiveCamera(75, currentMount.clientWidth / currentMount.clientHeight, 0.1, 1000);
544
+ camera.position.z = 5;
545
+
546
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
547
+ renderer.setSize(currentMount.clientWidth, currentMount.clientHeight);
548
+ currentMount.appendChild(renderer.domElement);
549
+
550
+ // Lights
551
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
552
+ scene.add(ambientLight);
553
+ const pointLight = new THREE.PointLight(0xffffff, 0.5);
554
+ pointLight.position.set(5, 5, 5);
555
+ scene.add(pointLight);
556
+
557
+ // Molecule Group
558
+ const moleculeGroup = new THREE.Group();
559
+ scene.add(moleculeGroup);
560
+
561
+ // Create Atoms
562
+ molecule.atoms.forEach(atom => {
563
+ const geometry = new THREE.SphereGeometry(atom.element === 'H' ? 0.2 : 0.4, 32, 32);
564
+ const material = new THREE.MeshStandardMaterial({ color: atom.color });
565
+ const sphere = new THREE.Mesh(geometry, material);
566
+ sphere.position.set(...atom.position);
567
+ moleculeGroup.add(sphere);
568
+ });
569
+
570
+ // Create Bonds
571
+ molecule.bonds?.forEach(bond => {
572
+ const start = new THREE.Vector3(...molecule.atoms[bond.from].position);
573
+ const end = new THREE.Vector3(...molecule.atoms[bond.to].position);
574
+ const path = new THREE.LineCurve3(start, end);
575
+ const geometry = new THREE.TubeGeometry(path, 1, 0.05, 8, false);
576
+ const material = new THREE.MeshStandardMaterial({ color: '#cccccc' });
577
+ const mesh = new THREE.Mesh(geometry, material);
578
+ moleculeGroup.add(mesh);
579
+ });
580
+
581
+ // Center the molecule
582
+ new THREE.Box3().setFromObject(moleculeGroup).getCenter(moleculeGroup.position).multiplyScalar(-1);
583
+
584
+ // Animation loop
585
+ let animationFrameId;
586
+ const animate = () => {
587
+ animationFrameId = requestAnimationFrame(animate);
588
+ if (isAnimating) {
589
+ moleculeGroup.rotation.y += 0.005;
590
+ moleculeGroup.rotation.x += 0.002;
591
+ }
592
+ renderer.render(scene, camera);
593
+ };
594
+ animate();
595
+
596
+ // Resize handler
597
+ const handleResize = () => {
598
+ if (!currentMount) return;
599
+ camera.aspect = currentMount.clientWidth / currentMount.clientHeight;
600
+ camera.updateProjectionMatrix();
601
+ renderer.setSize(currentMount.clientWidth, currentMount.clientHeight);
602
+ };
603
+ window.addEventListener('resize', handleResize);
604
+
605
+ // Cleanup
606
+ return () => {
607
+ window.removeEventListener('resize', handleResize);
608
+ if (currentMount.contains(renderer.domElement)) {
609
+ currentMount.removeChild(renderer.domElement);
610
+ }
611
+ cancelAnimationFrame(animationFrameId);
612
+ };
613
+ }, [molecule, isAnimating]);
614
+
615
+ return <div ref={mountRef} className="w-full h-full" />;
616
+ };
617
+
618
+ export default function MolecularViewer() {
619
+ const [selectedMolecule, setSelectedMolecule] = useState(MOLECULES[0]);
620
+ const [isAnimating, setIsAnimating] = useState(true);
621
+ const [searchTerm, setSearchTerm] = useState("");
622
+ const [selectedCategory, setSelectedCategory] = useState("all");
623
+
624
+ const filteredMolecules = MOLECULES.filter(mol => {
625
+ const matchesSearch = mol.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
626
+ mol.formula.toLowerCase().includes(searchTerm.toLowerCase());
627
+ const matchesCategory = selectedCategory === "all" || mol.category === selectedCategory;
628
+ return matchesSearch && matchesCategory;
629
+ });
630
+
631
+ return (
632
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-purple-50 p-4 md:p-8">
633
+ <div className="max-w-7xl mx-auto">
634
+ <div className="mb-8">
635
+ <div className="flex items-center gap-3 mb-4">
636
+ <div className="w-12 h-12 bg-gradient-to-br from-purple-600 to-pink-700 rounded-xl flex items-center justify-center">
637
+ <Atom className="w-6 h-6 text-white" />
638
+ </div>
639
+ <div>
640
+ <h1 className="text-3xl font-bold text-slate-900">3D Molecular Database</h1>
641
+ <p className="text-slate-600">Explore {MOLECULES.length} molecular structures in interactive 3D space</p>
642
+ </div>
643
+ </div>
644
+ </div>
645
+
646
+ <div className="grid lg:grid-cols-4 gap-8">
647
+ {/* Molecule Library */}
648
+ <div className="lg:col-span-1">
649
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
650
+ <CardHeader>
651
+ <CardTitle className="flex items-center gap-2 text-lg">
652
+ <Search className="w-5 h-5 text-purple-600" />
653
+ Molecule Library
654
+ </CardTitle>
655
+ </CardHeader>
656
+ <CardContent>
657
+ <div className="space-y-4">
658
+ <Input
659
+ placeholder="Search molecules..."
660
+ value={searchTerm}
661
+ onChange={(e) => setSearchTerm(e.target.value)}
662
+ className="bg-white"
663
+ />
664
+
665
+ <div>
666
+ <label className="block text-sm font-medium text-slate-700 mb-2">Category</label>
667
+ <Select value={selectedCategory} onValueChange={setSelectedCategory}>
668
+ <SelectTrigger className="bg-white">
669
+ <SelectValue />
670
+ </SelectTrigger>
671
+ <SelectContent>
672
+ {CATEGORIES.map((category) => (
673
+ <SelectItem key={category.value} value={category.value}>
674
+ {category.label} ({category.count})
675
+ </SelectItem>
676
+ ))}
677
+ </SelectContent>
678
+ </Select>
679
+ </div>
680
+
681
+ <div className="space-y-2 max-h-96 overflow-y-auto pr-2">
682
+ {filteredMolecules.map((molecule, index) => (
683
+ <button
684
+ key={index}
685
+ onClick={() => setSelectedMolecule(molecule)}
686
+ className={`w-full text-left p-3 rounded-lg border transition-all duration-200 ${
687
+ selectedMolecule?.name === molecule.name
688
+ ? 'border-purple-500 bg-purple-50'
689
+ : 'border-slate-200 hover:border-purple-300 hover:bg-purple-25'
690
+ }`}
691
+ >
692
+ <div className="font-medium text-slate-900 mb-1">
693
+ {molecule.name}
694
+ </div>
695
+ <div className="flex items-center justify-between">
696
+ <Badge variant="outline" className="text-xs">
697
+ {molecule.formula}
698
+ </Badge>
699
+ <Badge variant="secondary" className="text-xs capitalize">
700
+ {molecule.category}
701
+ </Badge>
702
+ </div>
703
+ </button>
704
+ ))}
705
+ {filteredMolecules.length === 0 && (
706
+ <div className="text-center py-8 text-slate-500">
707
+ <Search className="w-12 h-12 mx-auto mb-2 opacity-50" />
708
+ <p>No molecules found</p>
709
+ </div>
710
+ )}
711
+ </div>
712
+ </div>
713
+ </CardContent>
714
+ </Card>
715
+ </div>
716
+
717
+ {/* Main Viewer */}
718
+ <div className="lg:col-span-3">
719
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
720
+ <CardHeader>
721
+ <div className="flex items-center justify-between flex-wrap gap-4">
722
+ <CardTitle className="text-xl">
723
+ {selectedMolecule?.name}
724
+ </CardTitle>
725
+ <div className="flex items-center gap-2">
726
+ <Button
727
+ variant="outline"
728
+ size="icon"
729
+ onClick={() => setIsAnimating(!isAnimating)}
730
+ title={isAnimating ? "Pause Animation" : "Play Animation"}
731
+ >
732
+ {isAnimating ? (
733
+ <Pause className="w-4 h-4" />
734
+ ) : (
735
+ <Play className="w-4 h-4" />
736
+ )}
737
+ </Button>
738
+ </div>
739
+ </div>
740
+ </CardHeader>
741
+ <CardContent>
742
+ <Tabs defaultValue="viewer" className="w-full">
743
+ <TabsList className="grid w-full grid-cols-2 mb-6">
744
+ <TabsTrigger value="viewer">3D Viewer</TabsTrigger>
745
+ <TabsTrigger value="info">Molecule Info</TabsTrigger>
746
+ </TabsList>
747
+
748
+ <TabsContent value="viewer" className="space-y-0">
749
+ <div className="h-96 w-full bg-gradient-to-b from-slate-900 to-slate-800 rounded-xl overflow-hidden relative">
750
+ <ThreeCanvas molecule={selectedMolecule} isAnimating={isAnimating} />
751
+
752
+ <div className="absolute top-4 right-4">
753
+ <Badge className="bg-purple-600 text-white">
754
+ {selectedMolecule?.formula}
755
+ </Badge>
756
+ </div>
757
+ </div>
758
+ </TabsContent>
759
+
760
+ <TabsContent value="info" className="space-y-6">
761
+ <div className="grid md:grid-cols-2 gap-6">
762
+ <Card className="bg-gradient-to-br from-blue-50 to-indigo-50 border-blue-200">
763
+ <CardContent className="p-6">
764
+ <div className="flex items-center gap-2 mb-3">
765
+ <Info className="w-5 h-5 text-blue-600" />
766
+ <h3 className="font-semibold text-blue-900">Molecular Formula</h3>
767
+ </div>
768
+ <p className="text-2xl font-bold text-blue-800 font-mono">
769
+ {selectedMolecule?.formula}
770
+ </p>
771
+ </CardContent>
772
+ </Card>
773
+
774
+ <Card className="bg-gradient-to-br from-emerald-50 to-teal-50 border-emerald-200">
775
+ <CardContent className="p-6">
776
+ <div className="flex items-center gap-2 mb-3">
777
+ <Atom className="w-5 h-5 text-emerald-600" />
778
+ <h3 className="font-semibold text-emerald-900">Atom Count</h3>
779
+ </div>
780
+ <p className="text-2xl font-bold text-emerald-800">
781
+ {selectedMolecule?.atoms.length} atoms
782
+ </p>
783
+ </CardContent>
784
+ </Card>
785
+ </div>
786
+
787
+ <Card className="bg-gradient-to-br from-purple-50 to-pink-50 border-purple-200">
788
+ <CardContent className="p-6">
789
+ <div className="flex items-center gap-2 mb-3">
790
+ <Filter className="w-5 h-5 text-purple-600" />
791
+ <h3 className="font-semibold text-purple-900">Category</h3>
792
+ </div>
793
+ <Badge className="capitalize bg-purple-600 text-white text-lg px-3 py-1">
794
+ {selectedMolecule?.category}
795
+ </Badge>
796
+ </CardContent>
797
+ </Card>
798
+
799
+ <Card className="bg-slate-50 border-slate-200">
800
+ <CardHeader>
801
+ <CardTitle className="text-lg">Description</CardTitle>
802
+ </CardHeader>
803
+ <CardContent>
804
+ <p className="text-slate-700 leading-relaxed">
805
+ {selectedMolecule?.description}
806
+ </p>
807
+ </CardContent>
808
+ </Card>
809
+
810
+ {selectedMolecule?.atoms && (
811
+ <Card className="bg-slate-50 border-slate-200">
812
+ <CardHeader>
813
+ <CardTitle className="text-lg">Atomic Composition</CardTitle>
814
+ </CardHeader>
815
+ <CardContent>
816
+ <div className="space-y-3">
817
+ {Object.entries(
818
+ selectedMolecule.atoms.reduce((acc, atom) => {
819
+ acc[atom.element] = (acc[atom.element] || 0) + 1;
820
+ return acc;
821
+ }, {})
822
+ ).map(([element, count]) => (
823
+ <div key={element} className="flex items-center gap-3">
824
+ <div
825
+ className="w-8 h-8 rounded-full border-2 border-slate-300 flex items-center justify-center text-xs font-bold"
826
+ style={{
827
+ backgroundColor: selectedMolecule.atoms.find(a => a.element === element)?.color,
828
+ color: element === 'H' ? '#000' : '#fff'
829
+ }}
830
+ >
831
+ {element}
832
+ </div>
833
+ <span className="font-medium text-slate-900">{element}</span>
834
+ <span className="text-slate-600">× {count}</span>
835
+ </div>
836
+ ))}
837
+ </div>
838
+ </CardContent>
839
+ </Card>
840
+ )}
841
+ </TabsContent>
842
+ </Tabs>
843
+ </CardContent>
844
+ </Card>
845
+ </div>
846
+ </div>
847
+ </div>
848
+ </div>
849
+ );
850
+ }
Pages/Items/Prctice.txt ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React, { useState, useEffect } from "react";
3
+ import { Problem } from "@/entities/Problem";
4
+ import { StudySession } from "@/entities/StudySession";
5
+ import { User } from "@/entities/User";
6
+ import { InvokeLLM } from "@/integrations/Core";
7
+ import { Button } from "@/components/ui/button";
8
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
9
+ import { Badge } from "@/components/ui/badge";
10
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
11
+ import { Textarea } from "@/components/ui/textarea";
12
+ import { Alert, AlertDescription } from "@/components/ui/alert";
13
+ import {
14
+ Brain,
15
+ Lightbulb,
16
+ CheckCircle,
17
+ XCircle,
18
+ RefreshCw,
19
+ Sparkles,
20
+ Clock,
21
+ Target,
22
+ ChevronRight,
23
+ Atom,
24
+ BookOpen
25
+ } from "lucide-react";
26
+
27
+ const TOPICS = [
28
+ { value: "organic_chemistry", label: "Organic Chemistry" },
29
+ { value: "inorganic_chemistry", label: "Inorganic Chemistry" },
30
+ { value: "physical_chemistry", label: "Physical Chemistry" },
31
+ { value: "analytical_chemistry", label: "Analytical Chemistry" },
32
+ { value: "biochemistry", label: "Biochemistry" },
33
+ { value: "quantum_chemistry", label: "Quantum Chemistry" },
34
+ { value: "materials_science", label: "Materials Science" }
35
+ ];
36
+
37
+ const DIFFICULTIES = [
38
+ { value: "beginner", label: "Beginner", color: "bg-green-100 text-green-800" },
39
+ { value: "intermediate", label: "Intermediate", color: "bg-yellow-100 text-yellow-800" },
40
+ { value: "advanced", label: "Advanced", color: "bg-red-100 text-red-800" }
41
+ ];
42
+
43
+ export default function Practice() {
44
+ const [user, setUser] = useState(null);
45
+ const [currentProblem, setCurrentProblem] = useState(null);
46
+ const [userAnswer, setUserAnswer] = useState("");
47
+ const [showSolution, setShowSolution] = useState(false);
48
+ const [showHints, setShowHints] = useState(false);
49
+ const [hintIndex, setHintIndex] = useState(0);
50
+ const [isGenerating, setIsGenerating] = useState(false);
51
+ const [isSubmitting, setIsSubmitting] = useState(false);
52
+ const [sessionStartTime, setSessionStartTime] = useState(null);
53
+ const [selectedTopic, setSelectedTopic] = useState("");
54
+ const [selectedDifficulty, setSelectedDifficulty] = useState("");
55
+ const [score, setScore] = useState(null);
56
+
57
+ useEffect(() => {
58
+ loadUser();
59
+ }, []);
60
+
61
+ const loadUser = async () => {
62
+ try {
63
+ const userData = await User.me();
64
+ setUser(userData);
65
+ setSelectedDifficulty(userData.learning_level || "beginner");
66
+ } catch (error) {
67
+ await User.login();
68
+ }
69
+ };
70
+
71
+ const generateProblem = async () => {
72
+ if (!selectedTopic || !selectedDifficulty) return;
73
+
74
+ setIsGenerating(true);
75
+ setCurrentProblem(null);
76
+ setUserAnswer("");
77
+ setShowSolution(false);
78
+ setShowHints(false);
79
+ setHintIndex(0);
80
+ setScore(null);
81
+ setSessionStartTime(Date.now());
82
+
83
+ try {
84
+ const topicName = TOPICS.find(t => t.value === selectedTopic)?.label || selectedTopic;
85
+
86
+ const prompt = `Generate a ${selectedDifficulty} level chemistry problem in ${topicName}.
87
+
88
+ The problem should be educational, engaging, and appropriate for a student at the ${selectedDifficulty} level.
89
+
90
+ Include:
91
+ - A clear, specific problem statement
92
+ - Step-by-step solution with explanations
93
+ - 3 progressive hints to help students
94
+ - Key concepts being tested
95
+ - Molecular formula if applicable
96
+ - Brief molecular structure description if relevant
97
+
98
+ Make it practical and relatable to real-world chemistry applications.`;
99
+
100
+ const result = await InvokeLLM({
101
+ prompt,
102
+ response_json_schema: {
103
+ type: "object",
104
+ properties: {
105
+ title: { type: "string" },
106
+ question: { type: "string" },
107
+ solution: { type: "string" },
108
+ molecular_formula: { type: "string" },
109
+ molecular_structure: { type: "string" },
110
+ concepts: { type: "array", items: { type: "string" } },
111
+ hints: { type: "array", items: { type: "string" } }
112
+ },
113
+ required: ["title", "question", "solution", "concepts", "hints"]
114
+ }
115
+ });
116
+
117
+ const problemData = {
118
+ ...result,
119
+ topic: selectedTopic,
120
+ difficulty: selectedDifficulty
121
+ };
122
+
123
+ const savedProblem = await Problem.create(problemData);
124
+ setCurrentProblem(savedProblem);
125
+
126
+ } catch (error) {
127
+ console.error("Error generating problem:", error);
128
+ }
129
+ setIsGenerating(false);
130
+ };
131
+
132
+ const submitAnswer = async () => {
133
+ if (!currentProblem || !userAnswer.trim()) return;
134
+
135
+ setIsSubmitting(true);
136
+ const timeSpent = sessionStartTime ? Math.round((Date.now() - sessionStartTime) / 1000 / 60) : 0;
137
+
138
+ try {
139
+ // Use AI to evaluate the answer
140
+ const evaluation = await InvokeLLM({
141
+ prompt: `Evaluate this student's answer to a chemistry problem:
142
+
143
+ Problem: ${currentProblem.question}
144
+ Correct Solution: ${currentProblem.solution}
145
+ Student Answer: ${userAnswer}
146
+
147
+ Provide a score from 0-100 and brief feedback on their understanding.`,
148
+ response_json_schema: {
149
+ type: "object",
150
+ properties: {
151
+ score: { type: "number", minimum: 0, maximum: 100 },
152
+ feedback: { type: "string" },
153
+ is_correct: { type: "boolean" }
154
+ },
155
+ required: ["score", "feedback", "is_correct"]
156
+ }
157
+ });
158
+
159
+ setScore(evaluation);
160
+
161
+ // Save study session
162
+ await StudySession.create({
163
+ user_email: user.email,
164
+ problem_id: currentProblem.id,
165
+ completed: evaluation.is_correct,
166
+ time_spent: timeSpent,
167
+ hints_used: hintIndex,
168
+ score: evaluation.score,
169
+ session_date: new Date().toISOString().split('T')[0]
170
+ });
171
+
172
+ // Update user stats if correct
173
+ if (evaluation.is_correct) {
174
+ await User.updateMyUserData({
175
+ total_problems_solved: (user.total_problems_solved || 0) + 1
176
+ });
177
+ }
178
+
179
+ setShowSolution(true);
180
+
181
+ } catch (error) {
182
+ console.error("Error submitting answer:", error);
183
+ }
184
+ setIsSubmitting(false);
185
+ };
186
+
187
+ const nextHint = () => {
188
+ if (hintIndex < (currentProblem?.hints?.length || 0) - 1) {
189
+ setHintIndex(hintIndex + 1);
190
+ }
191
+ setShowHints(true);
192
+ };
193
+
194
+ return (
195
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 p-4 md:p-8">
196
+ <div className="max-w-4xl mx-auto">
197
+ <div className="mb-8">
198
+ <div className="flex items-center gap-3 mb-4">
199
+ <div className="w-12 h-12 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-xl flex items-center justify-center">
200
+ <Brain className="w-6 h-6 text-white" />
201
+ </div>
202
+ <div>
203
+ <h1 className="text-3xl font-bold text-slate-900">AI Practice Problems</h1>
204
+ <p className="text-slate-600">Personalized chemistry problems generated just for you</p>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ {/* Problem Generator */}
210
+ <Card className="border-0 shadow-xl bg-white/90 backdrop-blur-sm mb-8">
211
+ <CardHeader>
212
+ <CardTitle className="flex items-center gap-2">
213
+ <Sparkles className="w-5 h-5 text-amber-500" />
214
+ Generate New Problem
215
+ </CardTitle>
216
+ </CardHeader>
217
+ <CardContent>
218
+ <div className="grid md:grid-cols-2 gap-4 mb-6">
219
+ <div>
220
+ <label className="block text-sm font-medium text-slate-700 mb-2">Topic</label>
221
+ <Select value={selectedTopic} onValueChange={setSelectedTopic}>
222
+ <SelectTrigger className="bg-white">
223
+ <SelectValue placeholder="Choose a chemistry topic" />
224
+ </SelectTrigger>
225
+ <SelectContent>
226
+ {TOPICS.map((topic) => (
227
+ <SelectItem key={topic.value} value={topic.value}>
228
+ {topic.label}
229
+ </SelectItem>
230
+ ))}
231
+ </SelectContent>
232
+ </Select>
233
+ </div>
234
+ <div>
235
+ <label className="block text-sm font-medium text-slate-700 mb-2">Difficulty</label>
236
+ <Select value={selectedDifficulty} onValueChange={setSelectedDifficulty}>
237
+ <SelectTrigger className="bg-white">
238
+ <SelectValue placeholder="Select difficulty" />
239
+ </SelectTrigger>
240
+ <SelectContent>
241
+ {DIFFICULTIES.map((diff) => (
242
+ <SelectItem key={diff.value} value={diff.value}>
243
+ {diff.label}
244
+ </SelectItem>
245
+ ))}
246
+ </SelectContent>
247
+ </Select>
248
+ </div>
249
+ </div>
250
+ <Button
251
+ onClick={generateProblem}
252
+ disabled={!selectedTopic || !selectedDifficulty || isGenerating}
253
+ className="w-full bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 font-semibold py-3"
254
+ >
255
+ {isGenerating ? (
256
+ <>
257
+ <RefreshCw className="w-5 h-5 mr-2 animate-spin" />
258
+ Generating Problem...
259
+ </>
260
+ ) : (
261
+ <>
262
+ <Brain className="w-5 h-5 mr-2" />
263
+ Generate Problem
264
+ </>
265
+ )}
266
+ </Button>
267
+ </CardContent>
268
+ </Card>
269
+
270
+ {/* Current Problem */}
271
+ {currentProblem && (
272
+ <div className="space-y-6">
273
+ <Card className="border-0 shadow-xl bg-white/90 backdrop-blur-sm">
274
+ <CardHeader>
275
+ <div className="flex items-center justify-between flex-wrap gap-4">
276
+ <CardTitle className="text-xl">{currentProblem.title}</CardTitle>
277
+ <div className="flex gap-2">
278
+ <Badge className={DIFFICULTIES.find(d => d.value === currentProblem.difficulty)?.color}>
279
+ {currentProblem.difficulty}
280
+ </Badge>
281
+ <Badge variant="outline">
282
+ {TOPICS.find(t => t.value === currentProblem.topic)?.label}
283
+ </Badge>
284
+ </div>
285
+ </div>
286
+ </CardHeader>
287
+ <CardContent>
288
+ <div className="prose max-w-none mb-6">
289
+ <p className="text-lg leading-relaxed text-slate-700">{currentProblem.question}</p>
290
+ </div>
291
+
292
+ {currentProblem.molecular_formula && (
293
+ <div className="bg-slate-50 rounded-lg p-4 mb-6">
294
+ <div className="flex items-center gap-2 mb-2">
295
+ <Atom className="w-5 h-5 text-blue-600" />
296
+ <span className="font-medium text-slate-700">Molecular Formula:</span>
297
+ </div>
298
+ <code className="text-lg font-mono text-blue-700 bg-white px-3 py-1 rounded">
299
+ {currentProblem.molecular_formula}
300
+ </code>
301
+ </div>
302
+ )}
303
+
304
+ {currentProblem.concepts && (
305
+ <div className="mb-6">
306
+ <div className="flex items-center gap-2 mb-3">
307
+ <BookOpen className="w-5 h-5 text-purple-600" />
308
+ <span className="font-medium text-slate-700">Key Concepts:</span>
309
+ </div>
310
+ <div className="flex flex-wrap gap-2">
311
+ {currentProblem.concepts.map((concept, index) => (
312
+ <Badge key={index} variant="secondary" className="bg-purple-100 text-purple-800">
313
+ {concept}
314
+ </Badge>
315
+ ))}
316
+ </div>
317
+ </div>
318
+ )}
319
+
320
+ {!showSolution && (
321
+ <div className="space-y-4">
322
+ <div>
323
+ <label className="block text-sm font-medium text-slate-700 mb-2">
324
+ Your Answer:
325
+ </label>
326
+ <Textarea
327
+ value={userAnswer}
328
+ onChange={(e) => setUserAnswer(e.target.value)}
329
+ placeholder="Write your solution step by step..."
330
+ className="min-h-32 bg-white"
331
+ />
332
+ </div>
333
+
334
+ <div className="flex gap-3 flex-wrap">
335
+ <Button
336
+ onClick={submitAnswer}
337
+ disabled={!userAnswer.trim() || isSubmitting}
338
+ className="bg-emerald-600 hover:bg-emerald-700"
339
+ >
340
+ {isSubmitting ? (
341
+ <>
342
+ <RefreshCw className="w-4 h-4 mr-2 animate-spin" />
343
+ Evaluating...
344
+ </>
345
+ ) : (
346
+ <>
347
+ <CheckCircle className="w-4 h-4 mr-2" />
348
+ Submit Answer
349
+ </>
350
+ )}
351
+ </Button>
352
+
353
+ {currentProblem.hints && hintIndex < currentProblem.hints.length && (
354
+ <Button onClick={nextHint} variant="outline">
355
+ <Lightbulb className="w-4 h-4 mr-2" />
356
+ Get Hint ({hintIndex + 1}/{currentProblem.hints.length})
357
+ </Button>
358
+ )}
359
+ </div>
360
+ </div>
361
+ )}
362
+
363
+ {/* Hints */}
364
+ {showHints && currentProblem.hints && (
365
+ <Card className="bg-amber-50 border-amber-200">
366
+ <CardContent className="p-4">
367
+ <div className="flex items-start gap-3">
368
+ <Lightbulb className="w-5 h-5 text-amber-600 mt-0.5" />
369
+ <div>
370
+ <p className="font-medium text-amber-900 mb-2">Hint {hintIndex + 1}:</p>
371
+ <p className="text-amber-800">{currentProblem.hints[hintIndex]}</p>
372
+ </div>
373
+ </div>
374
+ </CardContent>
375
+ </Card>
376
+ )}
377
+
378
+ {/* Results */}
379
+ {score && showSolution && (
380
+ <div className="space-y-4 mt-6">
381
+ <Alert className={score.is_correct ? "border-emerald-200 bg-emerald-50" : "border-amber-200 bg-amber-50"}>
382
+ <div className="flex items-center gap-2">
383
+ {score.is_correct ? (
384
+ <CheckCircle className="w-5 h-5 text-emerald-600" />
385
+ ) : (
386
+ <Target className="w-5 h-5 text-amber-600" />
387
+ )}
388
+ <div>
389
+ <h4 className={`font-semibold ${score.is_correct ? 'text-emerald-900' : 'text-amber-900'}`}>
390
+ Score: {score.score}/100
391
+ </h4>
392
+ <AlertDescription className={score.is_correct ? 'text-emerald-800' : 'text-amber-800'}>
393
+ {score.feedback}
394
+ </AlertDescription>
395
+ </div>
396
+ </div>
397
+ </Alert>
398
+
399
+ <Card className="bg-slate-50 border-slate-200">
400
+ <CardHeader>
401
+ <CardTitle className="text-lg flex items-center gap-2">
402
+ <BookOpen className="w-5 h-5 text-blue-600" />
403
+ Complete Solution
404
+ </CardTitle>
405
+ </CardHeader>
406
+ <CardContent>
407
+ <div className="prose max-w-none text-slate-700">
408
+ {currentProblem.solution.split('\n').map((line, index) => (
409
+ <p key={index} className="mb-2">{line}</p>
410
+ ))}
411
+ </div>
412
+ </CardContent>
413
+ </Card>
414
+ </div>
415
+ )}
416
+ </CardContent>
417
+ </Card>
418
+ </div>
419
+ )}
420
+
421
+ {/* Empty State */}
422
+ {!currentProblem && !isGenerating && (
423
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
424
+ <CardContent className="text-center py-12">
425
+ <Brain className="w-16 h-16 mx-auto text-slate-400 mb-4" />
426
+ <h3 className="text-xl font-semibold text-slate-900 mb-2">Ready to Practice?</h3>
427
+ <p className="text-slate-600 mb-6">
428
+ Select a topic and difficulty level above to generate your first AI-powered chemistry problem!
429
+ </p>
430
+ </CardContent>
431
+ </Card>
432
+ )}
433
+ </div>
434
+ </div>
435
+ );
436
+ }
Pages/Items/Study_Material.txt ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React, { useState, useEffect } from "react";
3
+ import { User } from "@/entities/User";
4
+ import { InvokeLLM } from "@/integrations/Core";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
8
+ import { Badge } from "@/components/ui/badge";
9
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
10
+ import { Alert, AlertDescription } from "@/components/ui/alert";
11
+ import {
12
+ BookOpen,
13
+ FileText,
14
+ Lightbulb,
15
+ RefreshCw,
16
+ Download,
17
+ Sparkles,
18
+ GraduationCap,
19
+ Target,
20
+ Brain,
21
+ CheckCircle
22
+ } from "lucide-react";
23
+
24
+ const TOPICS = [
25
+ { value: "organic_chemistry", label: "Organic Chemistry", icon: "🧪", color: "bg-green-100 text-green-800" },
26
+ { value: "inorganic_chemistry", label: "Inorganic Chemistry", icon: "⚛️", color: "bg-blue-100 text-blue-800" },
27
+ { value: "physical_chemistry", label: "Physical Chemistry", icon: "🔬", color: "bg-purple-100 text-purple-800" },
28
+ { value: "analytical_chemistry", label: "Analytical Chemistry", icon: "📊", color: "bg-orange-100 text-orange-800" },
29
+ { value: "biochemistry", label: "Biochemistry", icon: "🧬", color: "bg-pink-100 text-pink-800" },
30
+ { value: "quantum_chemistry", label: "Quantum Chemistry", icon: "⚡", color: "bg-indigo-100 text-indigo-800" },
31
+ { value: "materials_science", label: "Materials Science", icon: "🏗️", color: "bg-cyan-100 text-cyan-800" }
32
+ ];
33
+
34
+ const MATERIAL_TYPES = [
35
+ { value: "study_guide", label: "Study Guide", icon: BookOpen, description: "Comprehensive topic overview" },
36
+ { value: "flashcards", label: "Flashcards", icon: Brain, description: "Key terms and definitions" },
37
+ { value: "practice_problems", label: "Practice Problems", icon: Target, description: "Problems with solutions" },
38
+ { value: "concept_map", label: "Concept Map", icon: Lightbulb, description: "Visual concept connections" }
39
+ ];
40
+
41
+ export default function StudyMaterials() {
42
+ const [user, setUser] = useState(null);
43
+ const [selectedTopic, setSelectedTopic] = useState("");
44
+ const [selectedType, setSelectedType] = useState("");
45
+ const [generatedMaterial, setGeneratedMaterial] = useState(null);
46
+ const [isGenerating, setIsGenerating] = useState(false);
47
+
48
+ useEffect(() => {
49
+ loadUser();
50
+ }, []);
51
+
52
+ const loadUser = async () => {
53
+ try {
54
+ const userData = await User.me();
55
+ setUser(userData);
56
+ } catch (error) {
57
+ await User.login();
58
+ }
59
+ };
60
+
61
+ const generateMaterial = async () => {
62
+ if (!selectedTopic || !selectedType) return;
63
+
64
+ setIsGenerating(true);
65
+ setGeneratedMaterial(null);
66
+
67
+ try {
68
+ const topic = TOPICS.find(t => t.value === selectedTopic);
69
+ const materialType = MATERIAL_TYPES.find(t => t.value === selectedType);
70
+
71
+ let prompt = "";
72
+ let schema = {};
73
+
74
+ switch (selectedType) {
75
+ case "study_guide":
76
+ prompt = `Create a comprehensive study guide for ${topic.label} suitable for a ${user?.learning_level || 'beginner'} level student. Include:
77
+ - Overview and importance
78
+ - Key concepts with clear explanations
79
+ - Important formulas or reactions
80
+ - Real-world applications
81
+ - Common misconceptions
82
+ - Study tips and memory aids`;
83
+
84
+ schema = {
85
+ type: "object",
86
+ properties: {
87
+ title: { type: "string" },
88
+ overview: { type: "string" },
89
+ key_concepts: {
90
+ type: "array",
91
+ items: {
92
+ type: "object",
93
+ properties: {
94
+ concept: { type: "string" },
95
+ explanation: { type: "string" }
96
+ }
97
+ }
98
+ },
99
+ formulas: { type: "array", items: { type: "string" } },
100
+ applications: { type: "array", items: { type: "string" } },
101
+ misconceptions: { type: "array", items: { type: "string" } },
102
+ study_tips: { type: "array", items: { type: "string" } }
103
+ }
104
+ };
105
+ break;
106
+
107
+ case "flashcards":
108
+ prompt = `Create 15-20 flashcards for ${topic.label} at ${user?.learning_level || 'beginner'} level. Each flashcard should have:
109
+ - A clear, concise question or term
110
+ - A comprehensive answer or definition
111
+ - Include key formulas, reactions, or concepts`;
112
+
113
+ schema = {
114
+ type: "object",
115
+ properties: {
116
+ title: { type: "string" },
117
+ cards: {
118
+ type: "array",
119
+ items: {
120
+ type: "object",
121
+ properties: {
122
+ front: { type: "string" },
123
+ back: { type: "string" }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ };
129
+ break;
130
+
131
+ case "practice_problems":
132
+ prompt = `Create 8-10 practice problems for ${topic.label} at ${user?.learning_level || 'beginner'} level. Include:
133
+ - Varied difficulty within the level
134
+ - Step-by-step solutions
135
+ - Brief explanations of key concepts used`;
136
+
137
+ schema = {
138
+ type: "object",
139
+ properties: {
140
+ title: { type: "string" },
141
+ problems: {
142
+ type: "array",
143
+ items: {
144
+ type: "object",
145
+ properties: {
146
+ question: { type: "string" },
147
+ solution: { type: "string" },
148
+ concepts_used: { type: "array", items: { type: "string" } }
149
+ }
150
+ }
151
+ }
152
+ }
153
+ };
154
+ break;
155
+
156
+ case "concept_map":
157
+ prompt = `Create a concept map structure for ${topic.label} at ${user?.learning_level || 'beginner'} level showing:
158
+ - Main concepts and their relationships
159
+ - Hierarchical organization
160
+ - Key connections between ideas
161
+ - Brief descriptions for each concept`;
162
+
163
+ schema = {
164
+ type: "object",
165
+ properties: {
166
+ title: { type: "string" },
167
+ main_concept: { type: "string" },
168
+ concepts: {
169
+ type: "array",
170
+ items: {
171
+ type: "object",
172
+ properties: {
173
+ name: { type: "string" },
174
+ description: { type: "string" },
175
+ level: { type: "number" },
176
+ connections: { type: "array", items: { type: "string" } }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ };
182
+ break;
183
+ }
184
+
185
+ const result = await InvokeLLM({
186
+ prompt,
187
+ response_json_schema: schema
188
+ });
189
+
190
+ setGeneratedMaterial({
191
+ type: selectedType,
192
+ topic: selectedTopic,
193
+ data: result
194
+ });
195
+
196
+ } catch (error) {
197
+ console.error("Error generating material:", error);
198
+ }
199
+ setIsGenerating(false);
200
+ };
201
+
202
+ const downloadMaterial = () => {
203
+ if (!generatedMaterial) return;
204
+
205
+ let content = "";
206
+ const { data } = generatedMaterial;
207
+
208
+ switch (generatedMaterial.type) {
209
+ case "study_guide":
210
+ content = `${data.title}\n\n`;
211
+ content += `Overview:\n${data.overview}\n\n`;
212
+ if (data.key_concepts) {
213
+ content += "Key Concepts:\n";
214
+ data.key_concepts.forEach(concept => {
215
+ content += `- ${concept.concept}: ${concept.explanation}\n`;
216
+ });
217
+ content += "\n";
218
+ }
219
+ if (data.formulas && data.formulas.length > 0) {
220
+ content += "Important Formulas/Reactions:\n";
221
+ data.formulas.forEach(formula => {
222
+ content += `- ${formula}\n`;
223
+ });
224
+ content += "\n";
225
+ }
226
+ if (data.applications && data.applications.length > 0) {
227
+ content += "Real-world Applications:\n";
228
+ data.applications.forEach(app => {
229
+ content += `- ${app}\n`;
230
+ });
231
+ content += "\n";
232
+ }
233
+ if (data.misconceptions && data.misconceptions.length > 0) {
234
+ content += "Common Misconceptions:\n";
235
+ data.misconceptions.forEach(misconception => {
236
+ content += `- ${misconception}\n`;
237
+ });
238
+ content += "\n";
239
+ }
240
+ if (data.study_tips && data.study_tips.length > 0) {
241
+ content += "Study Tips:\n";
242
+ data.study_tips.forEach(tip => {
243
+ content += `- ${tip}\n`;
244
+ });
245
+ content += "\n";
246
+ }
247
+ break;
248
+ case "flashcards":
249
+ content = `${data.title}\n\nFlashcards:\n\n`;
250
+ data.cards?.forEach((card, index) => {
251
+ content += `Card ${index + 1}:\nQ: ${card.front}\nA: ${card.back}\n\n`;
252
+ });
253
+ break;
254
+ case "practice_problems":
255
+ content = `${data.title}\n\nPractice Problems:\n\n`;
256
+ data.problems?.forEach((problem, index) => {
257
+ content += `Problem ${index + 1}:\nQuestion: ${problem.question}\nSolution: ${problem.solution}\nConcepts Used: ${problem.concepts_used?.join(', ')}\n\n`;
258
+ });
259
+ break;
260
+ case "concept_map":
261
+ content = `${data.title}\n\nMain Concept: ${data.main_concept}\n\n`;
262
+ content += "Concepts:\n";
263
+ data.concepts?.forEach(concept => {
264
+ content += `- Name: ${concept.name}\n Description: ${concept.description}\n Level: ${concept.level}\n Connections: ${concept.connections?.join(', ')}\n\n`;
265
+ });
266
+ break;
267
+ }
268
+
269
+ const blob = new Blob([content], { type: 'text/plain' });
270
+ const url = URL.createObjectURL(blob);
271
+ const a = document.createElement('a');
272
+ a.href = url;
273
+ a.download = `${data.title.replace(/\s+/g, '_').replace(/[^a-zA-Z0-9_.]/g, '')}.txt`; // Sanitize filename
274
+ document.body.appendChild(a);
275
+ a.click();
276
+ document.body.removeChild(a);
277
+ URL.revokeObjectURL(url);
278
+ };
279
+
280
+ const renderMaterial = () => {
281
+ if (!generatedMaterial) return null;
282
+
283
+ const { data, type } = generatedMaterial;
284
+
285
+ switch (type) {
286
+ case "study_guide":
287
+ return (
288
+ <div className="space-y-6">
289
+ <Card className="bg-gradient-to-br from-blue-50 to-indigo-50 border-blue-200">
290
+ <CardHeader>
291
+ <CardTitle className="text-2xl">{data.title}</CardTitle>
292
+ </CardHeader>
293
+ <CardContent>
294
+ <p className="text-lg text-slate-700 leading-relaxed">{data.overview}</p>
295
+ </CardContent>
296
+ </Card>
297
+
298
+ {data.key_concepts && data.key_concepts.length > 0 && (
299
+ <Card>
300
+ <CardHeader>
301
+ <CardTitle className="flex items-center gap-2">
302
+ <Lightbulb className="w-5 h-5 text-amber-500" />
303
+ Key Concepts
304
+ </CardTitle>
305
+ </CardHeader>
306
+ <CardContent>
307
+ <div className="space-y-4">
308
+ {data.key_concepts.map((concept, index) => (
309
+ <div key={index} className="p-4 bg-slate-50 rounded-lg">
310
+ <h4 className="font-semibold text-slate-900 mb-2">{concept.concept}</h4>
311
+ <p className="text-slate-700">{concept.explanation}</p>
312
+ </div>
313
+ ))}
314
+ </div>
315
+ </CardContent>
316
+ </Card>
317
+ )}
318
+
319
+ {data.formulas && data.formulas.length > 0 && (
320
+ <Card>
321
+ <CardHeader>
322
+ <CardTitle className="flex items-center gap-2">
323
+ <FileText className="w-5 h-5 text-red-500" />
324
+ Important Formulas/Reactions
325
+ </CardTitle>
326
+ </CardHeader>
327
+ <CardContent>
328
+ <ul className="list-disc list-inside space-y-2">
329
+ {data.formulas.map((formula, index) => (
330
+ <li key={index} className="text-slate-700">{formula}</li>
331
+ ))}
332
+ </ul>
333
+ </CardContent>
334
+ </Card>
335
+ )}
336
+
337
+ {data.applications && data.applications.length > 0 && (
338
+ <Card>
339
+ <CardHeader>
340
+ <CardTitle className="flex items-center gap-2">
341
+ <Target className="w-5 h-5 text-orange-500" />
342
+ Real-world Applications
343
+ </CardTitle>
344
+ </CardHeader>
345
+ <CardContent>
346
+ <ul className="list-disc list-inside space-y-2">
347
+ {data.applications.map((app, index) => (
348
+ <li key={index} className="text-slate-700">{app}</li>
349
+ ))}
350
+ </ul>
351
+ </CardContent>
352
+ </Card>
353
+ )}
354
+
355
+ {data.misconceptions && data.misconceptions.length > 0 && (
356
+ <Card>
357
+ <CardHeader>
358
+ <CardTitle className="flex items-center gap-2">
359
+ <Lightbulb className="w-5 h-5 text-purple-500" />
360
+ Common Misconceptions
361
+ </CardTitle>
362
+ </CardHeader>
363
+ <CardContent>
364
+ <ul className="list-disc list-inside space-y-2">
365
+ {data.misconceptions.map((misconception, index) => (
366
+ <li key={index} className="text-slate-700">{misconception}</li>
367
+ ))}
368
+ </ul>
369
+ </CardContent>
370
+ </Card>
371
+ )}
372
+
373
+ {data.study_tips && data.study_tips.length > 0 && (
374
+ <Card>
375
+ <CardHeader>
376
+ <CardTitle className="flex items-center gap-2">
377
+ <GraduationCap className="w-5 h-5 text-emerald-500" />
378
+ Study Tips
379
+ </CardTitle>
380
+ </CardHeader>
381
+ <CardContent>
382
+ <ul className="space-y-2">
383
+ {data.study_tips.map((tip, index) => (
384
+ <li key={index} className="flex items-start gap-3">
385
+ <CheckCircle className="w-5 h-5 text-emerald-500 mt-0.5 flex-shrink-0" />
386
+ <span className="text-slate-700">{tip}</span>
387
+ </li>
388
+ ))}
389
+ </ul>
390
+ </CardContent>
391
+ </Card>
392
+ )}
393
+ </div>
394
+ );
395
+
396
+ case "flashcards":
397
+ return (
398
+ <div className="space-y-6">
399
+ <Card className="bg-gradient-to-br from-purple-50 to-pink-50 border-purple-200">
400
+ <CardHeader>
401
+ <CardTitle className="text-2xl">{data.title}</CardTitle>
402
+ <p className="text-slate-600">{data.cards?.length} flashcards</p>
403
+ </CardHeader>
404
+ </Card>
405
+
406
+ <div className="grid md:grid-cols-2 gap-4">
407
+ {data.cards?.map((card, index) => (
408
+ <Card key={index} className="hover:shadow-lg transition-shadow">
409
+ <CardContent className="p-6">
410
+ <div className="text-center">
411
+ <Badge className="mb-4">Card {index + 1}</Badge>
412
+ <div className="space-y-4">
413
+ <div>
414
+ <h4 className="font-medium text-slate-600 mb-2">Question:</h4>
415
+ <p className="font-semibold text-slate-900">{card.front}</p>
416
+ </div>
417
+ <div className="border-t pt-4">
418
+ <h4 className="font-medium text-slate-600 mb-2">Answer:</h4>
419
+ <p className="text-slate-800">{card.back}</p>
420
+ </div>
421
+ </div>
422
+ </div>
423
+ </CardContent>
424
+ </Card>
425
+ ))}
426
+ </div>
427
+ </div>
428
+ );
429
+
430
+ case "practice_problems":
431
+ return (
432
+ <div className="space-y-6">
433
+ <Card className="bg-gradient-to-br from-teal-50 to-emerald-50 border-teal-200">
434
+ <CardHeader>
435
+ <CardTitle className="text-2xl">{data.title}</CardTitle>
436
+ <p className="text-slate-600">{data.problems?.length} practice problems</p>
437
+ </CardHeader>
438
+ </Card>
439
+
440
+ <div className="space-y-4">
441
+ {data.problems?.map((problem, index) => (
442
+ <Card key={index} className="hover:shadow-lg transition-shadow">
443
+ <CardContent className="p-6">
444
+ <div className="space-y-4">
445
+ <div>
446
+ <h4 className="font-medium text-slate-600 mb-2">Problem {index + 1}:</h4>
447
+ <p className="font-semibold text-slate-900">{problem.question}</p>
448
+ </div>
449
+ <div className="border-t pt-4">
450
+ <h4 className="font-medium text-slate-600 mb-2">Solution:</h4>
451
+ <p className="text-slate-800 whitespace-pre-wrap">{problem.solution}</p>
452
+ </div>
453
+ {problem.concepts_used && problem.concepts_used.length > 0 && (
454
+ <div className="border-t pt-4">
455
+ <h4 className="font-medium text-slate-600 mb-2">Concepts Used:</h4>
456
+ <div className="flex flex-wrap gap-2">
457
+ {problem.concepts_used.map((concept, idx) => (
458
+ <Badge key={idx} variant="outline" className="bg-blue-50 text-blue-700">{concept}</Badge>
459
+ ))}
460
+ </div>
461
+ </div>
462
+ )}
463
+ </div>
464
+ </CardContent>
465
+ </Card>
466
+ ))}
467
+ </div>
468
+ </div>
469
+ );
470
+
471
+ case "concept_map":
472
+ return (
473
+ <div className="space-y-6">
474
+ <Card className="bg-gradient-to-br from-yellow-50 to-orange-50 border-yellow-200">
475
+ <CardHeader>
476
+ <CardTitle className="text-2xl">{data.title}</CardTitle>
477
+ <p className="text-slate-600">Main Concept: <span className="font-medium">{data.main_concept}</span></p>
478
+ </CardHeader>
479
+ </Card>
480
+
481
+ {data.concepts && data.concepts.length > 0 && (
482
+ <Card>
483
+ <CardHeader>
484
+ <CardTitle className="flex items-center gap-2">
485
+ <Lightbulb className="w-5 h-5 text-amber-500" />
486
+ Related Concepts
487
+ </CardTitle>
488
+ </CardHeader>
489
+ <CardContent>
490
+ <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
491
+ {data.concepts.map((concept, index) => (
492
+ <Card key={index} className="p-4 bg-slate-50 rounded-lg shadow-sm">
493
+ <h4 className="font-semibold text-slate-900 mb-2">{concept.name}</h4>
494
+ <p className="text-sm text-slate-700 mb-2">{concept.description}</p>
495
+ {concept.connections && concept.connections.length > 0 && (
496
+ <div className="mt-2">
497
+ <span className="font-medium text-xs text-slate-600">Connections: </span>
498
+ <div className="flex flex-wrap gap-1">
499
+ {concept.connections.map((conn, idx) => (
500
+ <Badge key={idx} variant="secondary" className="text-xs">{conn}</Badge>
501
+ ))}
502
+ </div>
503
+ </div>
504
+ )}
505
+ </Card>
506
+ ))}
507
+ </div>
508
+ </CardContent>
509
+ </Card>
510
+ )}
511
+ </div>
512
+ );
513
+
514
+ default:
515
+ return (
516
+ <Alert>
517
+ <AlertDescription>
518
+ Material type not yet implemented for display.
519
+ </AlertDescription>
520
+ </Alert>
521
+ );
522
+ }
523
+ };
524
+
525
+ return (
526
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-emerald-50 p-4 md:p-8">
527
+ <div className="max-w-6xl mx-auto">
528
+ <div className="mb-8">
529
+ <div className="flex items-center gap-3 mb-4">
530
+ <div className="w-12 h-12 bg-gradient-to-br from-emerald-600 to-teal-700 rounded-xl flex items-center justify-center">
531
+ <BookOpen className="w-6 h-6 text-white" />
532
+ </div>
533
+ <div>
534
+ <h1 className="text-3xl font-bold text-slate-900">AI Study Materials</h1>
535
+ <p className="text-slate-600">Generate personalized learning resources with AI</p>
536
+ </div>
537
+ </div>
538
+ </div>
539
+
540
+ {/* Material Generator */}
541
+ <Card className="border-0 shadow-xl bg-white/90 backdrop-blur-sm mb-8">
542
+ <CardHeader>
543
+ <CardTitle className="flex items-center gap-2">
544
+ <Sparkles className="w-5 h-5 text-amber-500" />
545
+ Generate Study Material
546
+ </CardTitle>
547
+ </CardHeader>
548
+ <CardContent>
549
+ <div className="grid md:grid-cols-2 gap-6 mb-6">
550
+ <div>
551
+ <label className="block text-sm font-medium text-slate-700 mb-3">Chemistry Topic</label>
552
+ <div className="grid grid-cols-2 gap-2">
553
+ {TOPICS.map((topic) => (
554
+ <button
555
+ key={topic.value}
556
+ onClick={() => setSelectedTopic(topic.value)}
557
+ className={`p-3 text-left rounded-lg border transition-all duration-200 ${
558
+ selectedTopic === topic.value
559
+ ? 'border-emerald-500 bg-emerald-50'
560
+ : 'border-slate-200 hover:border-emerald-300'
561
+ }`}
562
+ >
563
+ <div className="text-lg mb-1">{topic.icon}</div>
564
+ <div className="text-sm font-medium text-slate-900">{topic.label}</div>
565
+ </button>
566
+ ))}
567
+ </div>
568
+ </div>
569
+
570
+ <div>
571
+ <label className="block text-sm font-medium text-slate-700 mb-3">Material Type</label>
572
+ <div className="space-y-2">
573
+ {MATERIAL_TYPES.map((type) => (
574
+ <button
575
+ key={type.value}
576
+ onClick={() => setSelectedType(type.value)}
577
+ className={`w-full p-4 text-left rounded-lg border transition-all duration-200 ${
578
+ selectedType === type.value
579
+ ? 'border-emerald-500 bg-emerald-50'
580
+ : 'border-slate-200 hover:border-emerald-300'
581
+ }`}
582
+ >
583
+ <div className="flex items-center gap-3">
584
+ <type.icon className="w-5 h-5 text-emerald-600" />
585
+ <div>
586
+ <div className="font-medium text-slate-900">{type.label}</div>
587
+ <div className="text-sm text-slate-500">{type.description}</div>
588
+ </div>
589
+ </div>
590
+ </button>
591
+ ))}
592
+ </div>
593
+ </div>
594
+ </div>
595
+
596
+ <Button
597
+ onClick={generateMaterial}
598
+ disabled={!selectedTopic || !selectedType || isGenerating}
599
+ className="w-full bg-gradient-to-r from-emerald-600 to-teal-700 hover:from-emerald-700 hover:to-teal-800 font-semibold py-3"
600
+ >
601
+ {isGenerating ? (
602
+ <>
603
+ <RefreshCw className="w-5 h-5 mr-2 animate-spin" />
604
+ Generating Material...
605
+ </>
606
+ ) : (
607
+ <>
608
+ <Brain className="w-5 h-5 mr-2" />
609
+ Generate Study Material
610
+ </>
611
+ )}
612
+ </Button>
613
+ </CardContent>
614
+ </Card>
615
+
616
+ {/* Generated Material */}
617
+ {generatedMaterial && (
618
+ <Card className="border-0 shadow-xl bg-white/90 backdrop-blur-sm">
619
+ <CardHeader>
620
+ <div className="flex items-center justify-between flex-wrap gap-4">
621
+ <div>
622
+ <CardTitle className="text-xl">Generated Material</CardTitle>
623
+ <div className="flex gap-2 mt-2">
624
+ <Badge className={TOPICS.find(t => t.value === generatedMaterial.topic)?.color}>
625
+ {TOPICS.find(t => t.value === generatedMaterial.topic)?.label}
626
+ </Badge>
627
+ <Badge variant="outline">
628
+ {MATERIAL_TYPES.find(t => t.value === generatedMaterial.type)?.label}
629
+ </Badge>
630
+ </div>
631
+ </div>
632
+ <Button onClick={downloadMaterial} variant="outline">
633
+ <Download className="w-4 h-4 mr-2" />
634
+ Download
635
+ </Button>
636
+ </div>
637
+ </CardHeader>
638
+ <CardContent>
639
+ {renderMaterial()}
640
+ </CardContent>
641
+ </Card>
642
+ )}
643
+
644
+ {/* Empty State */}
645
+ {!generatedMaterial && !isGenerating && (
646
+ <Card className="border-0 shadow-xl bg-white/80 backdrop-blur-sm">
647
+ <CardContent className="text-center py-12">
648
+ <BookOpen className="w-16 h-16 mx-auto text-slate-400 mb-4" />
649
+ <h3 className="text-xl font-semibold text-slate-900 mb-2">Ready to Study?</h3>
650
+ <p className="text-slate-600 mb-6">
651
+ Select a chemistry topic and material type above to generate personalized study materials!
652
+ </p>
653
+ </CardContent>
654
+ </Card>
655
+ )}
656
+ </div>
657
+ </div>
658
+ );
659
+ }