Hma47 commited on
Commit
234c063
·
verified ·
1 Parent(s): a0aa850

Delete index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -1929
index.html DELETED
@@ -1,1929 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en" dir="ltr">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI Cognitive Strategy Generator - Enhanced Learning & Critical Thinking</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
10
-
11
- <style>
12
- /* CSS Reset and Base Styles */
13
- *, *::before, *::after {
14
- box-sizing: border-box;
15
- margin: 0;
16
- padding: 0;
17
- }
18
-
19
- /* CSS Custom Properties */
20
- :root {
21
- /* Color System - Cognitive/Learning theme */
22
- --color-primary: #2563eb;
23
- --color-primary-hover: #1d4ed8;
24
- --color-secondary: #7c3aed;
25
- --color-accent: #a855f7;
26
- --color-success: #059669;
27
- --color-warning: #d97706;
28
- --color-error: #dc2626;
29
-
30
- /* Neutral Colors - Light Mode */
31
- --color-background: #f8fafc;
32
- --color-surface: #ffffff;
33
- --color-surface-elevated: #ffffff;
34
- --color-border: #e2e8f0;
35
- --color-border-focus: #3b82f6;
36
- --color-text-primary: #1e293b;
37
- --color-text-secondary: #64748b;
38
- --color-text-muted: #94a3b8;
39
-
40
- /* Typography */
41
- --font-family-primary: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
42
- --font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
43
-
44
- /* Optimized Spacing System */
45
- --spacing-xs: 0.25rem;
46
- --spacing-sm: 0.5rem;
47
- --spacing-md: 0.75rem;
48
- --spacing-lg: 1rem;
49
- --spacing-xl: 1.25rem;
50
- --spacing-2xl: 1.5rem;
51
- --spacing-3xl: 2rem;
52
-
53
- /* Border Radius */
54
- --radius-sm: 0.375rem;
55
- --radius-md: 0.5rem;
56
- --radius-lg: 0.75rem;
57
- --radius-xl: 1rem;
58
-
59
- /* Shadows */
60
- --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
61
- --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
62
- --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
63
- --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
64
-
65
- /* Transitions */
66
- --transition-fast: 150ms ease-in-out;
67
- --transition-normal: 250ms ease-in-out;
68
- --transition-slow: 350ms ease-in-out;
69
-
70
- /* Layout */
71
- --container-max-width: 1400px;
72
- --content-max-width: 1200px;
73
- }
74
-
75
- /* RTL Support */
76
- [dir="rtl"] {
77
- text-align: right;
78
- }
79
-
80
- [dir="rtl"] .app-container {
81
- direction: rtl;
82
- }
83
-
84
- [dir="rtl"] .api-key-compact {
85
- left: auto;
86
- right: var(--spacing-lg);
87
- }
88
-
89
- [dir="rtl"] .language-switcher {
90
- right: auto;
91
- left: var(--spacing-lg);
92
- }
93
-
94
- /* Dark Mode Support */
95
- @media (prefers-color-scheme: dark) {
96
- :root {
97
- --color-background: #0f172a;
98
- --color-surface: #1e293b;
99
- --color-surface-elevated: #334155;
100
- --color-border: #334155;
101
- --color-text-primary: #f1f5f9;
102
- --color-text-secondary: #cbd5e1;
103
- --color-text-muted: #94a3b8;
104
- }
105
- }
106
-
107
- /* Base Styles */
108
- html {
109
- font-size: 16px;
110
- line-height: 1.5;
111
- scroll-behavior: smooth;
112
- }
113
-
114
- body {
115
- font-family: var(--font-family-primary);
116
- background-color: var(--color-background);
117
- color: var(--color-text-primary);
118
- line-height: 1.5;
119
- -webkit-font-smoothing: antialiased;
120
- -moz-osx-font-smoothing: grayscale;
121
- min-height: 100vh;
122
- transition: all 0.3s ease;
123
- padding: 15px;
124
- }
125
-
126
- /* Progress Bar */
127
- .progress-bar {
128
- position: fixed;
129
- top: 0;
130
- left: 0;
131
- height: 4px;
132
- background: var(--color-primary);
133
- transition: width 0.3s ease;
134
- z-index: 1000;
135
- }
136
-
137
- /* Language Selection Landing */
138
- .language-landing {
139
- display: block;
140
- max-width: 600px;
141
- margin: 50px auto;
142
- background: var(--color-surface);
143
- border-radius: var(--radius-xl);
144
- box-shadow: var(--shadow-lg);
145
- padding: 40px;
146
- text-align: center;
147
- }
148
-
149
- .language-landing h1 {
150
- font-size: 2.5rem;
151
- font-weight: 800;
152
- background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-secondary) 100%);
153
- -webkit-background-clip: text;
154
- -webkit-text-fill-color: transparent;
155
- background-clip: text;
156
- margin-bottom: 15px;
157
- }
158
-
159
- .language-landing p {
160
- font-size: 1.1rem;
161
- color: var(--color-text-secondary);
162
- margin-bottom: 30px;
163
- }
164
-
165
- .language-selector {
166
- margin-bottom: 25px;
167
- }
168
-
169
- .language-selector label {
170
- display: block;
171
- margin-bottom: 10px;
172
- font-weight: 600;
173
- color: var(--color-text-primary);
174
- font-size: 1.1rem;
175
- }
176
-
177
- .language-selector select {
178
- width: 100%;
179
- padding: 15px 20px;
180
- border: 2px solid var(--color-border);
181
- border-radius: var(--radius-lg);
182
- font-size: 1.1rem;
183
- font-family: inherit;
184
- background: var(--color-surface);
185
- transition: all 0.2s ease;
186
- margin-bottom: 20px;
187
- }
188
-
189
- .language-selector select:focus {
190
- outline: none;
191
- border-color: var(--color-border-focus);
192
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
193
- }
194
-
195
- .api-key-landing {
196
- margin-bottom: 25px;
197
- }
198
-
199
- .api-key-landing label {
200
- display: block;
201
- margin-bottom: 10px;
202
- font-weight: 600;
203
- color: var(--color-text-primary);
204
- font-size: 1.1rem;
205
- }
206
-
207
- .api-key-landing input {
208
- width: 100%;
209
- padding: 15px 20px;
210
- border: 2px solid var(--color-border);
211
- border-radius: var(--radius-lg);
212
- font-size: 1.1rem;
213
- background: var(--color-surface);
214
- transition: all 0.2s ease;
215
- font-family: 'Courier New', monospace;
216
- }
217
-
218
- .api-key-landing input:focus {
219
- outline: none;
220
- border-color: var(--color-border-focus);
221
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
222
- }
223
-
224
- .start-btn {
225
- background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-secondary) 100%);
226
- color: white;
227
- padding: 18px 40px;
228
- border: none;
229
- border-radius: var(--radius-lg);
230
- font-size: 1.2rem;
231
- font-weight: 700;
232
- cursor: pointer;
233
- transition: all 0.3s ease;
234
- width: 100%;
235
- }
236
-
237
- .start-btn:hover {
238
- transform: translateY(-2px);
239
- box-shadow: 0 12px 24px -8px rgba(37, 99, 235, 0.4);
240
- }
241
-
242
- .start-btn:disabled {
243
- opacity: 0.7;
244
- cursor: not-allowed;
245
- transform: none;
246
- }
247
-
248
- /* Cache Management Section */
249
- .cache-management {
250
- background: rgba(37, 99, 235, 0.05);
251
- border: 1px solid rgba(37, 99, 235, 0.1);
252
- border-radius: var(--radius-lg);
253
- padding: 20px;
254
- margin-bottom: 25px;
255
- text-align: center;
256
- }
257
-
258
- .cache-management h3 {
259
- color: var(--color-primary);
260
- margin-bottom: 15px;
261
- font-size: 1.1rem;
262
- font-weight: 600;
263
- }
264
-
265
- .cache-status-display {
266
- background: rgba(5, 150, 105, 0.1);
267
- border: 1px solid rgba(5, 150, 105, 0.2);
268
- color: var(--color-success);
269
- padding: 12px 16px;
270
- border-radius: var(--radius-md);
271
- margin-bottom: 15px;
272
- font-size: 0.9rem;
273
- font-weight: 500;
274
- }
275
-
276
- .cache-status-display.no-cache {
277
- background: rgba(100, 116, 139, 0.1);
278
- border-color: rgba(100, 116, 139, 0.2);
279
- color: var(--color-text-secondary);
280
- }
281
-
282
- .clear-cache-btn {
283
- background: linear-gradient(135deg, var(--color-warning) 0%, #d97706 100%);
284
- color: white;
285
- padding: 12px 24px;
286
- border: none;
287
- border-radius: var(--radius-md);
288
- font-size: 0.9rem;
289
- font-weight: 600;
290
- cursor: pointer;
291
- transition: all 0.3s ease;
292
- }
293
-
294
- .clear-cache-btn:hover {
295
- transform: translateY(-1px);
296
- box-shadow: 0 6px 12px -4px rgba(217, 119, 6, 0.4);
297
- }
298
-
299
- .clear-cache-btn:disabled {
300
- opacity: 0.5;
301
- cursor: not-allowed;
302
- transform: none;
303
- }
304
-
305
- /* Cache Status Indicator */
306
- .cache-status {
307
- background: rgba(5, 150, 105, 0.1);
308
- border: 1px solid rgba(5, 150, 105, 0.2);
309
- color: var(--color-success);
310
- padding: 8px 12px;
311
- border-radius: var(--radius-sm);
312
- margin-bottom: 15px;
313
- font-size: 0.85rem;
314
- text-align: center;
315
- font-weight: 500;
316
- display: none;
317
- }
318
-
319
- .cache-status.cached {
320
- display: block;
321
- }
322
-
323
- .cache-status.translating {
324
- background: rgba(37, 99, 235, 0.1);
325
- border-color: rgba(37, 99, 235, 0.2);
326
- color: var(--color-primary);
327
- }
328
-
329
- /* Translation Loading Overlay */
330
- .translation-overlay {
331
- position: fixed;
332
- top: 0;
333
- left: 0;
334
- width: 100%;
335
- height: 100%;
336
- background: rgba(37, 99, 235, 0.9);
337
- display: none;
338
- justify-content: center;
339
- align-items: center;
340
- z-index: 10000;
341
- color: white;
342
- text-align: center;
343
- }
344
-
345
- .translation-content {
346
- background: rgba(255, 255, 255, 0.1);
347
- padding: 40px;
348
- border-radius: var(--radius-xl);
349
- backdrop-filter: blur(10px);
350
- }
351
-
352
- .translation-spinner {
353
- width: 50px;
354
- height: 50px;
355
- border: 4px solid rgba(255, 255, 255, 0.3);
356
- border-radius: 50%;
357
- border-top-color: white;
358
- animation: spin 1s ease-in-out infinite;
359
- margin: 0 auto 20px;
360
- }
361
-
362
- /* Main Application (Hidden Initially) */
363
- .main-app {
364
- display: none;
365
- }
366
-
367
- /* Layout Components */
368
- .app-container {
369
- min-height: 100vh;
370
- max-width: var(--container-max-width);
371
- margin: 0 auto;
372
- background: var(--color-surface);
373
- border-radius: 16px;
374
- box-shadow: var(--shadow-lg);
375
- overflow: hidden;
376
- position: relative;
377
- }
378
-
379
- /* Language Switcher in Main App */
380
- .language-switcher {
381
- position: absolute;
382
- top: var(--spacing-lg);
383
- right: var(--spacing-lg);
384
- display: flex;
385
- gap: 10px;
386
- align-items: center;
387
- z-index: 10;
388
- }
389
-
390
- .language-switch-btn {
391
- background: rgba(37, 99, 235, 0.05);
392
- border: 1px solid rgba(37, 99, 235, 0.1);
393
- border-radius: var(--radius-md);
394
- padding: 8px 12px;
395
- font-size: 12px;
396
- cursor: pointer;
397
- transition: all 0.2s ease;
398
- color: var(--color-primary);
399
- font-weight: 500;
400
- }
401
-
402
- .language-switch-btn:hover {
403
- background: rgba(37, 99, 235, 0.1);
404
- }
405
-
406
- .mini-clear-cache {
407
- background: rgba(217, 119, 6, 0.1);
408
- border: 1px solid rgba(217, 119, 6, 0.2);
409
- color: var(--color-warning);
410
- padding: 6px 10px;
411
- border-radius: var(--radius-sm);
412
- font-size: 11px;
413
- cursor: pointer;
414
- transition: all 0.2s ease;
415
- font-weight: 500;
416
- }
417
-
418
- .mini-clear-cache:hover {
419
- background: rgba(217, 119, 6, 0.2);
420
- }
421
-
422
- /* Compact API Key in Top-Left */
423
- .api-key-compact {
424
- position: absolute;
425
- top: var(--spacing-lg);
426
- left: var(--spacing-lg);
427
- z-index: 10;
428
- background: rgba(37, 99, 235, 0.05);
429
- border: 1px solid rgba(37, 99, 235, 0.1);
430
- border-radius: var(--radius-lg);
431
- padding: var(--spacing-md) var(--spacing-lg);
432
- transition: all var(--transition-normal);
433
- max-width: 280px;
434
- }
435
-
436
- .api-key-compact:hover {
437
- background: rgba(37, 99, 235, 0.08);
438
- }
439
-
440
- .api-key-compact-label {
441
- display: block;
442
- font-size: 0.75rem;
443
- font-weight: 600;
444
- color: var(--color-primary);
445
- margin-bottom: var(--spacing-xs);
446
- text-transform: uppercase;
447
- letter-spacing: 0.05em;
448
- }
449
-
450
- .api-key-compact-input {
451
- width: 100%;
452
- padding: var(--spacing-sm) var(--spacing-md);
453
- border: 1px solid var(--color-border);
454
- border-radius: var(--radius-sm);
455
- font-size: 0.875rem;
456
- background: var(--color-surface);
457
- color: var(--color-text-primary);
458
- transition: all var(--transition-fast);
459
- font-family: var(--font-family-mono);
460
- }
461
-
462
- .api-key-compact-input:focus {
463
- outline: none;
464
- border-color: var(--color-border-focus);
465
- box-shadow: 0 0 0 2px rgb(59 130 246 / 0.1);
466
- }
467
-
468
- .api-key-compact-input::placeholder {
469
- color: var(--color-text-muted);
470
- font-size: 0.75rem;
471
- }
472
-
473
- /* Main Content */
474
- .app-main {
475
- max-width: var(--content-max-width);
476
- margin: 0 auto;
477
- padding: 20px 30px 30px;
478
- padding-top: 80px;
479
- }
480
-
481
- .app-header {
482
- text-align: center;
483
- margin-bottom: var(--spacing-xl);
484
- }
485
-
486
- .app-title {
487
- font-size: 2.25rem;
488
- font-weight: 700;
489
- background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
490
- -webkit-background-clip: text;
491
- -webkit-text-fill-color: transparent;
492
- background-clip: text;
493
- margin-bottom: var(--spacing-md);
494
- line-height: 1.2;
495
- }
496
-
497
- .app-subtitle {
498
- font-size: 1rem;
499
- color: var(--color-text-secondary);
500
- max-width: 600px;
501
- margin: 0 auto;
502
- line-height: 1.4;
503
- }
504
-
505
- /* Input Section */
506
- .input-section {
507
- margin-bottom: var(--spacing-xl);
508
- }
509
-
510
- .input-label {
511
- display: block;
512
- font-weight: 600;
513
- color: var(--color-text-primary);
514
- margin-bottom: var(--spacing-md);
515
- font-size: 1rem;
516
- }
517
-
518
- .input-container {
519
- position: relative;
520
- }
521
-
522
- .prompt-textarea {
523
- width: 100%;
524
- min-height: 120px;
525
- padding: var(--spacing-lg);
526
- border: 2px solid var(--color-border);
527
- border-radius: var(--radius-lg);
528
- font-size: 1rem;
529
- font-family: var(--font-family-primary);
530
- background: var(--color-surface);
531
- color: var(--color-text-primary);
532
- resize: vertical;
533
- transition: all var(--transition-fast);
534
- line-height: 1.5;
535
- }
536
-
537
- .prompt-textarea:focus {
538
- outline: none;
539
- border-color: var(--color-border-focus);
540
- box-shadow: 0 0 0 3px rgb(59 130 246 / 0.1);
541
- }
542
-
543
- .prompt-textarea::placeholder {
544
- color: var(--color-text-muted);
545
- }
546
-
547
- .character-counter {
548
- position: absolute;
549
- bottom: var(--spacing-sm);
550
- right: var(--spacing-md);
551
- font-size: 0.75rem;
552
- color: var(--color-text-muted);
553
- background: var(--color-surface);
554
- padding: var(--spacing-xs) var(--spacing-sm);
555
- border-radius: var(--radius-sm);
556
- }
557
-
558
- /* Action Section */
559
- .action-section {
560
- text-align: center;
561
- margin-bottom: var(--spacing-xl);
562
- }
563
-
564
- .generate-button {
565
- display: inline-flex;
566
- align-items: center;
567
- gap: var(--spacing-sm);
568
- padding: var(--spacing-md) var(--spacing-xl);
569
- font-size: 1rem;
570
- font-weight: 600;
571
- color: white;
572
- background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
573
- border: none;
574
- border-radius: var(--radius-lg);
575
- cursor: pointer;
576
- transition: all var(--transition-normal);
577
- box-shadow: var(--shadow-md);
578
- position: relative;
579
- overflow: hidden;
580
- }
581
-
582
- .generate-button:hover:not(:disabled) {
583
- transform: translateY(-1px);
584
- box-shadow: var(--shadow-lg);
585
- }
586
-
587
- .generate-button:active {
588
- transform: translateY(0);
589
- }
590
-
591
- .generate-button:disabled {
592
- opacity: 0.7;
593
- cursor: not-allowed;
594
- transform: none;
595
- }
596
-
597
- .button-text {
598
- transition: opacity var(--transition-fast);
599
- }
600
-
601
- .loading-spinner {
602
- display: none;
603
- width: 18px;
604
- height: 18px;
605
- border: 2px solid rgba(255, 255, 255, 0.3);
606
- border-top: 2px solid white;
607
- border-radius: 50%;
608
- animation: spin 1s linear infinite;
609
- }
610
-
611
- @keyframes spin {
612
- 0% { transform: rotate(0deg); }
613
- 100% { transform: rotate(360deg); }
614
- }
615
-
616
- /* Output Section */
617
- .output-section {
618
- margin-bottom: var(--spacing-lg);
619
- }
620
-
621
- .output-header {
622
- display: flex;
623
- align-items: center;
624
- justify-content: space-between;
625
- margin-bottom: var(--spacing-lg);
626
- }
627
-
628
- .output-title {
629
- font-size: 1.25rem;
630
- font-weight: 600;
631
- color: var(--color-text-primary);
632
- }
633
-
634
- .copy-button {
635
- display: inline-flex;
636
- align-items: center;
637
- gap: var(--spacing-xs);
638
- padding: var(--spacing-sm) var(--spacing-md);
639
- font-size: 0.875rem;
640
- font-weight: 500;
641
- color: var(--color-primary);
642
- background: transparent;
643
- border: 1px solid var(--color-primary);
644
- border-radius: var(--radius-md);
645
- cursor: pointer;
646
- transition: all var(--transition-fast);
647
- }
648
-
649
- .copy-button:hover {
650
- background: var(--color-primary);
651
- color: white;
652
- }
653
-
654
- .output-container {
655
- background: var(--color-surface);
656
- border: 1px solid var(--color-border);
657
- border-radius: var(--radius-lg);
658
- padding: var(--spacing-lg);
659
- box-shadow: var(--shadow-sm);
660
- transition: all var(--transition-normal);
661
- }
662
-
663
- .output-container:hover {
664
- box-shadow: var(--shadow-md);
665
- }
666
-
667
- .output-content {
668
- font-family: var(--font-family-primary);
669
- line-height: 1.6;
670
- color: var(--color-text-primary);
671
- white-space: pre-wrap;
672
- word-wrap: break-word;
673
- }
674
-
675
- .output-content h1,
676
- .output-content h2,
677
- .output-content h3 {
678
- color: var(--color-text-primary);
679
- margin-top: var(--spacing-lg);
680
- margin-bottom: var(--spacing-md);
681
- font-weight: 600;
682
- }
683
-
684
- .output-content h1 {
685
- font-size: 1.375rem;
686
- border-bottom: 2px solid var(--color-border);
687
- padding-bottom: var(--spacing-sm);
688
- }
689
-
690
- .output-content h2 {
691
- font-size: 1.125rem;
692
- color: var(--color-primary);
693
- }
694
-
695
- .output-content h3 {
696
- font-size: 1rem;
697
- }
698
-
699
- .output-content p {
700
- margin-bottom: var(--spacing-md);
701
- }
702
-
703
- .output-content ul,
704
- .output-content ol {
705
- margin-left: var(--spacing-lg);
706
- margin-bottom: var(--spacing-md);
707
- }
708
-
709
- .output-content li {
710
- margin-bottom: var(--spacing-xs);
711
- }
712
-
713
- .empty-state {
714
- text-align: center;
715
- padding: var(--spacing-2xl);
716
- color: var(--color-text-muted);
717
- }
718
-
719
- .empty-state-icon {
720
- font-size: 2.5rem;
721
- margin-bottom: var(--spacing-md);
722
- opacity: 0.5;
723
- }
724
-
725
- .empty-state-text {
726
- font-size: 1rem;
727
- }
728
-
729
- /* Error Handling */
730
- .error-message {
731
- background: #fef2f2;
732
- border: 1px solid #fecaca;
733
- color: #dc2626;
734
- padding: var(--spacing-md);
735
- border-radius: var(--radius-md);
736
- margin-bottom: var(--spacing-md);
737
- display: flex;
738
- align-items: center;
739
- gap: var(--spacing-sm);
740
- }
741
-
742
- .error-icon {
743
- font-size: 1.125rem;
744
- }
745
-
746
- .error-dismiss {
747
- margin-left: auto;
748
- background: none;
749
- border: none;
750
- color: #dc2626;
751
- cursor: pointer;
752
- font-size: 1.125rem;
753
- padding: var(--spacing-xs);
754
- }
755
-
756
- /* Footer */
757
- .app-footer {
758
- text-align: center;
759
- padding: var(--spacing-lg) 0;
760
- color: var(--color-text-muted);
761
- font-size: 0.875rem;
762
- border-top: 1px solid var(--color-border);
763
- margin-top: var(--spacing-xl);
764
- }
765
-
766
- /* Hidden sections */
767
- .hidden {
768
- display: none !important;
769
- }
770
-
771
- /* Responsive Design */
772
- @media (max-width: 768px) {
773
- body {
774
- padding: 10px;
775
- }
776
-
777
- .language-landing {
778
- margin: 20px auto;
779
- padding: 30px 20px;
780
- }
781
-
782
- .api-key-compact {
783
- position: static;
784
- margin-bottom: var(--spacing-xl);
785
- max-width: none;
786
- }
787
-
788
- .language-switcher {
789
- position: relative;
790
- top: auto;
791
- right: auto;
792
- margin-bottom: var(--spacing-xl);
793
- justify-content: center;
794
- }
795
-
796
- .app-main {
797
- padding: 15px 20px 20px;
798
- padding-top: 20px;
799
- }
800
-
801
- .app-title {
802
- font-size: 1.875rem;
803
- }
804
-
805
- .app-subtitle {
806
- font-size: 0.875rem;
807
- }
808
-
809
- .prompt-textarea {
810
- min-height: 100px;
811
- padding: var(--spacing-md);
812
- }
813
-
814
- .generate-button {
815
- width: 100%;
816
- justify-content: center;
817
- }
818
-
819
- .output-header {
820
- flex-direction: column;
821
- align-items: flex-start;
822
- gap: var(--spacing-md);
823
- }
824
-
825
- .empty-state {
826
- padding: var(--spacing-xl);
827
- }
828
-
829
- .empty-state-icon {
830
- font-size: 2rem;
831
- }
832
- }
833
-
834
- @media (max-width: 480px) {
835
- .language-landing h1 {
836
- font-size: 2rem;
837
- }
838
-
839
- .app-title {
840
- font-size: 1.5rem;
841
- }
842
- }
843
-
844
- /* Accessibility */
845
- .sr-only {
846
- position: absolute;
847
- width: 1px;
848
- height: 1px;
849
- padding: 0;
850
- margin: -1px;
851
- overflow: hidden;
852
- clip: rect(0, 0, 0, 0);
853
- white-space: nowrap;
854
- border: 0;
855
- }
856
-
857
- /* Focus styles for keyboard navigation */
858
- .generate-button:focus,
859
- .copy-button:focus,
860
- .api-key-compact-input:focus,
861
- .prompt-textarea:focus {
862
- outline: 2px solid var(--color-primary);
863
- outline-offset: 2px;
864
- }
865
-
866
- /* Reduced motion support */
867
- @media (prefers-reduced-motion: reduce) {
868
- *,
869
- *::before,
870
- *::after {
871
- animation-duration: 0.01ms !important;
872
- animation-iteration-count: 1 !important;
873
- transition-duration: 0.01ms !important;
874
- scroll-behavior: auto !important;
875
- }
876
- }
877
- </style>
878
- </head>
879
-
880
- <body>
881
- <!-- Progress Bar -->
882
- <div class="progress-bar" id="progressBar"></div>
883
-
884
- <!-- Translation Loading Overlay -->
885
- <div class="translation-overlay" id="translationOverlay">
886
- <div class="translation-content">
887
- <div class="translation-spinner"></div>
888
- <h2 id="translationTitle">Translating Interface...</h2>
889
- <p id="translationMessage">Please wait while we translate the interface to your selected language.</p>
890
- </div>
891
- </div>
892
-
893
- <!-- Language Selection Landing Page -->
894
- <div class="language-landing" id="languageLanding">
895
- <h1 data-translate="app_title">AI Cognitive Strategy Generator</h1>
896
- <p data-translate="welcome_message">Welcome! Please select your preferred language and enter your API key to get started with enhanced learning and critical thinking strategy generation.</p>
897
-
898
- <!-- Cache Status Indicator -->
899
- <div class="cache-status" id="cacheStatus">
900
- 💾 Translations cached - instant loading!
901
- </div>
902
-
903
- <!-- Cache Management Section -->
904
- <div class="cache-management" id="cacheManagement">
905
- <h3 data-translate="cache_management_title">🗂️ Translation Cache Management</h3>
906
- <div class="cache-status-display" id="cacheStatusDisplay">
907
- <span data-translate="cache_status_checking">Checking cache status...</span>
908
- </div>
909
- <button class="clear-cache-btn" id="clearCacheBtn" data-translate="clear_cache_button">
910
- 🗑️ Clear All Cached Translations
911
- </button>
912
- </div>
913
-
914
- <div class="language-selector">
915
- <label for="languageSelect" data-translate="select_language">🌐 Select Language</label>
916
- <select id="languageSelect">
917
- <option value="en">🇺🇸 English</option>
918
- <option value="es">🇪🇸 Español (Spanish)</option>
919
- <option value="fr">🇫🇷 Français (French)</option>
920
- <option value="de">🇩🇪 Deutsch (German)</option>
921
- <option value="zh">🇨🇳 中文 (Chinese)</option>
922
- <option value="ja">🇯🇵 日本語 (Japanese)</option>
923
- <option value="ko">🇰🇷 한국어 (Korean)</option>
924
- <option value="pt">🇵🇹 Português (Portuguese)</option>
925
- <option value="it">🇮🇹 Italiano (Italian)</option>
926
- <option value="ar">🇸🇦 العربية (Arabic)</option>
927
- <option value="ru">🇷🇺 Русский (Russian)</option>
928
- <option value="hi">🇮🇳 हिन्दी (Hindi)</option>
929
- <option value="bn">🇧🇩 বাংলা (Bengali)</option>
930
- <option value="ur">🇵🇰 اردو (Urdu)</option>
931
- <option value="tr">🇹🇷 Türkçe (Turkish)</option>
932
- <option value="pl">🇵🇱 Polski (Polish)</option>
933
- <option value="nl">🇳🇱 Nederlands (Dutch)</option>
934
- <option value="sv">🇸🇪 Svenska (Swedish)</option>
935
- <option value="da">🇩🇰 Dansk (Danish)</option>
936
- <option value="no">🇳🇴 Norsk (Norwegian)</option>
937
- <option value="fi">🇫🇮 Suomi (Finnish)</option>
938
- <option value="is">🇮🇸 Íslenska (Icelandic)</option>
939
- <option value="cs">🇨🇿 Čeština (Czech)</option>
940
- <option value="sk">🇸🇰 Slovenčina (Slovak)</option>
941
- <option value="hu">🇭🇺 Magyar (Hungarian)</option>
942
- <option value="ro">����🇴 Română (Romanian)</option>
943
- <option value="bg">🇧🇬 Български (Bulgarian)</option>
944
- <option value="hr">🇭🇷 Hrvatski (Croatian)</option>
945
- <option value="sr">🇷🇸 Српски (Serbian)</option>
946
- <option value="sl">🇸🇮 Slovenščina (Slovenian)</option>
947
- <option value="mk">🇲🇰 Македонски (Macedonian)</option>
948
- <option value="sq">🇦🇱 Shqip (Albanian)</option>
949
- <option value="lv">🇱🇻 Latviešu (Latvian)</option>
950
- <option value="lt">🇱🇹 Lietuvių (Lithuanian)</option>
951
- <option value="et">🇪🇪 Eesti (Estonian)</option>
952
- <option value="mt">🇲🇹 Malti (Maltese)</option>
953
- <option value="ga">🇮🇪 Gaeilge (Irish)</option>
954
- <option value="cy">🏴󠁧󠁢󠁷󠁬󠁳󠁿 Cymraeg (Welsh)</option>
955
- <option value="eu">🏴󠁥󠁳󠁰󠁶󠁿 Euskera (Basque)</option>
956
- <option value="ca">🏴󠁥󠁳󠁣󠁴󠁿 Català (Catalan)</option>
957
- <option value="gl">🏴󠁥󠁳󠁧󠁡󠁿 Galego (Galician)</option>
958
- <option value="el">🇬🇷 Ελληνικά (Greek)</option>
959
- <option value="he">🇮🇱 עברית (Hebrew)</option>
960
- <option value="fa">🇮🇷 فارسی (Persian)</option>
961
- <option value="ps">🇦🇫 پښتو (Pashto)</option>
962
- <option value="ku">🏴󠁩󠁱󠁫󠁲󠁿 کوردی (Kurdish)</option>
963
- <option value="az">🇦🇿 Azərbaycan (Azerbaijani)</option>
964
- <option value="kk">🇰🇿 Қазақша (Kazakh)</option>
965
- <option value="ky">🇰🇬 Кыргызча (Kyrgyz)</option>
966
- <option value="uz">🇺🇿 O'zbek (Uzbek)</option>
967
- <option value="tk">🇹🇲 Türkmen (Turkmen)</option>
968
- <option value="tg">🇹🇯 Тоҷикӣ (Tajik)</option>
969
- <option value="mn">🇲🇳 Монгол (Mongolian)</option>
970
- <option value="ka">🇬🇪 ქართული (Georgian)</option>
971
- <option value="hy">🇦🇲 Հայերեն (Armenian)</option>
972
- <option value="th">🇹🇭 ไทย (Thai)</option>
973
- <option value="vi">🇻🇳 Tiếng Việt (Vietnamese)</option>
974
- <option value="lo">🇱🇦 ລາວ (Lao)</option>
975
- <option value="km">🇰🇭 ខ្មែរ (Khmer)</option>
976
- <option value="my">🇲🇲 မြန်မာ (Myanmar)</option>
977
- <option value="si">🇱🇰 සිංහල (Sinhala)</option>
978
- <option value="ta">🇱🇰 தமிழ் (Tamil)</option>
979
- <option value="te">🇮🇳 తెలుగు (Telugu)</option>
980
- <option value="kn">🇮🇳 ಕನ್ನಡ (Kannada)</option>
981
- <option value="ml">🇮🇳 മലയാളം (Malayalam)</option>
982
- <option value="gu">🇮🇳 ગુજરાતી (Gujarati)</option>
983
- <option value="pa">🇮🇳 ਪੰਜਾਬੀ (Punjabi)</option>
984
- <option value="or">🇮🇳 ଓଡ଼ିଆ (Odia)</option>
985
- <option value="as">🇮🇳 অসমীয়া (Assamese)</option>
986
- <option value="ne">🇳🇵 नेपाली (Nepali)</option>
987
- <option value="dz">🇧🇹 རྫོང་ཁ (Dzongkha)</option>
988
- <option value="bo">🏔️ བོད་ཡིག (Tibetan)</option>
989
- <option value="id">🇮🇩 Bahasa Indonesia</option>
990
- <option value="ms">🇲🇾 Bahasa Melayu (Malay)</option>
991
- <option value="tl">🇵🇭 Filipino (Tagalog)</option>
992
- <option value="ceb">🇵🇭 Cebuano</option>
993
- <option value="haw">🏝️ ʻŌlelo Hawaiʻi (Hawaiian)</option>
994
- <option value="mi">🇳🇿 Te Reo Māori (Maori)</option>
995
- <option value="sm">🇼🇸 Gagana Samoa (Samoan)</option>
996
- <option value="to">🇹🇴 Lea Fakatonga (Tongan)</option>
997
- <option value="fj">🇫🇯 Na Vosa Vakaviti (Fijian)</option>
998
- <option value="mg">🇲🇬 Malagasy</option>
999
- <option value="sw">🇰🇪 Kiswahili (Swahili)</option>
1000
- <option value="zu">🇿🇦 isiZulu (Zulu)</option>
1001
- <option value="xh">🇿🇦 isiXhosa (Xhosa)</option>
1002
- <option value="af">🇿🇦 Afrikaans</option>
1003
- <option value="st">🇱🇸 Sesotho (Southern Sotho)</option>
1004
- <option value="tn">🇧🇼 Setswana (Tswana)</option>
1005
- <option value="ss">🇸🇿 siSwati (Swati)</option>
1006
- <option value="ve">🇿🇦 Tshivenḓa (Venda)</option>
1007
- <option value="ts">🇿🇦 Xitsonga (Tsonga)</option>
1008
- <option value="nr">🇿🇦 isiNdebele (Southern Ndebele)</option>
1009
- <option value="am">🇪🇹 አማርኛ (Amharic)</option>
1010
- <option value="ti">🇪🇷 ትግርኛ (Tigrinya)</option>
1011
- <option value="om">🇪🇹 Afaan Oromoo (Oromo)</option>
1012
- <option value="so">🇸🇴 Soomaali (Somali)</option>
1013
- <option value="ha">🇳🇬 Hausa</option>
1014
- <option value="yo">🇳🇬 Yorùbá (Yoruba)</option>
1015
- <option value="ig">🇳🇬 Igbo</option>
1016
- <option value="ff">🇸🇳 Fulfulde (Fulani)</option>
1017
- <option value="wo">🇸🇳 Wolof</option>
1018
- <option value="bm">🇲🇱 Bamanankan (Bambara)</option>
1019
- <option value="rn">🇧🇮 Kirundi (Rundi)</option>
1020
- <option value="rw">🇷🇼 Kinyarwanda (Rwanda)</option>
1021
- <option value="lg">🇺🇬 Luganda</option>
1022
- <option value="ny">🇲🇼 Chichewa (Nyanja)</option>
1023
- <option value="sn">🇿🇼 chiShona (Shona)</option>
1024
- <option value="nd">🇿🇼 isiNdebele (Northern Ndebele)</option>
1025
- </select>
1026
- </div>
1027
-
1028
- <div class="api-key-landing">
1029
- <label for="apiKeyLanding" data-translate="api_key_label">🔑 OpenAI API Key</label>
1030
- <input type="password" id="apiKeyLanding" placeholder="Enter your OpenAI API key" data-translate-placeholder="api_key_placeholder">
1031
- </div>
1032
-
1033
- <button class="start-btn" id="startBtn" data-translate="start_button">🚀 Start AI Cognitive Strategy Generator</button>
1034
- </div>
1035
-
1036
- <!-- Main Application -->
1037
- <div class="main-app" id="mainApp">
1038
- <div class="app-container">
1039
- <!-- Language Switcher -->
1040
- <div class="language-switcher" id="languageSwitcher">
1041
- <div class="language-switch-btn" onclick="showLanguageLanding()">
1042
- <span data-translate="change_language">🌐 Change Language</span>
1043
- </div>
1044
- <div class="mini-clear-cache" onclick="clearAllTranslationCache()" title="Clear translation cache">
1045
- <span data-translate="clear_cache_mini">🗑️ Clear Cache</span>
1046
- </div>
1047
- </div>
1048
-
1049
- <!-- Compact API Key in Top-Left -->
1050
- <div class="api-key-compact">
1051
- <label for="apiKey" class="api-key-compact-label" data-translate="api_key_short">API Key</label>
1052
- <input
1053
- type="password"
1054
- id="apiKey"
1055
- class="api-key-compact-input"
1056
- data-translate-placeholder="api_key_placeholder"
1057
- autocomplete="off"
1058
- >
1059
- </div>
1060
-
1061
- <main class="app-main">
1062
- <header class="app-header">
1063
- <h1 class="app-title" data-translate="app_title">AI Cognitive Strategy Generator</h1>
1064
- <p class="app-subtitle" data-translate="app_subtitle">
1065
- Generate tailored strategies to enhance cognitive abilities and boost confidence,
1066
- plus learn how to mitigate potential negative impacts of generative AI on cognitive skills.
1067
- </p>
1068
- </header>
1069
-
1070
- <section class="input-section">
1071
- <label for="userPrompt" class="input-label" data-translate="input_label">Enter Your Prompt</label>
1072
- <div class="input-container">
1073
- <textarea
1074
- id="userPrompt"
1075
- class="prompt-textarea"
1076
- data-translate-placeholder="input_placeholder"
1077
- required
1078
- maxlength="2000"
1079
- ></textarea>
1080
- <div class="character-counter" id="characterCounter">0 / 2000</div>
1081
- </div>
1082
- </section>
1083
-
1084
- <section class="action-section">
1085
- <button id="generateBtn" class="generate-button">
1086
- <span class="button-text" data-translate="generate_button">Generate Strategies</span>
1087
- <div class="loading-spinner" id="loadingSpinner"></div>
1088
- </button>
1089
- </section>
1090
-
1091
- <section class="output-section">
1092
- <div class="output-header">
1093
- <h2 class="output-title" data-translate="output_title">Enhanced Strategy Output</h2>
1094
- <button id="copyBtn" class="copy-button" style="display: none;">
1095
- <span>📋</span>
1096
- <span data-translate="copy_button">Copy to Clipboard</span>
1097
- </button>
1098
- </div>
1099
-
1100
- <div class="output-container">
1101
- <div id="outputArea" class="output-content">
1102
- <div class="empty-state">
1103
- <div class="empty-state-icon">🧠</div>
1104
- <div class="empty-state-text" data-translate="empty_state">Your AI-generated cognitive strategies will appear here</div>
1105
- </div>
1106
- </div>
1107
- </div>
1108
- </section>
1109
-
1110
- <footer class="app-footer">
1111
- <p>Created By <strong>Shift Mind AI Labs</strong></p>
1112
- </footer>
1113
- </main>
1114
- </div>
1115
- </div>
1116
-
1117
- <script>
1118
- // RTL languages list
1119
- const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'ps', 'ku'];
1120
-
1121
- // Current language and API key
1122
- let currentLanguage = 'en';
1123
- let currentApiKey = '';
1124
-
1125
- // Language names mapping
1126
- const languageNames = {
1127
- en: 'English', es: 'Spanish', fr: 'French', de: 'German', zh: 'Chinese',
1128
- ja: 'Japanese', ko: 'Korean', pt: 'Portuguese', it: 'Italian', ar: 'Arabic',
1129
- ru: 'Russian', hi: 'Hindi', bn: 'Bengali', ur: 'Urdu', tr: 'Turkish',
1130
- pl: 'Polish', nl: 'Dutch', sv: 'Swedish', da: 'Danish', no: 'Norwegian',
1131
- fi: 'Finnish', is: 'Icelandic', cs: 'Czech', sk: 'Slovak', hu: 'Hungarian',
1132
- ro: 'Romanian', bg: 'Bulgarian', hr: 'Croatian', sr: 'Serbian', sl: 'Slovenian',
1133
- mk: 'Macedonian', sq: 'Albanian', lv: 'Latvian', lt: 'Lithuanian', et: 'Estonian',
1134
- mt: 'Maltese', ga: 'Irish', cy: 'Welsh', eu: 'Basque', ca: 'Catalan',
1135
- gl: 'Galician', el: 'Greek', he: 'Hebrew', fa: 'Persian', ps: 'Pashto',
1136
- ku: 'Kurdish', az: 'Azerbaijani', kk: 'Kazakh', ky: 'Kyrgyz', uz: 'Uzbek',
1137
- tk: 'Turkmen', tg: 'Tajik', mn: 'Mongolian', ka: 'Georgian', hy: 'Armenian',
1138
- th: 'Thai', vi: 'Vietnamese', lo: 'Lao', km: 'Khmer', my: 'Myanmar',
1139
- si: 'Sinhala', ta: 'Tamil', te: 'Telugu', kn: 'Kannada', ml: 'Malayalam',
1140
- gu: 'Gujarati', pa: 'Punjabi', or: 'Odia', as: 'Assamese', ne: 'Nepali',
1141
- dz: 'Dzongkha', bo: 'Tibetan', id: 'Indonesian', ms: 'Malay', tl: 'Filipino',
1142
- ceb: 'Cebuano', haw: 'Hawaiian', mi: 'Maori', sm: 'Samoan', to: 'Tongan',
1143
- fj: 'Fijian', mg: 'Malagasy', sw: 'Swahili', zu: 'Zulu', xh: 'Xhosa',
1144
- af: 'Afrikaans', st: 'Southern Sotho', tn: 'Tswana', ss: 'Swati', ve: 'Venda',
1145
- ts: 'Tsonga', nr: 'Southern Ndebele', am: 'Amharic', ti: 'Tigrinya', om: 'Oromo',
1146
- so: 'Somali', ha: 'Hausa', yo: 'Yoruba', ig: 'Igbo', ff: 'Fulani',
1147
- wo: 'Wolof', bm: 'Bambara', rn: 'Rundi', rw: 'Rwanda', lg: 'Luganda',
1148
- ny: 'Chichewa', sn: 'Shona', nd: 'Northern Ndebele'
1149
- };
1150
-
1151
- // Translation cache management
1152
- const CACHE_PREFIX = 'aicognitive_translations_';
1153
- const CACHE_VERSION = '1.0';
1154
-
1155
- // App Configuration
1156
- const AppConfig = {
1157
- API_BASE_URL: 'https://api.openai.com/v1/chat/completions',
1158
- MODEL: 'gpt-4o-mini',
1159
- MAX_TOKENS: 3000,
1160
- TEMPERATURE: 0.7,
1161
- MAX_PROMPT_LENGTH: 2000
1162
- };
1163
-
1164
- // App State Management
1165
- const AppState = {
1166
- apiKey: '',
1167
- isLoading: false,
1168
- currentPrompt: '',
1169
- lastResult: '',
1170
-
1171
- setApiKey(key) {
1172
- this.apiKey = key;
1173
- this.saveToLocalStorage();
1174
- },
1175
-
1176
- setLoading(loading) {
1177
- this.isLoading = loading;
1178
- UIController.updateLoadingState(loading);
1179
- },
1180
-
1181
- saveToLocalStorage() {
1182
- try {
1183
- localStorage.setItem('aiCognitiveStrategy_apiKey', this.apiKey);
1184
- } catch (e) {
1185
- console.warn('Could not save to localStorage:', e);
1186
- }
1187
- },
1188
-
1189
- loadFromLocalStorage() {
1190
- try {
1191
- this.apiKey = localStorage.getItem('aiCognitiveStrategy_apiKey') || '';
1192
- } catch (e) {
1193
- console.warn('Could not load from localStorage:', e);
1194
- }
1195
- }
1196
- };
1197
-
1198
- // Check if translations are cached for a language
1199
- function isLanguageCached(language) {
1200
- const cacheKey = CACHE_PREFIX + language;
1201
- const cached = localStorage.getItem(cacheKey);
1202
- return cached !== null;
1203
- }
1204
-
1205
- // Save translations to cache
1206
- function saveTranslationsToCache(language, translations) {
1207
- const cacheKey = CACHE_PREFIX + language;
1208
- const cacheData = {
1209
- version: CACHE_VERSION,
1210
- timestamp: Date.now(),
1211
- translations: translations
1212
- };
1213
- localStorage.setItem(cacheKey, JSON.stringify(cacheData));
1214
- console.log(`Translations cached for ${language}`);
1215
- }
1216
-
1217
- // Load translations from cache
1218
- function loadTranslationsFromCache(language) {
1219
- const cacheKey = CACHE_PREFIX + language;
1220
- const cached = localStorage.getItem(cacheKey);
1221
-
1222
- if (cached) {
1223
- try {
1224
- const cacheData = JSON.parse(cached);
1225
- if (cacheData.version === CACHE_VERSION) {
1226
- console.log(`Translations loaded from cache for ${language}`);
1227
- return cacheData.translations;
1228
- }
1229
- } catch (error) {
1230
- console.error('Error parsing cached translations:', error);
1231
- }
1232
- }
1233
- return null;
1234
- }
1235
-
1236
- // Get all cached languages
1237
- function getCachedLanguages() {
1238
- const cachedLanguages = [];
1239
- for (let i = 0; i < localStorage.length; i++) {
1240
- const key = localStorage.key(i);
1241
- if (key && key.startsWith(CACHE_PREFIX)) {
1242
- const language = key.replace(CACHE_PREFIX, '');
1243
- cachedLanguages.push(language);
1244
- }
1245
- }
1246
- return cachedLanguages;
1247
- }
1248
-
1249
- // Clear all translation cache
1250
- function clearAllTranslationCache() {
1251
- const cachedLanguages = getCachedLanguages();
1252
-
1253
- if (cachedLanguages.length === 0) {
1254
- alert('No cached translations to clear.');
1255
- return;
1256
- }
1257
-
1258
- const languageList = cachedLanguages.map(lang => languageNames[lang] || lang).join(', ');
1259
- const confirmMessage = `Are you sure you want to clear all cached translations?\n\nCached languages: ${languageList}\n\nThis will require re-downloading translations when switching languages.`;
1260
-
1261
- if (confirm(confirmMessage)) {
1262
- // Clear all translation caches
1263
- cachedLanguages.forEach(language => {
1264
- const cacheKey = CACHE_PREFIX + language;
1265
- localStorage.removeItem(cacheKey);
1266
- });
1267
-
1268
- // Update cache status
1269
- updateCacheStatus(currentLanguage);
1270
- updateCacheStatusDisplay();
1271
-
1272
- alert(`Cache cleared successfully!\n\n${cachedLanguages.length} language(s) removed from cache.`);
1273
-
1274
- // Ask if user wants to reload current language translations
1275
- if (currentLanguage !== 'en' && cachedLanguages.includes(currentLanguage)) {
1276
- if (confirm('Would you like to reload the current language translations?')) {
1277
- applyLanguage(currentLanguage);
1278
- }
1279
- }
1280
- }
1281
- }
1282
-
1283
- // Update cache status indicator
1284
- function updateCacheStatus(language) {
1285
- const cacheStatus = document.getElementById('cacheStatus');
1286
- const isCached = isLanguageCached(language);
1287
-
1288
- if (language === 'en') {
1289
- cacheStatus.classList.remove('cached', 'translating');
1290
- return;
1291
- }
1292
-
1293
- if (isCached) {
1294
- cacheStatus.textContent = '💾 Translations cached - instant loading!';
1295
- cacheStatus.classList.add('cached');
1296
- cacheStatus.classList.remove('translating');
1297
- } else {
1298
- cacheStatus.textContent = '🔄 First time translation - will be cached for future use';
1299
- cacheStatus.classList.add('translating');
1300
- cacheStatus.classList.remove('cached');
1301
- }
1302
- }
1303
-
1304
- // Update cache status display in management section
1305
- function updateCacheStatusDisplay() {
1306
- const cacheStatusDisplay = document.getElementById('cacheStatusDisplay');
1307
- const clearCacheBtn = document.getElementById('clearCacheBtn');
1308
- const cachedLanguages = getCachedLanguages();
1309
-
1310
- if (cachedLanguages.length === 0) {
1311
- cacheStatusDisplay.textContent = '📭 No cached translations';
1312
- cacheStatusDisplay.className = 'cache-status-display no-cache';
1313
- clearCacheBtn.disabled = true;
1314
- } else {
1315
- const languageList = cachedLanguages.map(lang => languageNames[lang] || lang).join(', ');
1316
- cacheStatusDisplay.textContent = `💾 ${cachedLanguages.length} language(s) cached: ${languageList}`;
1317
- cacheStatusDisplay.className = 'cache-status-display';
1318
- clearCacheBtn.disabled = false;
1319
- }
1320
- }
1321
-
1322
- // Initialize the application
1323
- function initializeApp() {
1324
- // Load saved language and API key
1325
- const savedLanguage = localStorage.getItem('aicognitive_language') || 'en';
1326
- const savedApiKey = localStorage.getItem('aiCognitiveStrategy_apiKey') || '';
1327
-
1328
- currentLanguage = savedLanguage;
1329
- currentApiKey = savedApiKey;
1330
-
1331
- // Set language selector
1332
- document.getElementById('languageSelect').value = currentLanguage;
1333
- document.getElementById('apiKeyLanding').value = currentApiKey;
1334
-
1335
- // Apply direction for current language
1336
- applyDirection(currentLanguage);
1337
-
1338
- // Update cache status
1339
- updateCacheStatus(currentLanguage);
1340
- updateCacheStatusDisplay();
1341
-
1342
- // Show appropriate screen
1343
- if (currentApiKey && currentLanguage) {
1344
- showMainApp();
1345
- } else {
1346
- showLanguageLanding();
1347
- }
1348
- }
1349
-
1350
- // Apply language direction
1351
- function applyDirection(language) {
1352
- currentLanguage = language;
1353
-
1354
- // Set document language and direction
1355
- document.documentElement.lang = language;
1356
- document.documentElement.dir = rtlLanguages.includes(language) ? 'rtl' : 'ltr';
1357
-
1358
- // Save language preference
1359
- localStorage.setItem('aicognitive_language', language);
1360
-
1361
- // Update cache status
1362
- updateCacheStatus(language);
1363
- }
1364
-
1365
- // API call function for translation
1366
- async function translateText(text, targetLanguage) {
1367
- if (!currentApiKey) {
1368
- throw new Error('API key is required for translation');
1369
- }
1370
-
1371
- const languageName = languageNames[targetLanguage] || 'English';
1372
-
1373
- const prompt = `Translate the following text to ${languageName}. Provide ONLY the exact translation without any explanations, additional information, or formatting:
1374
-
1375
- "${text}"`;
1376
-
1377
- const payload = {
1378
- model: "gpt-4o-mini",
1379
- messages: [{ role: "user", content: prompt }],
1380
- max_tokens: 500,
1381
- temperature: 0.1
1382
- };
1383
-
1384
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
1385
- method: "POST",
1386
- headers: {
1387
- "Content-Type": "application/json",
1388
- "Authorization": `Bearer ${currentApiKey}`
1389
- },
1390
- body: JSON.stringify(payload)
1391
- });
1392
-
1393
- if (!response.ok) {
1394
- const errorData = await response.json();
1395
- throw new Error(errorData.error?.message || "Translation API request failed");
1396
- }
1397
-
1398
- const data = await response.json();
1399
- return data.choices[0].message.content.trim();
1400
- }
1401
-
1402
- // Apply cached translations to UI
1403
- function applyCachedTranslations(translations) {
1404
- // Apply text translations
1405
- Object.keys(translations.texts).forEach(originalText => {
1406
- const translation = translations.texts[originalText];
1407
- const elements = document.querySelectorAll(`[data-translate]`);
1408
-
1409
- elements.forEach(element => {
1410
- const originalElementText = element.getAttribute('data-original-text') || element.textContent;
1411
- if (originalElementText === originalText) {
1412
- element.textContent = translation;
1413
- }
1414
- });
1415
- });
1416
-
1417
- // Apply placeholder translations
1418
- Object.keys(translations.placeholders).forEach(originalPlaceholder => {
1419
- const translation = translations.placeholders[originalPlaceholder];
1420
- const elements = document.querySelectorAll(`[data-translate-placeholder]`);
1421
-
1422
- elements.forEach(element => {
1423
- const originalElementPlaceholder = element.getAttribute('data-original-placeholder') || element.placeholder;
1424
- if (originalElementPlaceholder === originalPlaceholder) {
1425
- element.placeholder = translation;
1426
- }
1427
- });
1428
- });
1429
- }
1430
-
1431
- // Translate all UI elements
1432
- async function translateInterface(targetLanguage) {
1433
- if (targetLanguage === 'en') {
1434
- // No translation needed for English
1435
- return;
1436
- }
1437
-
1438
- // Check if translations are cached
1439
- const cachedTranslations = loadTranslationsFromCache(targetLanguage);
1440
- if (cachedTranslations) {
1441
- // Use cached translations
1442
- console.log('Using cached translations for', targetLanguage);
1443
- applyCachedTranslations(cachedTranslations);
1444
- return;
1445
- }
1446
-
1447
- // Need to translate via API
1448
- showTranslationOverlay();
1449
-
1450
- try {
1451
- // Get all elements with data-translate attribute
1452
- const elements = document.querySelectorAll('[data-translate]');
1453
- const placeholderElements = document.querySelectorAll('[data-translate-placeholder]');
1454
-
1455
- // Collect all texts to translate
1456
- const textsToTranslate = [];
1457
- const placeholdersToTranslate = [];
1458
- const elementMap = new Map();
1459
-
1460
- elements.forEach(element => {
1461
- const originalText = element.getAttribute('data-original-text') || element.textContent;
1462
- if (!element.getAttribute('data-original-text')) {
1463
- element.setAttribute('data-original-text', originalText);
1464
- }
1465
- textsToTranslate.push(originalText);
1466
- elementMap.set(originalText, element);
1467
- });
1468
-
1469
- placeholderElements.forEach(element => {
1470
- const originalPlaceholder = element.getAttribute('data-original-placeholder') || element.placeholder;
1471
- if (!element.getAttribute('data-original-placeholder')) {
1472
- element.setAttribute('data-original-placeholder', originalPlaceholder);
1473
- }
1474
- placeholdersToTranslate.push(originalPlaceholder);
1475
- elementMap.set(originalPlaceholder, element);
1476
- });
1477
-
1478
- // Prepare cache structure
1479
- const translationsCache = {
1480
- texts: {},
1481
- placeholders: {}
1482
- };
1483
-
1484
- // Translate texts in batches
1485
- const batchSize = 10;
1486
- const allTexts = [...textsToTranslate, ...placeholdersToTranslate];
1487
-
1488
- for (let i = 0; i < allTexts.length; i += batchSize) {
1489
- const batch = allTexts.slice(i, i + batchSize);
1490
-
1491
- // Update progress
1492
- updateTranslationProgress(i, allTexts.length);
1493
-
1494
- // Translate batch
1495
- const translations = await Promise.all(
1496
- batch.map(text => translateText(text, targetLanguage))
1497
- );
1498
-
1499
- // Apply translations and cache them
1500
- batch.forEach((originalText, index) => {
1501
- const element = elementMap.get(originalText);
1502
- const translation = translations[index];
1503
-
1504
- if (element.hasAttribute('data-translate')) {
1505
- element.textContent = translation;
1506
- translationsCache.texts[originalText] = translation;
1507
- } else if (element.hasAttribute('data-translate-placeholder')) {
1508
- element.placeholder = translation;
1509
- translationsCache.placeholders[originalText] = translation;
1510
- }
1511
- });
1512
- }
1513
-
1514
- // Save translations to cache
1515
- saveTranslationsToCache(targetLanguage, translationsCache);
1516
-
1517
- // Update cache status
1518
- updateCacheStatus(targetLanguage);
1519
- updateCacheStatusDisplay();
1520
-
1521
- } catch (error) {
1522
- console.error('Translation error:', error);
1523
- UIController.showError('Translation failed: ' + error.message);
1524
- } finally {
1525
- hideTranslationOverlay();
1526
- }
1527
- }
1528
-
1529
- // Show translation overlay
1530
- function showTranslationOverlay() {
1531
- document.getElementById('translationOverlay').style.display = 'flex';
1532
- }
1533
-
1534
- // Hide translation overlay
1535
- function hideTranslationOverlay() {
1536
- document.getElementById('translationOverlay').style.display = 'none';
1537
- }
1538
-
1539
- // Update translation progress
1540
- function updateTranslationProgress(current, total) {
1541
- const percentage = Math.round((current / total) * 100);
1542
- document.getElementById('translationMessage').textContent =
1543
- `Translating interface... ${percentage}% complete (will be cached for future use)`;
1544
- }
1545
-
1546
- // Apply language with API translation or cache
1547
- async function applyLanguage(language) {
1548
- applyDirection(language);
1549
-
1550
- if (language !== 'en') {
1551
- await translateInterface(language);
1552
- }
1553
- }
1554
-
1555
- // Show language landing page
1556
- function showLanguageLanding() {
1557
- document.getElementById('languageLanding').style.display = 'block';
1558
- document.getElementById('mainApp').style.display = 'none';
1559
- }
1560
-
1561
- // Show main application
1562
- function showMainApp() {
1563
- document.getElementById('languageLanding').style.display = 'none';
1564
- document.getElementById('mainApp').style.display = 'block';
1565
-
1566
- // Set API key in main app
1567
- document.getElementById('apiKey').value = currentApiKey;
1568
- }
1569
-
1570
- // Start button click handler
1571
- document.getElementById('startBtn').addEventListener('click', async function() {
1572
- const selectedLanguage = document.getElementById('languageSelect').value;
1573
- const apiKey = document.getElementById('apiKeyLanding').value.trim();
1574
-
1575
- if (!apiKey) {
1576
- alert('Please enter your OpenAI API key');
1577
- return;
1578
- }
1579
-
1580
- currentLanguage = selectedLanguage;
1581
- currentApiKey = apiKey;
1582
-
1583
- // Save API key
1584
- localStorage.setItem('aiCognitiveStrategy_apiKey', apiKey);
1585
-
1586
- // Apply language with translation (cached or API)
1587
- await applyLanguage(selectedLanguage);
1588
-
1589
- // Show main app
1590
- showMainApp();
1591
- });
1592
-
1593
- // Language selector change handler
1594
- document.getElementById('languageSelect').addEventListener('change', async function() {
1595
- const selectedLanguage = this.value;
1596
- updateCacheStatus(selectedLanguage);
1597
-
1598
- if (currentApiKey) {
1599
- await applyLanguage(selectedLanguage);
1600
- } else {
1601
- applyDirection(selectedLanguage);
1602
- }
1603
- });
1604
-
1605
- // Clear cache button handler
1606
- document.getElementById('clearCacheBtn').addEventListener('click', clearAllTranslationCache);
1607
-
1608
- // API key sync between landing and main app
1609
- document.getElementById('apiKeyLanding').addEventListener('input', function() {
1610
- currentApiKey = this.value;
1611
- localStorage.setItem('aiCognitiveStrategy_apiKey', this.value);
1612
- document.getElementById('apiKey').value = this.value;
1613
- });
1614
-
1615
- document.getElementById('apiKey').addEventListener('input', function() {
1616
- currentApiKey = this.value;
1617
- localStorage.setItem('aiCognitiveStrategy_apiKey', this.value);
1618
- document.getElementById('apiKeyLanding').value = this.value;
1619
- });
1620
-
1621
- // Scroll-based progress bar
1622
- window.addEventListener('scroll', () => {
1623
- const { scrollTop, scrollHeight } = document.documentElement;
1624
- const scrolled = (scrollTop / (scrollHeight - window.innerHeight)) * 100;
1625
- document.getElementById('progressBar').style.width = `${scrolled}%`;
1626
- });
1627
-
1628
- // API Service Module
1629
- const APIService = {
1630
- async callOpenAI(prompt, apiKey) {
1631
- const payload = {
1632
- model: AppConfig.MODEL,
1633
- messages: [{ role: 'user', content: prompt }],
1634
- max_tokens: AppConfig.MAX_TOKENS,
1635
- temperature: AppConfig.TEMPERATURE
1636
- };
1637
-
1638
- const response = await fetch(AppConfig.API_BASE_URL, {
1639
- method: 'POST',
1640
- headers: {
1641
- 'Content-Type': 'application/json',
1642
- 'Authorization': `Bearer ${apiKey}`
1643
- },
1644
- body: JSON.stringify(payload)
1645
- });
1646
-
1647
- if (!response.ok) {
1648
- const errorData = await response.json();
1649
- throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`);
1650
- }
1651
-
1652
- const data = await response.json();
1653
- return data.choices[0].message.content;
1654
- }
1655
- };
1656
-
1657
- // Prompt Builder Module
1658
- const PromptBuilder = {
1659
- buildCompositePrompt(userPrompt) {
1660
- const languageName = languageNames[currentLanguage] || 'English';
1661
-
1662
- return `**Important: Generate the entire response in ${languageName}. All content, headings, explanations, and strategy elements must be written in ${languageName}.**
1663
-
1664
- You are a professional educational strategist and cognitive scientist specializing in AI integration in learning. Based on the prompt provided below, generate two distinct sections in your response:
1665
-
1666
- Section 1: Critical Thinking Strategies
1667
- - Describe innovative ways in which AI can enhance cognitive abilities and boost learner confidence.
1668
- - Provide actionable recommendations and examples.
1669
-
1670
- Section 2: Mitigation Strategies
1671
- - Suggest methods to minimize the negative impacts of generative AI on cognitive skills.
1672
- - Provide practical recommendations and safeguards to protect cognitive development.
1673
-
1674
- Your response must be tailored to the prompt and presented in a clear, structured format with appropriate headings in ${languageName}.
1675
-
1676
- Prompt:
1677
- <<<BEGIN PROMPT>>>
1678
- ${userPrompt}
1679
- <<<END PROMPT>>>
1680
-
1681
- Output only the final enhanced prompt in ${languageName}.
1682
- `.trim();
1683
- }
1684
- };
1685
-
1686
- // UI Controller Module
1687
- const UIController = {
1688
- elements: {},
1689
-
1690
- init() {
1691
- this.elements = {
1692
- apiKeyInput: document.getElementById('apiKey'),
1693
- promptTextarea: document.getElementById('userPrompt'),
1694
- generateBtn: document.getElementById('generateBtn'),
1695
- loadingSpinner: document.getElementById('loadingSpinner'),
1696
- buttonText: document.querySelector('.button-text'),
1697
- outputArea: document.getElementById('outputArea'),
1698
- copyBtn: document.getElementById('copyBtn'),
1699
- characterCounter: document.getElementById('characterCounter')
1700
- };
1701
-
1702
- this.setupEventListeners();
1703
- this.updateCharacterCounter();
1704
- },
1705
-
1706
- setupEventListeners() {
1707
- this.elements.apiKeyInput.addEventListener('input', (e) => {
1708
- AppState.setApiKey(e.target.value.trim());
1709
- });
1710
-
1711
- this.elements.promptTextarea.addEventListener('input', () => {
1712
- this.updateCharacterCounter();
1713
- });
1714
-
1715
- this.elements.generateBtn.addEventListener('click', () => {
1716
- App.handleSubmit();
1717
- });
1718
-
1719
- this.elements.copyBtn.addEventListener('click', () => {
1720
- this.copyToClipboard();
1721
- });
1722
-
1723
- // Keyboard shortcuts
1724
- document.addEventListener('keydown', (e) => {
1725
- if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
1726
- e.preventDefault();
1727
- App.handleSubmit();
1728
- }
1729
- });
1730
- },
1731
-
1732
- updateCharacterCounter() {
1733
- const length = this.elements.promptTextarea.value.length;
1734
- const maxLength = AppConfig.MAX_PROMPT_LENGTH;
1735
- this.elements.characterCounter.textContent = `${length} / ${maxLength}`;
1736
-
1737
- if (length > maxLength * 0.9) {
1738
- this.elements.characterCounter.style.color = 'var(--color-warning)';
1739
- } else {
1740
- this.elements.characterCounter.style.color = 'var(--color-text-muted)';
1741
- }
1742
- },
1743
-
1744
- updateLoadingState(isLoading) {
1745
- if (isLoading) {
1746
- this.elements.generateBtn.disabled = true;
1747
- this.elements.buttonText.style.opacity = '0';
1748
- this.elements.loadingSpinner.style.display = 'block';
1749
- } else {
1750
- this.elements.generateBtn.disabled = false;
1751
- this.elements.buttonText.style.opacity = '1';
1752
- this.elements.loadingSpinner.style.display = 'none';
1753
- }
1754
- },
1755
-
1756
- displayResults(content) {
1757
- this.elements.outputArea.innerHTML = this.formatOutput(content);
1758
- this.elements.copyBtn.style.display = 'inline-flex';
1759
- AppState.lastResult = content;
1760
-
1761
- // Announce to screen readers
1762
- this.announceToScreenReader('Strategy generation completed. Results are now available.');
1763
- },
1764
-
1765
- formatOutput(content) {
1766
- // Basic markdown-like formatting
1767
- return content
1768
- .replace(/^# (.*$)/gm, '<h1>$1</h1>')
1769
- .replace(/^## (.*$)/gm, '<h2>$1</h2>')
1770
- .replace(/^### (.*$)/gm, '<h3>$1</h3>')
1771
- .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
1772
- .replace(/\*(.*?)\*/g, '<em>$1</em>')
1773
- .replace(/\n\n/g, '</p><p>')
1774
- .replace(/^(.*)$/gm, '<p>$1</p>')
1775
- .replace(/<p><\/p>/g, '')
1776
- .replace(/<p>(<h[1-6]>.*?<\/h[1-6]>)<\/p>/g, '$1');
1777
- },
1778
-
1779
- showError(message) {
1780
- const errorHtml = `
1781
- <div class="error-message">
1782
- <span class="error-icon">⚠️</span>
1783
- <span class="error-text">${message}</span>
1784
- <button class="error-dismiss" onclick="this.parentElement.remove()">×</button>
1785
- </div>
1786
- `;
1787
-
1788
- this.elements.outputArea.innerHTML = errorHtml + this.elements.outputArea.innerHTML;
1789
- this.announceToScreenReader(`Error: ${message}`);
1790
- },
1791
-
1792
- async copyToClipboard() {
1793
- try {
1794
- await navigator.clipboard.writeText(AppState.lastResult);
1795
-
1796
- // Visual feedback
1797
- const originalText = this.elements.copyBtn.innerHTML;
1798
- this.elements.copyBtn.innerHTML = '<span>✅</span> Copied!';
1799
-
1800
- setTimeout(() => {
1801
- this.elements.copyBtn.innerHTML = originalText;
1802
- }, 2000);
1803
-
1804
- this.announceToScreenReader('Content copied to clipboard');
1805
- } catch (err) {
1806
- console.error('Failed to copy:', err);
1807
- this.announceToScreenReader('Failed to copy content');
1808
- }
1809
- },
1810
-
1811
- announceToScreenReader(message) {
1812
- const announcement = document.createElement('div');
1813
- announcement.setAttribute('aria-live', 'polite');
1814
- announcement.setAttribute('aria-atomic', 'true');
1815
- announcement.className = 'sr-only';
1816
- announcement.textContent = message;
1817
- document.body.appendChild(announcement);
1818
-
1819
- setTimeout(() => {
1820
- document.body.removeChild(announcement);
1821
- }, 1000);
1822
- }
1823
- };
1824
-
1825
- // Error Handler Module
1826
- const ErrorHandler = {
1827
- handleError(error) {
1828
- console.error('Application error:', error);
1829
-
1830
- let userMessage = 'An unexpected error occurred. Please try again.';
1831
-
1832
- if (error.message.includes('API key')) {
1833
- userMessage = 'Invalid API key. Please check your OpenAI API key and try again.';
1834
- } else if (error.message.includes('network') || error.message.includes('fetch')) {
1835
- userMessage = 'Network error. Please check your internet connection and try again.';
1836
- } else if (error.message.includes('rate limit')) {
1837
- userMessage = 'Rate limit exceeded. Please wait a moment before trying again.';
1838
- } else if (error.message.includes('quota')) {
1839
- userMessage = 'API quota exceeded. Please check your OpenAI account usage.';
1840
- }
1841
-
1842
- UIController.showError(userMessage);
1843
- }
1844
- };
1845
-
1846
- // Input Validator Module
1847
- const InputValidator = {
1848
- validateApiKey(apiKey) {
1849
- if (!apiKey || apiKey.length < 10) {
1850
- throw new Error('Please enter a valid OpenAI API key.');
1851
- }
1852
-
1853
- if (!apiKey.startsWith('sk-')) {
1854
- throw new Error('OpenAI API key should start with "sk-".');
1855
- }
1856
-
1857
- return true;
1858
- },
1859
-
1860
- validatePrompt(prompt) {
1861
- if (!prompt || prompt.trim().length === 0) {
1862
- throw new Error('Please enter a prompt before generating strategies.');
1863
- }
1864
-
1865
- if (prompt.length > AppConfig.MAX_PROMPT_LENGTH) {
1866
- throw new Error(`Prompt is too long. Maximum ${AppConfig.MAX_PROMPT_LENGTH} characters allowed.`);
1867
- }
1868
-
1869
- return true;
1870
- }
1871
- };
1872
-
1873
- // Main App Module
1874
- const App = {
1875
- init() {
1876
- AppState.loadFromLocalStorage();
1877
- UIController.init();
1878
-
1879
- // Load saved API key
1880
- if (AppState.apiKey) {
1881
- UIController.elements.apiKeyInput.value = AppState.apiKey;
1882
- }
1883
-
1884
- console.log('AI Cognitive Strategy Generator initialized');
1885
- },
1886
-
1887
- async handleSubmit() {
1888
- if (AppState.isLoading) return;
1889
-
1890
- try {
1891
- const apiKey = UIController.elements.apiKeyInput.value.trim();
1892
- const userPrompt = UIController.elements.promptTextarea.value.trim();
1893
-
1894
- // Validate inputs
1895
- InputValidator.validateApiKey(apiKey);
1896
- InputValidator.validatePrompt(userPrompt);
1897
-
1898
- // Update state
1899
- AppState.setApiKey(apiKey);
1900
- AppState.currentPrompt = userPrompt;
1901
- AppState.setLoading(true);
1902
-
1903
- // Build composite prompt
1904
- const compositePrompt = PromptBuilder.buildCompositePrompt(userPrompt);
1905
- console.log('Composite Prompt:', compositePrompt);
1906
-
1907
- // Call API
1908
- const result = await APIService.callOpenAI(compositePrompt, apiKey);
1909
-
1910
- // Display results
1911
- UIController.displayResults(result);
1912
-
1913
- } catch (error) {
1914
- ErrorHandler.handleError(error);
1915
- } finally {
1916
- AppState.setLoading(false);
1917
- }
1918
- }
1919
- };
1920
-
1921
- // Initialize app when DOM is loaded
1922
- document.addEventListener('DOMContentLoaded', function() {
1923
- initializeApp();
1924
- App.init();
1925
- });
1926
- </script>
1927
- </body>
1928
- </html>
1929
-