malikm commited on
Commit
61fdb09
Β·
verified Β·
1 Parent(s): 24ad403

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +5 -3
  2. index.html +1634 -19
  3. prompts.txt +3 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Wjec Revision Dashboard
3
- emoji: πŸ“š
4
  colorFrom: blue
5
  colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: wjec-revision-dashboard
3
+ emoji: 🐳
4
  colorFrom: blue
5
  colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1634 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="light">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>WJEC A-Level Revision Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ .radar-chart-container {
12
+ position: relative;
13
+ height: 300px;
14
+ width: 100%;
15
+ }
16
+
17
+ .task-progress {
18
+ transition: width 0.5s ease-in-out;
19
+ }
20
+
21
+ .dark .dark\:bg-gray-800 {
22
+ background-color: #1f2937;
23
+ }
24
+
25
+ .dark .dark\:bg-gray-700 {
26
+ background-color: #374151;
27
+ }
28
+
29
+ .dark .dark\:text-white {
30
+ color: #f9fafb;
31
+ }
32
+
33
+ .dark .dark\:border-gray-600 {
34
+ border-color: #4b5563;
35
+ }
36
+
37
+ .profile-icon {
38
+ background: linear-gradient(135deg, #3b82f6, #8b5cf6);
39
+ }
40
+
41
+ .tab-active {
42
+ border-bottom: 3px solid #8b5cf6;
43
+ color: #8b5cf6;
44
+ font-weight: 600;
45
+ }
46
+
47
+ .dark .tab-active {
48
+ border-bottom: 3px solid #8b5cf6;
49
+ color: #8b5cf6;
50
+ }
51
+
52
+ .checkbox-container input:checked ~ .checkmark {
53
+ background-color: #8b5cf6;
54
+ border-color: #8b5cf6;
55
+ }
56
+
57
+ .checkbox-container .checkmark:after {
58
+ content: "";
59
+ position: absolute;
60
+ display: none;
61
+ left: 6px;
62
+ top: 2px;
63
+ width: 5px;
64
+ height: 10px;
65
+ border: solid white;
66
+ border-width: 0 2px 2px 0;
67
+ transform: rotate(45deg);
68
+ }
69
+
70
+ .checkbox-container input:checked ~ .checkmark:after {
71
+ display: block;
72
+ }
73
+
74
+ .activity-icon {
75
+ width: 36px;
76
+ height: 36px;
77
+ border-radius: 50%;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ }
82
+
83
+ .exam-pill {
84
+ transition: all 0.2s ease;
85
+ }
86
+
87
+ .exam-pill:hover {
88
+ transform: translateY(-2px);
89
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
90
+ }
91
+
92
+ .radar-tooltip {
93
+ position: absolute;
94
+ background: white;
95
+ border: 1px solid #ddd;
96
+ border-radius: 8px;
97
+ padding: 10px;
98
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
99
+ z-index: 100;
100
+ pointer-events: none;
101
+ display: none;
102
+ }
103
+ </style>
104
+ </head>
105
+ <body class="bg-gray-50 text-gray-800 min-h-screen transition-colors duration-300">
106
+ <div class="container mx-auto px-4 py-6 max-w-7xl">
107
+ <!-- Header -->
108
+ <header class="flex justify-between items-center mb-8">
109
+ <h1 class="text-3xl font-bold text-indigo-600">WJEC Revision Dashboard</h1>
110
+ <div class="flex items-center space-x-4">
111
+ <div class="relative">
112
+ <button id="theme-toggle" class="p-2 rounded-full bg-gray-200 dark:bg-gray-700">
113
+ <i class="fas fa-moon dark:hidden"></i>
114
+ <i class="fas fa-sun hidden dark:block text-yellow-300"></i>
115
+ </button>
116
+ </div>
117
+ <div class="profile-icon w-10 h-10 rounded-full flex items-center justify-center text-white font-bold cursor-pointer hover:shadow-lg transition-shadow">
118
+ M
119
+ </div>
120
+ </div>
121
+ </header>
122
+
123
+ <!-- Main Content -->
124
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
125
+ <!-- Left Column -->
126
+ <div class="lg:col-span-2 space-y-6">
127
+ <!-- Tabs Navigation -->
128
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-1">
129
+ <div class="flex border-b border-gray-200 dark:border-gray-700">
130
+ <button class="tab-button py-2 px-4 text-sm font-medium" data-tab="tasks">Tasks</button>
131
+ <button class="tab-button py-2 px-4 text-sm font-medium" data-tab="past-papers">Past Papers</button>
132
+ <button class="tab-button py-2 px-4 text-sm font-medium" data-tab="progress">Progress</button>
133
+ <button class="tab-button py-2 px-4 text-sm font-medium" data-tab="exams">Exams</button>
134
+ </div>
135
+
136
+ <!-- Tasks Tab -->
137
+ <div id="tasks-tab" class="tab-content p-4">
138
+ <div class="flex justify-between items-center mb-4">
139
+ <h2 class="text-xl font-semibold">My Revision Tasks</h2>
140
+ <button id="add-task-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center">
141
+ <i class="fas fa-plus mr-2"></i> Add Task
142
+ </button>
143
+ </div>
144
+
145
+ <!-- Task Filters -->
146
+ <div class="mb-4 flex flex-wrap gap-2">
147
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-indigo-100 text-indigo-800" data-filter="all">All</button>
148
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-blue-100 text-blue-800" data-filter="Biology">Biology</button>
149
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-green-100 text-green-800" data-filter="Chemistry">Chemistry</button>
150
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-yellow-100 text-yellow-800" data-filter="Maths">Maths</button>
151
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-purple-100 text-purple-800" data-filter="Flashcards">Flashcards</button>
152
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-pink-100 text-pink-800" data-filter="Past Papers">Past Papers</button>
153
+ <button class="filter-btn px-3 py-1 rounded-full text-xs bg-gray-100 text-gray-800" data-filter="Revision">Revision</button>
154
+ </div>
155
+
156
+ <!-- Task List -->
157
+ <div id="task-list" class="space-y-3">
158
+ <!-- Tasks will be dynamically inserted here -->
159
+ </div>
160
+ </div>
161
+
162
+ <!-- Past Papers Tab -->
163
+ <div id="past-papers-tab" class="tab-content hidden p-4">
164
+ <div class="flex justify-between items-center mb-4">
165
+ <h2 class="text-xl font-semibold">Past Paper Library (2017-2023)</h2>
166
+ <div class="relative">
167
+ <input type="text" id="paper-search" placeholder="Search papers..." class="pl-8 pr-4 py-2 border rounded-lg w-64">
168
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
169
+ </div>
170
+ </div>
171
+
172
+ <!-- Paper Filters -->
173
+ <div class="mb-4 flex flex-wrap gap-2">
174
+ <select id="paper-subject" class="px-3 py-1 rounded-lg border text-sm">
175
+ <option value="all">All Subjects</option>
176
+ <option value="Biology">Biology</option>
177
+ <option value="Chemistry">Chemistry</option>
178
+ <option value="Maths">Maths</option>
179
+ </select>
180
+ <select id="paper-year" class="px-3 py-1 rounded-lg border text-sm">
181
+ <option value="all">All Years</option>
182
+ <option value="2023">2023</option>
183
+ <option value="2022">2022</option>
184
+ <option value="2021">2021</option>
185
+ <option value="2020">2020</option>
186
+ <option value="2019">2019</option>
187
+ <option value="2018">2018</option>
188
+ <option value="2017">2017</option>
189
+ </select>
190
+ <select id="paper-status" class="px-3 py-1 rounded-lg border text-sm">
191
+ <option value="all">All Statuses</option>
192
+ <option value="Not Started">Not Started</option>
193
+ <option value="In Progress">In Progress</option>
194
+ <option value="Completed">Completed</option>
195
+ </select>
196
+ </div>
197
+
198
+ <!-- Papers List -->
199
+ <div id="papers-list" class="space-y-3">
200
+ <!-- Papers will be dynamically inserted here -->
201
+ </div>
202
+ </div>
203
+
204
+ <!-- Progress Tab -->
205
+ <div id="progress-tab" class="tab-content hidden p-4">
206
+ <h2 class="text-xl font-semibold mb-4">Progress Overview</h2>
207
+
208
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
209
+ <div class="bg-white dark:bg-gray-700 p-4 rounded-lg shadow">
210
+ <h3 class="font-medium mb-2">Biology Progress</h3>
211
+ <div class="radar-chart-container">
212
+ <canvas id="biology-radar"></canvas>
213
+ </div>
214
+ </div>
215
+ <div class="bg-white dark:bg-gray-700 p-4 rounded-lg shadow">
216
+ <h3 class="font-medium mb-2">Chemistry Progress</h3>
217
+ <div class="radar-chart-container">
218
+ <canvas id="chemistry-radar"></canvas>
219
+ </div>
220
+ </div>
221
+ <div class="bg-white dark:bg-gray-700 p-4 rounded-lg shadow">
222
+ <h3 class="font-medium mb-2">Maths Progress</h3>
223
+ <div class="radar-chart-container">
224
+ <canvas id="maths-radar"></canvas>
225
+ </div>
226
+ </div>
227
+ <div class="bg-white dark:bg-gray-700 p-4 rounded-lg shadow">
228
+ <h3 class="font-medium mb-2">Overall Completion</h3>
229
+ <div class="h-64 flex items-center justify-center">
230
+ <canvas id="overall-chart" class="max-h-full"></canvas>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ </div>
235
+
236
+ <!-- Exams Tab -->
237
+ <div id="exams-tab" class="tab-content hidden p-4">
238
+ <div class="flex justify-between items-center mb-4">
239
+ <h2 class="text-xl font-semibold">Exam Countdown</h2>
240
+ <button id="add-exam-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center">
241
+ <i class="fas fa-plus mr-2"></i> Add Exam
242
+ </button>
243
+ </div>
244
+
245
+ <div id="exams-list" class="space-y-4">
246
+ <!-- Exams will be dynamically inserted here -->
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </div>
251
+
252
+ <!-- Right Column -->
253
+ <div class="space-y-6">
254
+ <!-- Upcoming Deadlines -->
255
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
256
+ <h2 class="text-xl font-semibold mb-4">Upcoming Deadlines</h2>
257
+ <div id="deadlines-list" class="space-y-3">
258
+ <div class="p-3 bg-red-50 dark:bg-gray-700 rounded-lg border-l-4 border-red-500">
259
+ <div class="flex justify-between items-start">
260
+ <div>
261
+ <h3 class="font-medium">Biology Mock Exam</h3>
262
+ <p class="text-sm text-gray-600 dark:text-gray-300">Unit 3.1 Biological Molecules</p>
263
+ </div>
264
+ <span class="text-xs bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 px-2 py-1 rounded">Tomorrow</span>
265
+ </div>
266
+ </div>
267
+ <div class="p-3 bg-yellow-50 dark:bg-gray-700 rounded-lg border-l-4 border-yellow-500">
268
+ <div class="flex justify-between items-start">
269
+ <div>
270
+ <h3 class="font-medium">Chemistry Practical</h3>
271
+ <p class="text-sm text-gray-600 dark:text-gray-300">Required Practical 4</p>
272
+ </div>
273
+ <span class="text-xs bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 px-2 py-1 rounded">3 days</span>
274
+ </div>
275
+ </div>
276
+ <div class="p-3 bg-blue-50 dark:bg-gray-700 rounded-lg border-l-4 border-blue-500">
277
+ <div class="flex justify-between items-start">
278
+ <div>
279
+ <h3 class="font-medium">Maths Assignment</h3>
280
+ <p class="text-sm text-gray-600 dark:text-gray-300">Calculus Problems</p>
281
+ </div>
282
+ <span class="text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded">1 week</span>
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </div>
287
+
288
+ <!-- Quick Stats -->
289
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
290
+ <h2 class="text-xl font-semibold mb-4">Quick Stats</h2>
291
+ <div class="grid grid-cols-2 gap-4">
292
+ <div class="bg-indigo-50 dark:bg-gray-700 p-3 rounded-lg">
293
+ <p class="text-sm text-indigo-600 dark:text-indigo-400">Tasks Completed</p>
294
+ <p class="text-2xl font-bold" id="completed-tasks">0</p>
295
+ </div>
296
+ <div class="bg-green-50 dark:bg-gray-700 p-3 rounded-lg">
297
+ <p class="text-sm text-green-600 dark:text-green-400">Papers Attempted</p>
298
+ <p class="text-2xl font-bold" id="attempted-papers">0</p>
299
+ </div>
300
+ <div class="bg-purple-50 dark:bg-gray-700 p-3 rounded-lg">
301
+ <p class="text-sm text-purple-600 dark:text-purple-400">Biology Progress</p>
302
+ <p class="text-2xl font-bold" id="biology-progress">0%</p>
303
+ </div>
304
+ <div class="bg-blue-50 dark:bg-gray-700 p-3 rounded-lg">
305
+ <p class="text-sm text-blue-600 dark:text-blue-400">Days to Exams</p>
306
+ <p class="text-2xl font-bold" id="days-to-exams">42</p>
307
+ </div>
308
+ </div>
309
+ </div>
310
+
311
+ <!-- Recent Activity -->
312
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
313
+ <h2 class="text-xl font-semibold mb-4">Recent Activity</h2>
314
+ <div class="space-y-3">
315
+ <div class="flex items-start space-x-3">
316
+ <div class="activity-icon bg-green-100 dark:bg-green-900">
317
+ <i class="fas fa-check text-green-600 dark:text-green-400"></i>
318
+ </div>
319
+ <div>
320
+ <p class="text-sm">Completed <span class="font-medium">Chemistry Unit 2.3</span> flashcards</p>
321
+ <p class="text-xs text-gray-500 dark:text-gray-400">2 hours ago</p>
322
+ </div>
323
+ </div>
324
+ <div class="flex items-start space-x-3">
325
+ <div class="activity-icon bg-blue-100 dark:bg-blue-900">
326
+ <i class="fas fa-file-alt text-blue-600 dark:text-blue-400"></i>
327
+ </div>
328
+ <div>
329
+ <p class="text-sm">Started <span class="font-medium">Maths 2022 Paper 1</span></p>
330
+ <p class="text-xs text-gray-500 dark:text-gray-400">Yesterday</p>
331
+ </div>
332
+ </div>
333
+ <div class="flex items-start space-x-3">
334
+ <div class="activity-icon bg-purple-100 dark:bg-purple-900">
335
+ <i class="fas fa-tasks text-purple-600 dark:text-purple-400"></i>
336
+ </div>
337
+ <div>
338
+ <p class="text-sm">Added <span class="font-medium">Biology Unit 4.1</span> to tasks</p>
339
+ <p class="text-xs text-gray-500 dark:text-gray-400">2 days ago</p>
340
+ </div>
341
+ </div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ </div>
346
+ </div>
347
+
348
+ <!-- Add Task Modal -->
349
+ <div id="task-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
350
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md">
351
+ <div class="p-4 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
352
+ <h3 class="text-lg font-semibold">Add New Task</h3>
353
+ <button id="close-modal" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
354
+ <i class="fas fa-times"></i>
355
+ </button>
356
+ </div>
357
+ <div class="p-4">
358
+ <form id="task-form">
359
+ <div class="mb-4">
360
+ <label for="task-title" class="block text-sm font-medium mb-1">Task Title</label>
361
+ <input type="text" id="task-title" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600" required>
362
+ </div>
363
+ <div class="mb-4">
364
+ <label for="task-subject" class="block text-sm font-medium mb-1">Subject</label>
365
+ <select id="task-subject" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
366
+ <option value="">Select Subject</option>
367
+ <option value="Biology">Biology</option>
368
+ <option value="Chemistry">Chemistry</option>
369
+ <option value="Maths">Maths</option>
370
+ </select>
371
+ </div>
372
+ <div class="mb-4">
373
+ <label for="task-topic" class="block text-sm font-medium mb-1">Topic (WJEC Specification)</label>
374
+ <select id="task-topic" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
375
+ <option value="">Select Topic</option>
376
+ <!-- Will be populated dynamically based on subject -->
377
+ </select>
378
+ </div>
379
+ <div class="mb-4">
380
+ <label class="block text-sm font-medium mb-1">Task Type</label>
381
+ <div class="flex flex-wrap gap-2">
382
+ <label class="inline-flex items-center">
383
+ <input type="checkbox" name="task-type" value="Flashcards" class="hidden">
384
+ <span class="px-3 py-1 rounded-full text-xs bg-purple-100 text-purple-800 cursor-pointer">Flashcards</span>
385
+ </label>
386
+ <label class="inline-flex items-center">
387
+ <input type="checkbox" name="task-type" value="Past Papers" class="hidden">
388
+ <span class="px-3 py-1 rounded-full text-xs bg-pink-100 text-pink-800 cursor-pointer">Past Papers</span>
389
+ </label>
390
+ <label class="inline-flex items-center">
391
+ <input type="checkbox" name="task-type" value="Revision" class="hidden">
392
+ <span class="px-3 py-1 rounded-full text-xs bg-gray-100 text-gray-800 cursor-pointer">Revision</span>
393
+ </label>
394
+ </div>
395
+ </div>
396
+ <div class="mb-4">
397
+ <label for="task-due" class="block text-sm font-medium mb-1">Due Date</label>
398
+ <input type="date" id="task-due" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
399
+ </div>
400
+ <div class="mb-4">
401
+ <label for="task-progress" class="block text-sm font-medium mb-1">Progress</label>
402
+ <input type="range" id="task-progress" min="0" max="100" value="0" class="w-full">
403
+ <div class="flex justify-between text-xs text-gray-500">
404
+ <span>0%</span>
405
+ <span>50%</span>
406
+ <span>100%</span>
407
+ </div>
408
+ </div>
409
+ <div class="flex justify-end space-x-2">
410
+ <button type="button" id="cancel-task" class="px-4 py-2 border rounded-lg">Cancel</button>
411
+ <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Task</button>
412
+ </div>
413
+ </form>
414
+ </div>
415
+ </div>
416
+ </div>
417
+
418
+ <!-- Add Exam Modal -->
419
+ <div id="exam-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
420
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md">
421
+ <div class="p-4 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
422
+ <h3 class="text-lg font-semibold">Add New Exam</h3>
423
+ <button id="close-exam-modal" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
424
+ <i class="fas fa-times"></i>
425
+ </button>
426
+ </div>
427
+ <div class="p-4">
428
+ <form id="exam-form">
429
+ <div class="mb-4">
430
+ <label for="exam-name" class="block text-sm font-medium mb-1">Exam Name</label>
431
+ <input type="text" id="exam-name" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600" required>
432
+ </div>
433
+ <div class="mb-4">
434
+ <label for="exam-subject" class="block text-sm font-medium mb-1">Subject</label>
435
+ <select id="exam-subject" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
436
+ <option value="">Select Subject</option>
437
+ <option value="Biology">Biology</option>
438
+ <option value="Chemistry">Chemistry</option>
439
+ <option value="Maths">Maths</option>
440
+ </select>
441
+ </div>
442
+ <div class="mb-4">
443
+ <label for="exam-unit" class="block text-sm font-medium mb-1">Unit</label>
444
+ <select id="exam-unit" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
445
+ <option value="">Select Unit</option>
446
+ <option value="Unit 1">Unit 1</option>
447
+ <option value="Unit 2">Unit 2</option>
448
+ <option value="Unit 3">Unit 3</option>
449
+ <option value="Unit 4">Unit 4</option>
450
+ </select>
451
+ </div>
452
+ <div class="mb-4">
453
+ <label for="exam-date" class="block text-sm font-medium mb-1">Exam Date</label>
454
+ <input type="date" id="exam-date" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600" required>
455
+ </div>
456
+ <div class="mb-4">
457
+ <label for="exam-time" class="block text-sm font-medium mb-1">Exam Time</label>
458
+ <input type="time" id="exam-time" class="w-full px-3 py-2 border rounded-lg dark:bg-gray-700 dark:border-gray-600">
459
+ </div>
460
+ <div class="flex justify-end space-x-2">
461
+ <button type="button" id="cancel-exam" class="px-4 py-2 border rounded-lg">Cancel</button>
462
+ <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Exam</button>
463
+ </div>
464
+ </form>
465
+ </div>
466
+ </div>
467
+ </div>
468
+
469
+ <!-- Radar Chart Tooltip -->
470
+ <div id="radar-tooltip" class="radar-tooltip"></div>
471
+
472
+ <script>
473
+ // Theme Toggle
474
+ const themeToggle = document.getElementById('theme-toggle');
475
+ const html = document.documentElement;
476
+
477
+ themeToggle.addEventListener('click', () => {
478
+ html.classList.toggle('dark');
479
+ localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
480
+ });
481
+
482
+ // Check for saved theme preference
483
+ if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
484
+ html.classList.add('dark');
485
+ }
486
+
487
+ // Tab Navigation
488
+ const tabButtons = document.querySelectorAll('.tab-button');
489
+ const tabContents = document.querySelectorAll('.tab-content');
490
+
491
+ tabButtons.forEach(button => {
492
+ button.addEventListener('click', () => {
493
+ const tabName = button.getAttribute('data-tab');
494
+
495
+ // Update active tab button
496
+ tabButtons.forEach(btn => btn.classList.remove('tab-active'));
497
+ button.classList.add('tab-active');
498
+
499
+ // Show corresponding tab content
500
+ tabContents.forEach(content => content.classList.add('hidden'));
501
+ document.getElementById(`${tabName}-tab`).classList.remove('hidden');
502
+
503
+ // Update charts when progress tab is shown
504
+ if (tabName === 'progress') {
505
+ updateCharts();
506
+ }
507
+ });
508
+ });
509
+
510
+ // Set first tab as active by default
511
+ if (tabButtons.length > 0) {
512
+ tabButtons[0].classList.add('tab-active');
513
+ tabContents[0].classList.remove('hidden');
514
+ }
515
+
516
+ // Task Management
517
+ let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
518
+ let papers = JSON.parse(localStorage.getItem('papers')) || [];
519
+ let exams = JSON.parse(localStorage.getItem('exams')) || [];
520
+
521
+ // WJEC specification data with units
522
+ const wjecSpecs = {
523
+ Biology: {
524
+ "Unit 3": ["3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8"],
525
+ "Unit 4": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6"]
526
+ },
527
+ Chemistry: {
528
+ "Unit 1": ["1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7"],
529
+ "Unit 2": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8"],
530
+ "Unit 3": ["3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9"],
531
+ "Unit 4": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8"]
532
+ },
533
+ Maths: {
534
+ "Unit 1": ["1.1 Proof", "1.2 Algebra and Functions"],
535
+ "Unit 2": ["2.1 Coordinate Geometry", "2.2 Sequences and Series"],
536
+ "Unit 3": ["3.1 Trigonometry", "3.2 Exponentials and Logarithms"],
537
+ "Unit 4": ["4.1 Differentiation", "4.2 Integration"]
538
+ }
539
+ };
540
+
541
+ // Populate topic dropdown based on subject and unit
542
+ const subjectSelect = document.getElementById('task-subject');
543
+ const topicSelect = document.getElementById('task-topic');
544
+
545
+ subjectSelect.addEventListener('change', () => {
546
+ const subject = subjectSelect.value;
547
+ topicSelect.innerHTML = '<option value="">Select Topic</option>';
548
+
549
+ if (subject && wjecSpecs[subject]) {
550
+ for (const unit in wjecSpecs[subject]) {
551
+ const optgroup = document.createElement('optgroup');
552
+ optgroup.label = unit;
553
+
554
+ wjecSpecs[subject][unit].forEach(topic => {
555
+ const option = document.createElement('option');
556
+ option.value = `${unit} ${topic}`;
557
+ option.textContent = `${unit} ${topic}`;
558
+ optgroup.appendChild(option);
559
+ });
560
+
561
+ topicSelect.appendChild(optgroup);
562
+ }
563
+ }
564
+ });
565
+
566
+ // Task Modal
567
+ const addTaskBtn = document.getElementById('add-task-btn');
568
+ const taskModal = document.getElementById('task-modal');
569
+ const closeModal = document.getElementById('close-modal');
570
+ const cancelTask = document.getElementById('cancel-task');
571
+ const taskForm = document.getElementById('task-form');
572
+
573
+ addTaskBtn.addEventListener('click', () => {
574
+ taskModal.classList.remove('hidden');
575
+ });
576
+
577
+ closeModal.addEventListener('click', () => {
578
+ taskModal.classList.add('hidden');
579
+ });
580
+
581
+ cancelTask.addEventListener('click', () => {
582
+ taskModal.classList.add('hidden');
583
+ });
584
+
585
+ // Task Type Selection
586
+ const taskTypeLabels = document.querySelectorAll('label[class*="inline-flex"]');
587
+
588
+ taskTypeLabels.forEach(label => {
589
+ label.addEventListener('click', () => {
590
+ const checkbox = label.querySelector('input[type="checkbox"]');
591
+ checkbox.checked = !checkbox.checked;
592
+
593
+ if (checkbox.checked) {
594
+ label.querySelector('span').classList.add('bg-indigo-100', 'text-indigo-800');
595
+ label.querySelector('span').classList.remove('bg-purple-100', 'bg-pink-100', 'bg-gray-100');
596
+ } else {
597
+ const value = checkbox.value;
598
+ if (value === 'Flashcards') {
599
+ label.querySelector('span').classList.add('bg-purple-100', 'text-purple-800');
600
+ } else if (value === 'Past Papers') {
601
+ label.querySelector('span').classList.add('bg-pink-100', 'text-pink-800');
602
+ } else {
603
+ label.querySelector('span').classList.add('bg-gray-100', 'text-gray-800');
604
+ }
605
+ label.querySelector('span').classList.remove('bg-indigo-100', 'text-indigo-800');
606
+ }
607
+ });
608
+ });
609
+
610
+ // Save Task
611
+ taskForm.addEventListener('submit', (e) => {
612
+ e.preventDefault();
613
+
614
+ const title = document.getElementById('task-title').value;
615
+ const subject = document.getElementById('task-subject').value;
616
+ const topic = document.getElementById('task-topic').value;
617
+ const dueDate = document.getElementById('task-due').value;
618
+ const progress = document.getElementById('task-progress').value;
619
+
620
+ // Get selected task types
621
+ const taskTypes = [];
622
+ document.querySelectorAll('input[name="task-type"]:checked').forEach(checkbox => {
623
+ taskTypes.push(checkbox.value);
624
+ });
625
+
626
+ const newTask = {
627
+ id: Date.now(),
628
+ title,
629
+ subject,
630
+ topic,
631
+ types: taskTypes,
632
+ dueDate,
633
+ progress: parseInt(progress),
634
+ createdAt: new Date().toISOString()
635
+ };
636
+
637
+ tasks.push(newTask);
638
+ saveTasks();
639
+ renderTasks();
640
+ updateCharts();
641
+ updateStats();
642
+
643
+ // Reset form and close modal
644
+ taskForm.reset();
645
+ taskModal.classList.add('hidden');
646
+
647
+ // Reset topic dropdown
648
+ topicSelect.innerHTML = '<option value="">Select Topic</option>';
649
+
650
+ // Reset task type selections
651
+ document.querySelectorAll('input[name="task-type"]').forEach(checkbox => {
652
+ checkbox.checked = false;
653
+ });
654
+ taskTypeLabels.forEach(label => {
655
+ const value = label.querySelector('input').value;
656
+ const span = label.querySelector('span');
657
+ span.classList.remove('bg-indigo-100', 'text-indigo-800');
658
+ if (value === 'Flashcards') {
659
+ span.classList.add('bg-purple-100', 'text-purple-800');
660
+ } else if (value === 'Past Papers') {
661
+ span.classList.add('bg-pink-100', 'text-pink-800');
662
+ } else {
663
+ span.classList.add('bg-gray-100', 'text-gray-800');
664
+ }
665
+ });
666
+ });
667
+
668
+ // Filter Tasks
669
+ const filterButtons = document.querySelectorAll('.filter-btn');
670
+
671
+ filterButtons.forEach(button => {
672
+ button.addEventListener('click', () => {
673
+ const filter = button.getAttribute('data-filter');
674
+ renderTasks(filter);
675
+ });
676
+ });
677
+
678
+ // Render Tasks
679
+ function renderTasks(filter = 'all') {
680
+ const taskList = document.getElementById('task-list');
681
+ taskList.innerHTML = '';
682
+
683
+ let filteredTasks = tasks;
684
+
685
+ if (filter !== 'all') {
686
+ filteredTasks = tasks.filter(task => {
687
+ return task.subject === filter ||
688
+ (task.types && task.types.includes(filter));
689
+ });
690
+ }
691
+
692
+ if (filteredTasks.length === 0) {
693
+ taskList.innerHTML = '<p class="text-center py-4 text-gray-500">No tasks found. Add a new task to get started!</p>';
694
+ return;
695
+ }
696
+
697
+ filteredTasks.forEach(task => {
698
+ const taskElement = document.createElement('div');
699
+ taskElement.className = 'bg-white dark:bg-gray-700 rounded-lg shadow p-4 border-l-4 border-indigo-500';
700
+ taskElement.dataset.id = task.id;
701
+
702
+ // Determine badge color based on due date
703
+ let badgeColor = 'gray';
704
+ let badgeText = '';
705
+
706
+ if (task.dueDate) {
707
+ const today = new Date();
708
+ const dueDate = new Date(task.dueDate);
709
+ const diffTime = dueDate - today;
710
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
711
+
712
+ if (diffDays < 0) {
713
+ badgeColor = 'red';
714
+ badgeText = 'Overdue';
715
+ } else if (diffDays === 0) {
716
+ badgeColor = 'red';
717
+ badgeText = 'Today';
718
+ } else if (diffDays <= 3) {
719
+ badgeColor = 'orange';
720
+ badgeText = 'Soon';
721
+ } else if (diffDays <= 7) {
722
+ badgeColor = 'yellow';
723
+ badgeText = 'Next week';
724
+ }
725
+ }
726
+
727
+ // Create type badges
728
+ let typeBadges = '';
729
+ if (task.types && task.types.length > 0) {
730
+ task.types.forEach(type => {
731
+ let bgClass = 'bg-gray-100';
732
+ let textClass = 'text-gray-800';
733
+
734
+ if (type === 'Flashcards') {
735
+ bgClass = 'bg-purple-100';
736
+ textClass = 'text-purple-800';
737
+ } else if (type === 'Past Papers') {
738
+ bgClass = 'bg-pink-100';
739
+ textClass = 'text-pink-800';
740
+ } else if (type === 'Revision') {
741
+ bgClass = 'bg-gray-100';
742
+ textClass = 'text-gray-800';
743
+ }
744
+
745
+ typeBadges += `<span class="text-xs ${bgClass} ${textClass} px-2 py-1 rounded mr-1">${type}</span>`;
746
+ });
747
+ }
748
+
749
+ taskElement.innerHTML = `
750
+ <div class="flex justify-between items-start mb-2">
751
+ <div>
752
+ <h3 class="font-medium">${task.title}</h3>
753
+ ${task.subject ? `<p class="text-sm text-gray-600 dark:text-gray-300">${task.subject} ${task.topic ? 'Β· ' + task.topic : ''}</p>` : ''}
754
+ </div>
755
+ ${badgeText ? `<span class="text-xs bg-${badgeColor}-100 dark:bg-${badgeColor}-900 text-${badgeColor}-800 dark:text-${badgeColor}-200 px-2 py-1 rounded">${badgeText}</span>` : ''}
756
+ </div>
757
+ ${typeBadges ? `<div class="mb-2">${typeBadges}</div>` : ''}
758
+ <div class="flex items-center justify-between mt-3">
759
+ <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-2.5 mr-2">
760
+ <div class="task-progress bg-indigo-600 h-2.5 rounded-full" style="width: ${task.progress}%"></div>
761
+ </div>
762
+ <span class="text-sm font-medium">${task.progress}%</span>
763
+ </div>
764
+ <div class="flex justify-end mt-3 space-x-2">
765
+ <button class="edit-task text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 text-sm">
766
+ <i class="fas fa-edit mr-1"></i> Edit
767
+ </button>
768
+ <button class="delete-task text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 text-sm">
769
+ <i class="fas fa-trash-alt mr-1"></i> Delete
770
+ </button>
771
+ </div>
772
+ `;
773
+
774
+ taskList.appendChild(taskElement);
775
+ });
776
+
777
+ // Add event listeners to edit and delete buttons
778
+ document.querySelectorAll('.edit-task').forEach(button => {
779
+ button.addEventListener('click', (e) => {
780
+ const taskId = parseInt(e.target.closest('[data-id]').dataset.id);
781
+ editTask(taskId);
782
+ });
783
+ });
784
+
785
+ document.querySelectorAll('.delete-task').forEach(button => {
786
+ button.addEventListener('click', (e) => {
787
+ const taskId = parseInt(e.target.closest('[data-id]').dataset.id);
788
+ deleteTask(taskId);
789
+ });
790
+ });
791
+ }
792
+
793
+ // Edit Task
794
+ function editTask(taskId) {
795
+ const task = tasks.find(t => t.id === taskId);
796
+ if (!task) return;
797
+
798
+ // Fill the form with task data
799
+ document.getElementById('task-title').value = task.title;
800
+ document.getElementById('task-subject').value = task.subject || '';
801
+
802
+ // Populate topics if subject is selected
803
+ if (task.subject) {
804
+ topicSelect.innerHTML = '<option value="">Select Topic</option>';
805
+
806
+ for (const unit in wjecSpecs[task.subject]) {
807
+ const optgroup = document.createElement('optgroup');
808
+ optgroup.label = unit;
809
+
810
+ wjecSpecs[task.subject][unit].forEach(topic => {
811
+ const option = document.createElement('option');
812
+ option.value = `${unit} ${topic}`;
813
+ option.textContent = `${unit} ${topic}`;
814
+ optgroup.appendChild(option);
815
+ });
816
+
817
+ topicSelect.appendChild(optgroup);
818
+ }
819
+
820
+ document.getElementById('task-topic').value = task.topic || '';
821
+ }
822
+
823
+ // Set task types
824
+ document.querySelectorAll('input[name="task-type"]').forEach(checkbox => {
825
+ checkbox.checked = task.types && task.types.includes(checkbox.value);
826
+
827
+ // Update the visual state of the labels
828
+ const label = checkbox.closest('label');
829
+ const span = label.querySelector('span');
830
+
831
+ if (checkbox.checked) {
832
+ span.classList.add('bg-indigo-100', 'text-indigo-800');
833
+ span.classList.remove('bg-purple-100', 'bg-pink-100', 'bg-gray-100');
834
+ } else {
835
+ const value = checkbox.value;
836
+ if (value === 'Flashcards') {
837
+ span.classList.add('bg-purple-100', 'text-purple-800');
838
+ } else if (value === 'Past Papers') {
839
+ span.classList.add('bg-pink-100', 'text-pink-800');
840
+ } else {
841
+ span.classList.add('bg-gray-100', 'text-gray-800');
842
+ }
843
+ span.classList.remove('bg-indigo-100', 'text-indigo-800');
844
+ }
845
+ });
846
+
847
+ document.getElementById('task-due').value = task.dueDate || '';
848
+ document.getElementById('task-progress').value = task.progress;
849
+
850
+ // Show the modal
851
+ taskModal.classList.remove('hidden');
852
+
853
+ // Change the form to update mode
854
+ taskForm.dataset.editing = taskId;
855
+ taskForm.querySelector('button[type="submit"]').textContent = 'Update Task';
856
+ }
857
+
858
+ // Update Task
859
+ taskForm.addEventListener('submit', (e) => {
860
+ e.preventDefault();
861
+
862
+ const taskId = taskForm.dataset.editing;
863
+
864
+ if (taskId) {
865
+ // Update existing task
866
+ const taskIndex = tasks.findIndex(t => t.id === parseInt(taskId));
867
+ if (taskIndex === -1) return;
868
+
869
+ const title = document.getElementById('task-title').value;
870
+ const subject = document.getElementById('task-subject').value;
871
+ const topic = document.getElementById('task-topic').value;
872
+ const dueDate = document.getElementById('task-due').value;
873
+ const progress = document.getElementById('task-progress').value;
874
+
875
+ // Get selected task types
876
+ const taskTypes = [];
877
+ document.querySelectorAll('input[name="task-type"]:checked').forEach(checkbox => {
878
+ taskTypes.push(checkbox.value);
879
+ });
880
+
881
+ tasks[taskIndex] = {
882
+ ...tasks[taskIndex],
883
+ title,
884
+ subject,
885
+ topic,
886
+ types: taskTypes,
887
+ dueDate,
888
+ progress: parseInt(progress)
889
+ };
890
+
891
+ saveTasks();
892
+ renderTasks();
893
+ updateCharts();
894
+ updateStats();
895
+
896
+ // Reset form and close modal
897
+ taskForm.reset();
898
+ delete taskForm.dataset.editing;
899
+ taskForm.querySelector('button[type="submit"]').textContent = 'Save Task';
900
+ taskModal.classList.add('hidden');
901
+ }
902
+ });
903
+
904
+ // Delete Task
905
+ function deleteTask(taskId) {
906
+ if (confirm('Are you sure you want to delete this task?')) {
907
+ tasks = tasks.filter(t => t.id !== taskId);
908
+ saveTasks();
909
+ renderTasks();
910
+ updateCharts();
911
+ updateStats();
912
+ }
913
+ }
914
+
915
+ // Save Tasks to Local Storage
916
+ function saveTasks() {
917
+ localStorage.setItem('tasks', JSON.stringify(tasks));
918
+ }
919
+
920
+ // Initialize Past Papers
921
+ function initPapers() {
922
+ if (papers.length === 0) {
923
+ // Sample past papers data
924
+ const years = [2023, 2022, 2021, 2020, 2019, 2018, 2017];
925
+ const subjects = ['Biology', 'Chemistry', 'Maths'];
926
+ const types = ['Paper 1', 'Paper 2', 'Paper 3'];
927
+
928
+ years.forEach(year => {
929
+ subjects.forEach(subject => {
930
+ types.forEach(type => {
931
+ papers.push({
932
+ id: `${subject}-${year}-${type.replace(' ', '-')}`,
933
+ subject,
934
+ year,
935
+ type,
936
+ status: 'Not Started',
937
+ completed: false
938
+ });
939
+ });
940
+ });
941
+ });
942
+
943
+ localStorage.setItem('papers', JSON.stringify(papers));
944
+ }
945
+ }
946
+
947
+ // Render Past Papers
948
+ function renderPapers() {
949
+ const papersList = document.getElementById('papers-list');
950
+ papersList.innerHTML = '';
951
+
952
+ const subjectFilter = document.getElementById('paper-subject').value;
953
+ const yearFilter = document.getElementById('paper-year').value;
954
+ const statusFilter = document.getElementById('paper-status').value;
955
+ const searchQuery = document.getElementById('paper-search').value.toLowerCase();
956
+
957
+ let filteredPapers = papers;
958
+
959
+ if (subjectFilter !== 'all') {
960
+ filteredPapers = filteredPapers.filter(paper => paper.subject === subjectFilter);
961
+ }
962
+
963
+ if (yearFilter !== 'all') {
964
+ filteredPapers = filteredPapers.filter(paper => paper.year.toString() === yearFilter);
965
+ }
966
+
967
+ if (statusFilter !== 'all') {
968
+ filteredPapers = filteredPapers.filter(paper => paper.status === statusFilter);
969
+ }
970
+
971
+ if (searchQuery) {
972
+ filteredPapers = filteredPapers.filter(paper =>
973
+ paper.subject.toLowerCase().includes(searchQuery) ||
974
+ paper.type.toLowerCase().includes(searchQuery) ||
975
+ paper.year.toString().includes(searchQuery)
976
+ );
977
+ }
978
+
979
+ if (filteredPapers.length === 0) {
980
+ papersList.innerHTML = '<p class="text-center py-4 text-gray-500">No papers found matching your criteria.</p>';
981
+ return;
982
+ }
983
+
984
+ // Group papers by subject and year
985
+ const groupedPapers = {};
986
+
987
+ filteredPapers.forEach(paper => {
988
+ const key = `${paper.subject}-${paper.year}`;
989
+ if (!groupedPapers[key]) {
990
+ groupedPapers[key] = [];
991
+ }
992
+ groupedPapers[key].push(paper);
993
+ });
994
+
995
+ // Render grouped papers
996
+ for (const key in groupedPapers) {
997
+ const [subject, year] = key.split('-');
998
+ const papersGroup = groupedPapers[key];
999
+
1000
+ const groupElement = document.createElement('div');
1001
+ groupElement.className = 'mb-6';
1002
+
1003
+ groupElement.innerHTML = `
1004
+ <h3 class="font-medium text-lg mb-2">${subject} ${year}</h3>
1005
+ <div class="bg-white dark:bg-gray-700 rounded-lg shadow divide-y divide-gray-200 dark:divide-gray-600">
1006
+ ${papersGroup.map(paper => `
1007
+ <div class="p-3 flex items-center justify-between" data-id="${paper.id}">
1008
+ <div>
1009
+ <h4 class="font-medium">${paper.type}</h4>
1010
+ <div class="flex items-center mt-1">
1011
+ <span class="text-xs px-2 py-1 rounded mr-2
1012
+ ${paper.status === 'Completed' ? 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200' :
1013
+ paper.status === 'In Progress' ? 'bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200' :
1014
+ 'bg-gray-100 dark:bg-gray-600 text-gray-800 dark:text-gray-200'}">
1015
+ ${paper.status}
1016
+ </span>
1017
+ </div>
1018
+ </div>
1019
+ <div class="flex items-center">
1020
+ <a href="#" class="text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 mr-3">
1021
+ <i class="fas fa-download"></i>
1022
+ </a>
1023
+ <div class="checkbox-container relative inline-block w-5 h-5 mr-2">
1024
+ <input type="checkbox" class="absolute opacity-0 w-0 h-0" ${paper.status === 'Completed' ? 'checked' : ''}>
1025
+ <span class="checkmark absolute top-0 left-0 h-5 w-5 border-2 border-gray-300 dark:border-gray-500 rounded"></span>
1026
+ </div>
1027
+ </div>
1028
+ </div>
1029
+ `).join('')}
1030
+ </div>
1031
+ `;
1032
+
1033
+ papersList.appendChild(groupElement);
1034
+ }
1035
+
1036
+ // Add event listeners to checkboxes
1037
+ document.querySelectorAll('.checkbox-container input').forEach(checkbox => {
1038
+ checkbox.addEventListener('change', (e) => {
1039
+ const paperId = e.target.closest('[data-id]').dataset.id;
1040
+ const paperIndex = papers.findIndex(p => p.id === paperId);
1041
+
1042
+ if (paperIndex !== -1) {
1043
+ papers[paperIndex].status = e.target.checked ? 'Completed' : 'Not Started';
1044
+ localStorage.setItem('papers', JSON.stringify(papers));
1045
+ updateStats();
1046
+ }
1047
+ });
1048
+ });
1049
+ }
1050
+
1051
+ // Paper Filters
1052
+ document.getElementById('paper-subject').addEventListener('change', renderPapers);
1053
+ document.getElementById('paper-year').addEventListener('change', renderPapers);
1054
+ document.getElementById('paper-status').addEventListener('change', renderPapers);
1055
+ document.getElementById('paper-search').addEventListener('input', renderPapers);
1056
+
1057
+ // Exam Management
1058
+ const addExamBtn = document.getElementById('add-exam-btn');
1059
+ const examModal = document.getElementById('exam-modal');
1060
+ const closeExamModal = document.getElementById('close-exam-modal');
1061
+ const cancelExam = document.getElementById('cancel-exam');
1062
+ const examForm = document.getElementById('exam-form');
1063
+
1064
+ addExamBtn.addEventListener('click', () => {
1065
+ examModal.classList.remove('hidden');
1066
+ });
1067
+
1068
+ closeExamModal.addEventListener('click', () => {
1069
+ examModal.classList.add('hidden');
1070
+ });
1071
+
1072
+ cancelExam.addEventListener('click', () => {
1073
+ examModal.classList.add('hidden');
1074
+ });
1075
+
1076
+ // Save Exam
1077
+ examForm.addEventListener('submit', (e) => {
1078
+ e.preventDefault();
1079
+
1080
+ const name = document.getElementById('exam-name').value;
1081
+ const subject = document.getElementById('exam-subject').value;
1082
+ const unit = document.getElementById('exam-unit').value;
1083
+ const date = document.getElementById('exam-date').value;
1084
+ const time = document.getElementById('exam-time').value;
1085
+
1086
+ const newExam = {
1087
+ id: Date.now(),
1088
+ name,
1089
+ subject,
1090
+ unit,
1091
+ date,
1092
+ time,
1093
+ createdAt: new Date().toISOString()
1094
+ };
1095
+
1096
+ exams.push(newExam);
1097
+ saveExams();
1098
+ renderExams();
1099
+ updateStats();
1100
+
1101
+ // Reset form and close modal
1102
+ examForm.reset();
1103
+ examModal.classList.add('hidden');
1104
+ });
1105
+
1106
+ // Render Exams
1107
+ function renderExams() {
1108
+ const examsList = document.getElementById('exams-list');
1109
+ examsList.innerHTML = '';
1110
+
1111
+ if (exams.length === 0) {
1112
+ examsList.innerHTML = '<p class="text-center py-4 text-gray-500">No exams added yet. Add your first exam to see the countdown!</p>';
1113
+ return;
1114
+ }
1115
+
1116
+ // Sort exams by date (soonest first)
1117
+ const sortedExams = [...exams].sort((a, b) => {
1118
+ return new Date(a.date) - new Date(b.date);
1119
+ });
1120
+
1121
+ sortedExams.forEach(exam => {
1122
+ const examElement = document.createElement('div');
1123
+ examElement.className = 'bg-white dark:bg-gray-700 rounded-lg shadow p-4 exam-pill';
1124
+ examElement.dataset.id = exam.id;
1125
+
1126
+ const today = new Date();
1127
+ const examDate = new Date(exam.date);
1128
+ const diffTime = examDate - today;
1129
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
1130
+
1131
+ let statusText = '';
1132
+ let statusClass = '';
1133
+
1134
+ if (diffDays < 0) {
1135
+ statusText = 'Past';
1136
+ statusClass = 'bg-gray-100 dark:bg-gray-600 text-gray-800 dark:text-gray-200';
1137
+ } else if (diffDays === 0) {
1138
+ statusText = 'Today';
1139
+ statusClass = 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200';
1140
+ } else if (diffDays <= 7) {
1141
+ statusText = `${diffDays} day${diffDays !== 1 ? 's' : ''}`;
1142
+ statusClass = 'bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200';
1143
+ } else {
1144
+ statusText = `${diffDays} day${diffDays !== 1 ? 's' : ''}`;
1145
+ statusClass = 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200';
1146
+ }
1147
+
1148
+ examElement.innerHTML = `
1149
+ <div class="flex justify-between items-start mb-2">
1150
+ <div>
1151
+ <h3 class="font-medium">${exam.name}</h3>
1152
+ <p class="text-sm text-gray-600 dark:text-gray-300">${exam.subject} ${exam.unit}</p>
1153
+ </div>
1154
+ <span class="text-xs ${statusClass} px-2 py-1 rounded">${statusText}</span>
1155
+ </div>
1156
+ <div class="flex justify-between items-center mt-3">
1157
+ <div>
1158
+ <p class="text-sm text-gray-600 dark:text-gray-300">
1159
+ <i class="far fa-calendar-alt mr-1"></i> ${formatDate(exam.date)}
1160
+ ${exam.time ? `<span class="ml-2"><i class="far fa-clock mr-1"></i> ${exam.time}</span>` : ''}
1161
+ </p>
1162
+ </div>
1163
+ <div class="flex space-x-2">
1164
+ <button class="delete-exam text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 text-sm">
1165
+ <i class="fas fa-trash-alt"></i>
1166
+ </button>
1167
+ </div>
1168
+ </div>
1169
+ `;
1170
+
1171
+ examsList.appendChild(examElement);
1172
+ });
1173
+
1174
+ // Add event listeners to delete buttons
1175
+ document.querySelectorAll('.delete-exam').forEach(button => {
1176
+ button.addEventListener('click', (e) => {
1177
+ const examId = parseInt(e.target.closest('[data-id]').dataset.id);
1178
+ deleteExam(examId);
1179
+ });
1180
+ });
1181
+ }
1182
+
1183
+ // Delete Exam
1184
+ function deleteExam(examId) {
1185
+ if (confirm('Are you sure you want to delete this exam?')) {
1186
+ exams = exams.filter(e => e.id !== examId);
1187
+ saveExams();
1188
+ renderExams();
1189
+ updateStats();
1190
+ }
1191
+ }
1192
+
1193
+ // Save Exams to Local Storage
1194
+ function saveExams() {
1195
+ localStorage.setItem('exams', JSON.stringify(exams));
1196
+ }
1197
+
1198
+ // Format date as DD/MM/YYYY
1199
+ function formatDate(dateString) {
1200
+ const date = new Date(dateString);
1201
+ const day = date.getDate().toString().padStart(2, '0');
1202
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
1203
+ const year = date.getFullYear();
1204
+ return `${day}/${month}/${year}`;
1205
+ }
1206
+
1207
+ // Charts
1208
+ let biologyRadarChart, chemistryRadarChart, mathsRadarChart, overallChart;
1209
+ const radarTooltip = document.getElementById('radar-tooltip');
1210
+
1211
+ function initCharts() {
1212
+ // Biology Radar Chart
1213
+ const biologyCtx = document.getElementById('biology-radar').getContext('2d');
1214
+ biologyRadarChart = new Chart(biologyCtx, {
1215
+ type: 'radar',
1216
+ data: {
1217
+ labels: [...wjecSpecs.Biology["Unit 3"].map(t => `Unit 3 ${t}`), ...wjecSpecs.Biology["Unit 4"].map(t => `Unit 4 ${t}`)],
1218
+ datasets: [{
1219
+ label: 'Completion %',
1220
+ data: Array([...wjecSpecs.Biology["Unit 3"], ...wjecSpecs.Biology["Unit 4"]].length).fill(0),
1221
+ backgroundColor: 'rgba(79, 70, 229, 0.2)',
1222
+ borderColor: 'rgba(79, 70, 229, 1)',
1223
+ borderWidth: 2,
1224
+ pointBackgroundColor: 'rgba(79, 70, 229, 1)',
1225
+ pointRadius: 4
1226
+ }]
1227
+ },
1228
+ options: {
1229
+ scales: {
1230
+ r: {
1231
+ angleLines: {
1232
+ display: true
1233
+ },
1234
+ suggestedMin: 0,
1235
+ suggestedMax: 100,
1236
+ ticks: {
1237
+ stepSize: 20
1238
+ }
1239
+ }
1240
+ },
1241
+ plugins: {
1242
+ legend: {
1243
+ display: false
1244
+ }
1245
+ },
1246
+ onHover: (event, chartElement) => {
1247
+ if (chartElement.length > 0) {
1248
+ const index = chartElement[0].index;
1249
+ const label = biologyRadarChart.data.labels[index];
1250
+ const value = biologyRadarChart.data.datasets[0].data[index];
1251
+
1252
+ // Find related tasks
1253
+ const relatedTasks = tasks.filter(task =>
1254
+ task.subject === 'Biology' && task.topic === label
1255
+ );
1256
+
1257
+ // Position tooltip near the point
1258
+ const canvasPosition = event.nativeEvent;
1259
+ radarTooltip.style.left = (canvasPosition.offsetX + 10) + 'px';
1260
+ radarTooltip.style.top = (canvasPosition.offsetY + 10) + 'px';
1261
+
1262
+ // Set tooltip content
1263
+ if (relatedTasks.length > 0) {
1264
+ let tasksHtml = relatedTasks.map(task =>
1265
+ `<li class="text-xs">${task.title} (${task.progress}%)</li>`
1266
+ ).join('');
1267
+ radarTooltip.innerHTML = `
1268
+ <strong>${label}</strong>
1269
+ <div>Progress: ${value}%</div>
1270
+ <div class="mt-1">Related Tasks:</div>
1271
+ <ul class="list-disc pl-4">${tasksHtml}</ul>
1272
+ `;
1273
+ } else {
1274
+ radarTooltip.innerHTML = `
1275
+ <strong>${label}</strong>
1276
+ <div>Progress: ${value}%</div>
1277
+ <div class="mt-1">No tasks yet</div>
1278
+ `;
1279
+ }
1280
+
1281
+ radarTooltip.style.display = 'block';
1282
+ } else {
1283
+ radarTooltip.style.display = 'none';
1284
+ }
1285
+ }
1286
+ }
1287
+ });
1288
+
1289
+ // Chemistry Radar Chart
1290
+ const chemistryCtx = document.getElementById('chemistry-radar').getContext('2d');
1291
+ chemistryRadarChart = new Chart(chemistryCtx, {
1292
+ type: 'radar',
1293
+ data: {
1294
+ labels: [
1295
+ ...wjecSpecs.Chemistry["Unit 1"].map(t => `Unit 1 ${t}`),
1296
+ ...wjecSpecs.Chemistry["Unit 2"].map(t => `Unit 2 ${t}`),
1297
+ ...wjecSpecs.Chemistry["Unit 3"].map(t => `Unit 3 ${t}`),
1298
+ ...wjecSpecs.Chemistry["Unit 4"].map(t => `Unit 4 ${t}`)
1299
+ ],
1300
+ datasets: [{
1301
+ label: 'Completion %',
1302
+ data: Array([
1303
+ ...wjecSpecs.Chemistry["Unit 1"],
1304
+ ...wjecSpecs.Chemistry["Unit 2"],
1305
+ ...wjecSpecs.Chemistry["Unit 3"],
1306
+ ...wjecSpecs.Chemistry["Unit 4"]
1307
+ ].length).fill(0),
1308
+ backgroundColor: 'rgba(16, 185, 129, 0.2)',
1309
+ borderColor: 'rgba(16, 185, 129, 1)',
1310
+ borderWidth: 2,
1311
+ pointBackgroundColor: 'rgba(16, 185, 129, 1)',
1312
+ pointRadius: 4
1313
+ }]
1314
+ },
1315
+ options: {
1316
+ scales: {
1317
+ r: {
1318
+ angleLines: {
1319
+ display: true
1320
+ },
1321
+ suggestedMin: 0,
1322
+ suggestedMax: 100,
1323
+ ticks: {
1324
+ stepSize: 20
1325
+ }
1326
+ }
1327
+ },
1328
+ plugins: {
1329
+ legend: {
1330
+ display: false
1331
+ }
1332
+ },
1333
+ onHover: (event, chartElement) => {
1334
+ if (chartElement.length > 0) {
1335
+ const index = chartElement[0].index;
1336
+ const label = chemistryRadarChart.data.labels[index];
1337
+ const value = chemistryRadarChart.data.datasets[0].data[index];
1338
+
1339
+ // Find related tasks
1340
+ const relatedTasks = tasks.filter(task =>
1341
+ task.subject === 'Chemistry' && task.topic === label
1342
+ );
1343
+
1344
+ // Position tooltip near the point
1345
+ const canvasPosition = event.nativeEvent;
1346
+ radarTooltip.style.left = (canvasPosition.offsetX + 10) + 'px';
1347
+ radarTooltip.style.top = (canvasPosition.offsetY + 10) + 'px';
1348
+
1349
+ // Set tooltip content
1350
+ if (relatedTasks.length > 0) {
1351
+ let tasksHtml = relatedTasks.map(task =>
1352
+ `<li class="text-xs">${task.title} (${task.progress}%)</li>`
1353
+ ).join('');
1354
+ radarTooltip.innerHTML = `
1355
+ <strong>${label}</strong>
1356
+ <div>Progress: ${value}%</div>
1357
+ <div class="mt-1">Related Tasks:</div>
1358
+ <ul class="list-disc pl-4">${tasksHtml}</ul>
1359
+ `;
1360
+ } else {
1361
+ radarTooltip.innerHTML = `
1362
+ <strong>${label}</strong>
1363
+ <div>Progress: ${value}%</div>
1364
+ <div class="mt-1">No tasks yet</div>
1365
+ `;
1366
+ }
1367
+
1368
+ radarTooltip.style.display = 'block';
1369
+ } else {
1370
+ radarTooltip.style.display = 'none';
1371
+ }
1372
+ }
1373
+ }
1374
+ });
1375
+
1376
+ // Maths Radar Chart
1377
+ const mathsCtx = document.getElementById('maths-radar').getContext('2d');
1378
+ mathsRadarChart = new Chart(mathsCtx, {
1379
+ type: 'radar',
1380
+ data: {
1381
+ labels: [
1382
+ ...wjecSpecs.Maths["Unit 1"].map(t => `Unit 1 ${t}`),
1383
+ ...wjecSpecs.Maths["Unit 2"].map(t => `Unit 2 ${t}`),
1384
+ ...wjecSpecs.Maths["Unit 3"].map(t => `Unit 3 ${t}`),
1385
+ ...wjecSpecs.Maths["Unit 4"].map(t => `Unit 4 ${t}`)
1386
+ ],
1387
+ datasets: [{
1388
+ label: 'Completion %',
1389
+ data: Array([
1390
+ ...wjecSpecs.Maths["Unit 1"],
1391
+ ...wjecSpecs.Maths["Unit 2"],
1392
+ ...wjecSpecs.Maths["Unit 3"],
1393
+ ...wjecSpecs.Maths["Unit 4"]
1394
+ ].length).fill(0),
1395
+ backgroundColor: 'rgba(245, 158, 11, 0.2)',
1396
+ borderColor: 'rgba(245, 158, 11, 1)',
1397
+ borderWidth: 2,
1398
+ pointBackgroundColor: 'rgba(245, 158, 11, 1)',
1399
+ pointRadius: 4
1400
+ }]
1401
+ },
1402
+ options: {
1403
+ scales: {
1404
+ r: {
1405
+ angleLines: {
1406
+ display: true
1407
+ },
1408
+ suggestedMin: 0,
1409
+ suggestedMax: 100,
1410
+ ticks: {
1411
+ stepSize: 20
1412
+ }
1413
+ }
1414
+ },
1415
+ plugins: {
1416
+ legend: {
1417
+ display: false
1418
+ }
1419
+ },
1420
+ onHover: (event, chartElement) => {
1421
+ if (chartElement.length > 0) {
1422
+ const index = chartElement[0].index;
1423
+ const label = mathsRadarChart.data.labels[index];
1424
+ const value = mathsRadarChart.data.datasets[0].data[index];
1425
+
1426
+ // Find related tasks
1427
+ const relatedTasks = tasks.filter(task =>
1428
+ task.subject === 'Maths' && task.topic === label
1429
+ );
1430
+
1431
+ // Position tooltip near the point
1432
+ const canvasPosition = event.nativeEvent;
1433
+ radarTooltip.style.left = (canvasPosition.offsetX + 10) + 'px';
1434
+ radarTooltip.style.top = (canvasPosition.offsetY + 10) + 'px';
1435
+
1436
+ // Set tooltip content
1437
+ if (relatedTasks.length > 0) {
1438
+ let tasksHtml = relatedTasks.map(task =>
1439
+ `<li class="text-xs">${task.title} (${task.progress}%)</li>`
1440
+ ).join('');
1441
+ radarTooltip.innerHTML = `
1442
+ <strong>${label}</strong>
1443
+ <div>Progress: ${value}%</div>
1444
+ <div class="mt-1">Related Tasks:</div>
1445
+ <ul class="list-disc pl-4">${tasksHtml}</ul>
1446
+ `;
1447
+ } else {
1448
+ radarTooltip.innerHTML = `
1449
+ <strong>${label}</strong>
1450
+ <div>Progress: ${value}%</div>
1451
+ <div class="mt-1">No tasks yet</div>
1452
+ `;
1453
+ }
1454
+
1455
+ radarTooltip.style.display = 'block';
1456
+ } else {
1457
+ radarTooltip.style.display = 'none';
1458
+ }
1459
+ }
1460
+ }
1461
+ });
1462
+
1463
+ // Overall Progress Chart
1464
+ const overallCtx = document.getElementById('overall-chart').getContext('2d');
1465
+ overallChart = new Chart(overallCtx, {
1466
+ type: 'doughnut',
1467
+ data: {
1468
+ labels: ['Biology', 'Chemistry', 'Maths'],
1469
+ datasets: [{
1470
+ data: [0, 0, 0],
1471
+ backgroundColor: [
1472
+ 'rgba(79, 70, 229, 0.7)',
1473
+ 'rgba(16, 185, 129, 0.7)',
1474
+ 'rgba(245, 158, 11, 0.7)'
1475
+ ],
1476
+ borderColor: [
1477
+ 'rgba(79, 70, 229, 1)',
1478
+ 'rgba(16, 185, 129, 1)',
1479
+ 'rgba(245, 158, 11, 1)'
1480
+ ],
1481
+ borderWidth: 1
1482
+ }]
1483
+ },
1484
+ options: {
1485
+ plugins: {
1486
+ legend: {
1487
+ position: 'right'
1488
+ }
1489
+ },
1490
+ cutout: '70%'
1491
+ }
1492
+ });
1493
+ }
1494
+
1495
+ // Update Charts
1496
+ function updateCharts() {
1497
+ // Calculate progress for each topic in Biology
1498
+ const biologyProgress = [
1499
+ ...wjecSpecs.Biology["Unit 3"].map(topic => {
1500
+ const topicLabel = `Unit 3 ${topic}`;
1501
+ const topicTasks = tasks.filter(task =>
1502
+ task.subject === 'Biology' && task.topic === topicLabel
1503
+ );
1504
+
1505
+ if (topicTasks.length === 0) return 0;
1506
+
1507
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1508
+ return Math.round(totalProgress / topicTasks.length);
1509
+ }),
1510
+ ...wjecSpecs.Biology["Unit 4"].map(topic => {
1511
+ const topicLabel = `Unit 4 ${topic}`;
1512
+ const topicTasks = tasks.filter(task =>
1513
+ task.subject === 'Biology' && task.topic === topicLabel
1514
+ );
1515
+
1516
+ if (topicTasks.length === 0) return 0;
1517
+
1518
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1519
+ return Math.round(totalProgress / topicTasks.length);
1520
+ })
1521
+ ];
1522
+
1523
+ biologyRadarChart.data.datasets[0].data = biologyProgress;
1524
+ biologyRadarChart.update();
1525
+
1526
+ // Calculate progress for each topic in Chemistry
1527
+ const chemistryProgress = [
1528
+ ...wjecSpecs.Chemistry["Unit 1"].map(topic => {
1529
+ const topicLabel = `Unit 1 ${topic}`;
1530
+ const topicTasks = tasks.filter(task =>
1531
+ task.subject === 'Chemistry' && task.topic === topicLabel
1532
+ );
1533
+
1534
+ if (topicTasks.length === 0) return 0;
1535
+
1536
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1537
+ return Math.round(totalProgress / topicTasks.length);
1538
+ }),
1539
+ ...wjecSpecs.Chemistry["Unit 2"].map(topic => {
1540
+ const topicLabel = `Unit 2 ${topic}`;
1541
+ const topicTasks = tasks.filter(task =>
1542
+ task.subject === 'Chemistry' && task.topic === topicLabel
1543
+ );
1544
+
1545
+ if (topicTasks.length === 0) return 0;
1546
+
1547
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1548
+ return Math.round(totalProgress / topicTasks.length);
1549
+ }),
1550
+ ...wjecSpecs.Chemistry["Unit 3"].map(topic => {
1551
+ const topicLabel = `Unit 3 ${topic}`;
1552
+ const topicTasks = tasks.filter(task =>
1553
+ task.subject === 'Chemistry' && task.topic === topicLabel
1554
+ );
1555
+
1556
+ if (topicTasks.length === 0) return 0;
1557
+
1558
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1559
+ return Math.round(totalProgress / topicTasks.length);
1560
+ }),
1561
+ ...wjecSpecs.Chemistry["Unit 4"].map(topic => {
1562
+ const topicLabel = `Unit 4 ${topic}`;
1563
+ const topicTasks = tasks.filter(task =>
1564
+ task.subject === 'Chemistry' && task.topic === topicLabel
1565
+ );
1566
+
1567
+ if (topicTasks.length === 0) return 0;
1568
+
1569
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1570
+ return Math.round(totalProgress / topicTasks.length);
1571
+ })
1572
+ ];
1573
+
1574
+ chemistryRadarChart.data.datasets[0].data = chemistryProgress;
1575
+ chemistryRadarChart.update();
1576
+
1577
+ // Calculate progress for each topic in Maths
1578
+ const mathsProgress = [
1579
+ ...wjecSpecs.Maths["Unit 1"].map(topic => {
1580
+ const topicLabel = `Unit 1 ${topic}`;
1581
+ const topicTasks = tasks.filter(task =>
1582
+ task.subject === 'Maths' && task.topic === topicLabel
1583
+ );
1584
+
1585
+ if (topicTasks.length === 0) return 0;
1586
+
1587
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1588
+ return Math.round(totalProgress / topicTasks.length);
1589
+ }),
1590
+ ...wjecSpecs.Maths["Unit 2"].map(topic => {
1591
+ const topicLabel = `Unit 2 ${topic}`;
1592
+ const topicTasks = tasks.filter(task =>
1593
+ task.subject === 'Maths' && task.topic === topicLabel
1594
+ );
1595
+
1596
+ if (topicTasks.length === 0) return 0;
1597
+
1598
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1599
+ return Math.round(totalProgress / topicTasks.length);
1600
+ }),
1601
+ ...wjecSpecs.Maths["Unit 3"].map(topic => {
1602
+ const topicLabel = `Unit 3 ${topic}`;
1603
+ const topicTasks = tasks.filter(task =>
1604
+ task.subject === 'Maths' && task.topic === topicLabel
1605
+ );
1606
+
1607
+ if (topicTasks.length === 0) return 0;
1608
+
1609
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1610
+ return Math.round(totalProgress / topicTasks.length);
1611
+ }),
1612
+ ...wjecSpecs.Maths["Unit 4"].map(topic => {
1613
+ const topicLabel = `Unit 4 ${topic}`;
1614
+ const topicTasks = tasks.filter(task =>
1615
+ task.subject === 'Maths' && task.topic === topicLabel
1616
+ );
1617
+
1618
+ if (topicTasks.length === 0) return 0;
1619
+
1620
+ const totalProgress = topicTasks.reduce((sum, task) => sum + task.progress, 0);
1621
+ return Math.round(totalProgress / topicTasks.length);
1622
+ })
1623
+ ];
1624
+
1625
+ mathsRadarChart.data.datasets[0].data = mathsProgress;
1626
+ mathsRadarChart.update();
1627
+
1628
+ // Calculate overall subject progress
1629
+ const biologyTasks = tasks.filter(task => task.subject === 'Biology');
1630
+ const chemistryTasks = tasks.filter(task => task.subject === 'Chemistry');
1631
+ const mathsTasks = tasks.filter(task => task.subject === 'Maths');
1632
+
1633
+ const biologyAvg
1634
+ </html>
prompts.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Build me a modern interactive A-Level revision dashboard for WJEC Biology, Chemistry, and Maths. πŸ“Œ Core Features: Task Manager: Add/edit/delete tasks with progress bars. Each task should be taggable with filters: "Biology", "Chemistry", "Maths", "Flashcards", "Past Papers", "Revision". Radar Chart Progress Visualisation: Interactive radar/spider chart displaying progress per subject/topic (e.g., ticking off "3.1 Biological Molecules" updates the chart). Topic structure should reflect WJEC specs (can be JSON-based). Past Paper Library (2017–2023): Include a searchable and filterable list of WJEC past papers (2017–2023) by subject and year. Allow tracking of completed papers with tick boxes or progress states (Not Started, In Progress, Completed). Profile Icon: Simple circular icon with a centered "M" and a stylish gradient (e.g., blue-purple). Theme Support: Toggle for Light Mode and Dark Mode.
2
+ This is great!
3
+ This is great! Exam Countdown: Add a date selector so I can set my upcoming exam dates manually. The countdown should dynamically update based on the current date and the user-defined exam date. Support setting multiple exams with their own countdowns (e.g., Bio U3 = June 3rd, Chem U1 = June 6th). 🎯 Radar Chart + Topics: Update the radar chart to reflect my actual WJEC topic structure: json Copy Edit { "Biology Unit 3": ["3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8"], "Biology Unit 4": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6"], "Chemistry Unit 1": ["1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7"], "Chemistry Unit 2": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8"], "Chemistry Unit 3": ["3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9"], "Chemistry Unit 4": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8"] } Allow checkboxes or toggles per subtopic to update radar chart progress. Bonus: if possible, clicking a segment on the radar should display related tasks or notes. 🎨 UI Fixes: Fix the icons for Light/Dark mode toggle and Recent Activities β€” make them circular instead of pill-shaped. Keep the style clean, modern, and responsive. βœ… Summary: Add manual exam date setting with live countdowns. Populate radar chart with specific WJEC topics listed above. Update UI for icons to be circles, not pills.