studyup 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.html +5 -60
- package/package.json +1 -1
- package/server.js +0 -50
package/index.html
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
<!-- Material Design / Roboto Typography & Icons -->
|
|
8
8
|
<link href="https://fonts.googleapis.com/css?family=Roboto:400,500,700&display=swap" rel="stylesheet">
|
|
9
9
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
10
|
-
|
|
11
10
|
<style>
|
|
12
11
|
:root {
|
|
13
12
|
--primary-color: #3f51b5; /* Indigo */
|
|
@@ -23,7 +22,6 @@
|
|
|
23
22
|
--shadow-elevation-2: 0 3px 1px -2px rgba(0,0,0,0.2), 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12);
|
|
24
23
|
--shadow-elevation-4: 0 4px 5px -2px rgba(0,0,0,0.2), 0 7px 10px 1px rgba(0,0,0,0.14), 0 2px 16px 1px rgba(0,0,0,0.12);
|
|
25
24
|
}
|
|
26
|
-
|
|
27
25
|
body {
|
|
28
26
|
font-family: 'Roboto', sans-serif;
|
|
29
27
|
background-color: var(--background-color);
|
|
@@ -35,7 +33,6 @@
|
|
|
35
33
|
min-height: 100vh;
|
|
36
34
|
justify-content: space-between;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
36
|
header {
|
|
40
37
|
background-color: var(--primary-color);
|
|
41
38
|
color: white;
|
|
@@ -45,7 +42,6 @@
|
|
|
45
42
|
align-items: center;
|
|
46
43
|
justify-content: space-between;
|
|
47
44
|
}
|
|
48
|
-
|
|
49
45
|
header h1 {
|
|
50
46
|
margin: 0;
|
|
51
47
|
font-size: 20px;
|
|
@@ -53,13 +49,11 @@
|
|
|
53
49
|
letter-spacing: 0.5px;
|
|
54
50
|
cursor: pointer;
|
|
55
51
|
}
|
|
56
|
-
|
|
57
52
|
.header-actions {
|
|
58
53
|
display: flex;
|
|
59
54
|
gap: 12px;
|
|
60
55
|
align-items: center;
|
|
61
56
|
}
|
|
62
|
-
|
|
63
57
|
.view {
|
|
64
58
|
display: none;
|
|
65
59
|
flex: 1;
|
|
@@ -68,7 +62,6 @@
|
|
|
68
62
|
.view.active {
|
|
69
63
|
display: flex;
|
|
70
64
|
}
|
|
71
|
-
|
|
72
65
|
.container {
|
|
73
66
|
max-width: 420px;
|
|
74
67
|
width: 100%;
|
|
@@ -80,7 +73,6 @@
|
|
|
80
73
|
align-items: center;
|
|
81
74
|
justify-content: center;
|
|
82
75
|
}
|
|
83
|
-
|
|
84
76
|
.card {
|
|
85
77
|
background-color: var(--card-background);
|
|
86
78
|
border-radius: 2px;
|
|
@@ -93,7 +85,6 @@
|
|
|
93
85
|
width: 100%;
|
|
94
86
|
box-sizing: border-box;
|
|
95
87
|
}
|
|
96
|
-
|
|
97
88
|
.card-icon-wrapper {
|
|
98
89
|
background-color: rgba(63, 81, 181, 0.1);
|
|
99
90
|
color: var(--primary-color);
|
|
@@ -105,32 +96,27 @@
|
|
|
105
96
|
justify-content: center;
|
|
106
97
|
margin-bottom: 20px;
|
|
107
98
|
}
|
|
108
|
-
|
|
109
99
|
.card-icon-wrapper i {
|
|
110
100
|
font-size: 32px;
|
|
111
101
|
}
|
|
112
|
-
|
|
113
102
|
.card-title {
|
|
114
103
|
font-size: 24px;
|
|
115
104
|
font-weight: 500;
|
|
116
105
|
margin: 0 0 8px 0;
|
|
117
106
|
color: var(--text-primary);
|
|
118
107
|
}
|
|
119
|
-
|
|
120
108
|
.card-subtitle {
|
|
121
109
|
font-size: 14px;
|
|
122
110
|
color: var(--text-secondary);
|
|
123
111
|
margin: 0 0 24px 0;
|
|
124
112
|
line-height: 1.4;
|
|
125
113
|
}
|
|
126
|
-
|
|
127
114
|
.input-container {
|
|
128
115
|
position: relative;
|
|
129
116
|
margin-bottom: 24px;
|
|
130
117
|
width: 100%;
|
|
131
118
|
text-align: left;
|
|
132
119
|
}
|
|
133
|
-
|
|
134
120
|
.input-container input {
|
|
135
121
|
width: 100%;
|
|
136
122
|
padding: 12px;
|
|
@@ -143,13 +129,11 @@
|
|
|
143
129
|
background: transparent;
|
|
144
130
|
transition: border-color 0.2s;
|
|
145
131
|
}
|
|
146
|
-
|
|
147
132
|
.input-container input:focus {
|
|
148
133
|
border-color: var(--primary-color);
|
|
149
134
|
border-width: 2px;
|
|
150
135
|
padding: 11px;
|
|
151
136
|
}
|
|
152
|
-
|
|
153
137
|
.input-container label {
|
|
154
138
|
position: absolute;
|
|
155
139
|
left: 12px;
|
|
@@ -161,7 +145,6 @@
|
|
|
161
145
|
background: white;
|
|
162
146
|
padding: 0 4px;
|
|
163
147
|
}
|
|
164
|
-
|
|
165
148
|
.input-container input:focus ~ label,
|
|
166
149
|
.input-container input:not(:placeholder-shown) ~ label {
|
|
167
150
|
top: -10px;
|
|
@@ -169,7 +152,6 @@
|
|
|
169
152
|
color: var(--primary-color);
|
|
170
153
|
font-weight: 500;
|
|
171
154
|
}
|
|
172
|
-
|
|
173
155
|
#error-msg {
|
|
174
156
|
color: var(--error-color);
|
|
175
157
|
font-size: 13px;
|
|
@@ -177,7 +159,6 @@
|
|
|
177
159
|
display: none;
|
|
178
160
|
font-weight: 500;
|
|
179
161
|
}
|
|
180
|
-
|
|
181
162
|
.btn-raised {
|
|
182
163
|
background-color: var(--primary-color);
|
|
183
164
|
color: white;
|
|
@@ -194,26 +175,22 @@
|
|
|
194
175
|
transition: background-color 0.2s, box-shadow 0.2s;
|
|
195
176
|
letter-spacing: 0.5px;
|
|
196
177
|
}
|
|
197
|
-
|
|
198
178
|
.btn-raised:hover {
|
|
199
179
|
background-color: var(--primary-dark);
|
|
200
180
|
box-shadow: var(--shadow-elevation-4);
|
|
201
181
|
}
|
|
202
|
-
|
|
203
182
|
.btn-danger {
|
|
204
183
|
background-color: var(--error-color);
|
|
205
184
|
}
|
|
206
185
|
.btn-danger:hover {
|
|
207
186
|
background-color: #b71c1c;
|
|
208
187
|
}
|
|
209
|
-
|
|
210
188
|
.btn-warning {
|
|
211
189
|
background-color: var(--warning-color);
|
|
212
190
|
}
|
|
213
191
|
.btn-warning:hover {
|
|
214
192
|
background-color: #e65100;
|
|
215
193
|
}
|
|
216
|
-
|
|
217
194
|
.portal-container {
|
|
218
195
|
max-width: 1000px;
|
|
219
196
|
width: 100%;
|
|
@@ -225,7 +202,6 @@
|
|
|
225
202
|
gap: 24px;
|
|
226
203
|
flex: 1;
|
|
227
204
|
}
|
|
228
|
-
|
|
229
205
|
.portal-card {
|
|
230
206
|
background-color: var(--card-background);
|
|
231
207
|
border-radius: 2px;
|
|
@@ -235,11 +211,9 @@
|
|
|
235
211
|
flex-direction: column;
|
|
236
212
|
overflow: hidden;
|
|
237
213
|
}
|
|
238
|
-
|
|
239
214
|
.portal-card:hover {
|
|
240
215
|
box-shadow: var(--shadow-elevation-4);
|
|
241
216
|
}
|
|
242
|
-
|
|
243
217
|
.card-media {
|
|
244
218
|
height: 120px;
|
|
245
219
|
display: flex;
|
|
@@ -247,33 +221,28 @@
|
|
|
247
221
|
justify-content: center;
|
|
248
222
|
color: white;
|
|
249
223
|
}
|
|
250
|
-
|
|
251
224
|
.card-content {
|
|
252
225
|
padding: 24px;
|
|
253
226
|
flex: 1;
|
|
254
227
|
}
|
|
255
|
-
|
|
256
228
|
.portal-card-title {
|
|
257
229
|
font-size: 20px;
|
|
258
230
|
font-weight: 500;
|
|
259
231
|
margin: 0 0 8px 0;
|
|
260
232
|
color: var(--text-primary);
|
|
261
233
|
}
|
|
262
|
-
|
|
263
234
|
.card-text {
|
|
264
235
|
font-size: 14px;
|
|
265
236
|
color: var(--text-secondary);
|
|
266
237
|
line-height: 1.4;
|
|
267
238
|
margin: 0;
|
|
268
239
|
}
|
|
269
|
-
|
|
270
240
|
.card-actions {
|
|
271
241
|
padding: 8px 16px 16px 16px;
|
|
272
242
|
display: flex;
|
|
273
243
|
justify-content: flex-end;
|
|
274
244
|
gap: 8px;
|
|
275
245
|
}
|
|
276
|
-
|
|
277
246
|
.btn-flat {
|
|
278
247
|
background: transparent;
|
|
279
248
|
border: none;
|
|
@@ -289,11 +258,9 @@
|
|
|
289
258
|
transition: background-color 0.2s;
|
|
290
259
|
letter-spacing: 0.5px;
|
|
291
260
|
}
|
|
292
|
-
|
|
293
261
|
.btn-flat:hover {
|
|
294
262
|
background-color: rgba(63, 81, 181, 0.08);
|
|
295
263
|
}
|
|
296
|
-
|
|
297
264
|
.admin-section {
|
|
298
265
|
background: white;
|
|
299
266
|
padding: 24px;
|
|
@@ -301,7 +268,6 @@
|
|
|
301
268
|
box-shadow: var(--shadow-elevation-2);
|
|
302
269
|
margin-bottom: 24px;
|
|
303
270
|
}
|
|
304
|
-
|
|
305
271
|
.admin-section h2 {
|
|
306
272
|
margin-top: 0;
|
|
307
273
|
font-size: 18px;
|
|
@@ -309,7 +275,6 @@
|
|
|
309
275
|
border-bottom: 2px solid var(--background-color);
|
|
310
276
|
padding-bottom: 8px;
|
|
311
277
|
}
|
|
312
|
-
|
|
313
278
|
.code-list-item {
|
|
314
279
|
display: flex;
|
|
315
280
|
flex-direction: column;
|
|
@@ -320,7 +285,6 @@
|
|
|
320
285
|
border: 1px solid #e0e0e0;
|
|
321
286
|
gap: 12px;
|
|
322
287
|
}
|
|
323
|
-
|
|
324
288
|
@media(min-width: 600px) {
|
|
325
289
|
.code-list-item {
|
|
326
290
|
flex-direction: row;
|
|
@@ -328,7 +292,6 @@
|
|
|
328
292
|
justify-content: space-between;
|
|
329
293
|
}
|
|
330
294
|
}
|
|
331
|
-
|
|
332
295
|
.checkbox-group {
|
|
333
296
|
display: flex;
|
|
334
297
|
flex-wrap: wrap;
|
|
@@ -336,14 +299,12 @@
|
|
|
336
299
|
font-size: 14px;
|
|
337
300
|
align-items: center;
|
|
338
301
|
}
|
|
339
|
-
|
|
340
302
|
.checkbox-group label {
|
|
341
303
|
display: flex;
|
|
342
304
|
align-items: center;
|
|
343
305
|
gap: 4px;
|
|
344
306
|
cursor: pointer;
|
|
345
307
|
}
|
|
346
|
-
|
|
347
308
|
#game-modal {
|
|
348
309
|
display: none;
|
|
349
310
|
position: fixed;
|
|
@@ -357,7 +318,6 @@
|
|
|
357
318
|
align-items: center;
|
|
358
319
|
justify-content: center;
|
|
359
320
|
}
|
|
360
|
-
|
|
361
321
|
.modal-content {
|
|
362
322
|
width: 90vw;
|
|
363
323
|
height: 85vh;
|
|
@@ -368,7 +328,6 @@
|
|
|
368
328
|
flex-direction: column;
|
|
369
329
|
overflow: hidden;
|
|
370
330
|
}
|
|
371
|
-
|
|
372
331
|
.modal-header {
|
|
373
332
|
background-color: #212121;
|
|
374
333
|
color: white;
|
|
@@ -377,19 +336,16 @@
|
|
|
377
336
|
align-items: center;
|
|
378
337
|
justify-content: space-between;
|
|
379
338
|
}
|
|
380
|
-
|
|
381
339
|
.modal-title {
|
|
382
340
|
margin: 0;
|
|
383
341
|
font-size: 16px;
|
|
384
342
|
font-weight: 500;
|
|
385
343
|
}
|
|
386
|
-
|
|
387
344
|
.modal-header-actions {
|
|
388
345
|
display: flex;
|
|
389
346
|
align-items: center;
|
|
390
347
|
gap: 8px;
|
|
391
348
|
}
|
|
392
|
-
|
|
393
349
|
.modal-btn {
|
|
394
350
|
background: transparent;
|
|
395
351
|
border: none;
|
|
@@ -403,23 +359,19 @@
|
|
|
403
359
|
border-radius: 50%;
|
|
404
360
|
transition: background-color 0.2s;
|
|
405
361
|
}
|
|
406
|
-
|
|
407
362
|
.modal-btn:hover {
|
|
408
363
|
background-color: rgba(255, 255, 255, 0.1);
|
|
409
364
|
}
|
|
410
|
-
|
|
411
365
|
.modal-body {
|
|
412
366
|
flex: 1;
|
|
413
367
|
width: 100%;
|
|
414
368
|
background: #fff;
|
|
415
369
|
}
|
|
416
|
-
|
|
417
370
|
.modal-body iframe {
|
|
418
371
|
width: 100%;
|
|
419
372
|
height: 100%;
|
|
420
373
|
border: none;
|
|
421
374
|
}
|
|
422
|
-
|
|
423
375
|
footer {
|
|
424
376
|
text-align: center;
|
|
425
377
|
padding: 16px;
|
|
@@ -429,7 +381,6 @@
|
|
|
429
381
|
</style>
|
|
430
382
|
</head>
|
|
431
383
|
<body>
|
|
432
|
-
|
|
433
384
|
<header>
|
|
434
385
|
<h1 onclick="logout()">StudyUp</h1>
|
|
435
386
|
<div class="header-actions">
|
|
@@ -452,9 +403,7 @@
|
|
|
452
403
|
<input type="text" id="class-code-input" placeholder="e.g. 123456" maxlength="6" autofocus>
|
|
453
404
|
<label for="class-code-input">Class Code</label>
|
|
454
405
|
</div>
|
|
455
|
-
|
|
456
406
|
<div id="error-msg">Invalid class code or system currently locked.</div>
|
|
457
|
-
|
|
458
407
|
<button class="btn-raised" onclick="verifyCode()">Enter Code</button>
|
|
459
408
|
</div>
|
|
460
409
|
</main>
|
|
@@ -472,7 +421,6 @@
|
|
|
472
421
|
<h2 style="margin: 0; color: var(--primary-color);">Admin Dashboard</h2>
|
|
473
422
|
<button class="btn-raised" style="width: auto; padding: 8px 16px;" onclick="switchView('portal-view')">← Back to Portal</button>
|
|
474
423
|
</div>
|
|
475
|
-
|
|
476
424
|
<!-- Global Control Section -->
|
|
477
425
|
<div class="admin-section">
|
|
478
426
|
<h2>Global System Controls</h2>
|
|
@@ -485,7 +433,6 @@
|
|
|
485
433
|
<button id="global-toggle-btn" class="btn-raised btn-warning" onclick="toggleGlobalBlock()">Temporarily Block All Codes</button>
|
|
486
434
|
</div>
|
|
487
435
|
</div>
|
|
488
|
-
|
|
489
436
|
<!-- Create Code Section -->
|
|
490
437
|
<div class="admin-section">
|
|
491
438
|
<h2>Create New Class Code</h2>
|
|
@@ -498,7 +445,6 @@
|
|
|
498
445
|
</div>
|
|
499
446
|
<div id="admin-error-msg" style="color: var(--error-color); font-size: 13px; margin-top: 8px; display: none;"></div>
|
|
500
447
|
</div>
|
|
501
|
-
|
|
502
448
|
<!-- Manage Codes Section -->
|
|
503
449
|
<div class="admin-section">
|
|
504
450
|
<h2>Manage Existing Codes & Game Permissions</h2>
|
|
@@ -522,7 +468,7 @@
|
|
|
522
468
|
</div>
|
|
523
469
|
</div>
|
|
524
470
|
<div class="modal-body">
|
|
525
|
-
<iframe id="game-iframe" src="" title="Game View" sandbox="allow-scripts allow-same-origin allow-modals allow-pointer-lock allow-downloads"></iframe>
|
|
471
|
+
<iframe id="game-iframe" src="" title="Game View" sandbox="allow-scripts allow-same-origin allow-modals allow-pointer-lock allow-downloads allow-forms allow-popups"></iframe>
|
|
526
472
|
</div>
|
|
527
473
|
</div>
|
|
528
474
|
</div>
|
|
@@ -604,7 +550,7 @@
|
|
|
604
550
|
document.getElementById('class-code-input').value = '';
|
|
605
551
|
switchView('portal-view');
|
|
606
552
|
document.getElementById('current-user-badge').innerText = 'Master Admin Mode';
|
|
607
|
-
|
|
553
|
+
|
|
608
554
|
const allGameIds = AVAILABLE_GAMES.map(g => g.id);
|
|
609
555
|
loadStudentDashboard(allGameIds, true);
|
|
610
556
|
} else if (config.codes && config.codes[inputVal]) {
|
|
@@ -653,7 +599,7 @@
|
|
|
653
599
|
displayCards.forEach(item => {
|
|
654
600
|
const card = document.createElement('div');
|
|
655
601
|
card.className = 'portal-card';
|
|
656
|
-
|
|
602
|
+
|
|
657
603
|
if (item.isCustomAction) {
|
|
658
604
|
card.innerHTML = `
|
|
659
605
|
<div class="card-media" style="background-color: ${item.color};">
|
|
@@ -689,7 +635,7 @@
|
|
|
689
635
|
async function loadAdminDashboard() {
|
|
690
636
|
const config = await getConfig();
|
|
691
637
|
const isBlocked = config.globalBlock;
|
|
692
|
-
|
|
638
|
+
|
|
693
639
|
const statusText = document.getElementById('global-status-text');
|
|
694
640
|
const toggleBtn = document.getElementById('global-toggle-btn');
|
|
695
641
|
if (isBlocked) {
|
|
@@ -708,7 +654,6 @@
|
|
|
708
654
|
listContainer.innerHTML = '';
|
|
709
655
|
|
|
710
656
|
const studentCodes = Object.keys(config.codes || {});
|
|
711
|
-
|
|
712
657
|
if (studentCodes.length === 0) {
|
|
713
658
|
listContainer.innerHTML = `<p style="color: var(--text-secondary); font-style: italic;">No active student codes found. Create one above.</p>`;
|
|
714
659
|
return;
|
|
@@ -720,7 +665,7 @@
|
|
|
720
665
|
|
|
721
666
|
const item = document.createElement('div');
|
|
722
667
|
item.className = 'code-list-item';
|
|
723
|
-
|
|
668
|
+
|
|
724
669
|
let checkboxesHtml = AVAILABLE_GAMES.map(g => {
|
|
725
670
|
const checked = assignedGames.includes(g.id) ? 'checked' : '';
|
|
726
671
|
return `<label><input type="checkbox" value="${g.id}" ${checked} onchange="updateCodePermission('${code}', '${g.id}', this.checked)"> ${g.name}</label>`;
|
package/package.json
CHANGED
package/server.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const app = express();
|
|
6
|
-
const PORT = process.env.PORT || 3000;
|
|
7
|
-
const DATA_FILE = path.join(__dirname, 'data.json');
|
|
8
|
-
|
|
9
|
-
app.use(express.json());
|
|
10
|
-
// Serve static files from the same root folder where server.js lives
|
|
11
|
-
app.use(express.static(__dirname));
|
|
12
|
-
|
|
13
|
-
// Helper to read data
|
|
14
|
-
function getData() {
|
|
15
|
-
if (!fs.existsSync(DATA_FILE)) {
|
|
16
|
-
const defaultData = {
|
|
17
|
-
globalBlock: false,
|
|
18
|
-
codes: {
|
|
19
|
-
"123456": { games: ["Sandboxels", "HexGL", "ClassiCube", "2048"] }
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
fs.writeFileSync(DATA_FILE, JSON.stringify(defaultData, null, 2));
|
|
23
|
-
return defaultData;
|
|
24
|
-
}
|
|
25
|
-
return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Helper to write data
|
|
29
|
-
function saveData(data) {
|
|
30
|
-
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// API: Get current config
|
|
34
|
-
app.get('/api/config', (req, res) => {
|
|
35
|
-
res.json(getData());
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// API: Save/Update config (Admin actions)
|
|
39
|
-
app.post('/api/config', (req, res) => {
|
|
40
|
-
try {
|
|
41
|
-
saveData(req.body);
|
|
42
|
-
res.json({ success: true });
|
|
43
|
-
} catch (err) {
|
|
44
|
-
res.status(500).json({ success: false, error: err.message });
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
app.listen(PORT, () => {
|
|
49
|
-
console.log(`StudyUp server running on port ${PORT}`);
|
|
50
|
-
});
|