Multimedix commited on
Commit
a248e91
·
verified ·
1 Parent(s): b9f9cc1

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +599 -19
index.html CHANGED
@@ -1,19 +1,599 @@
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="de">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Fokus & Flow - Aufgabenliste mit Spracheingabe</title>
7
+
8
+ <!-- Google Fonts -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700&display=swap" rel="stylesheet">
12
+
13
+ <!-- Font Awesome -->
14
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
15
+
16
+ <style>
17
+ :root {
18
+ /* Light Theme Variables */
19
+ --bg-color: #f3f4f6;
20
+ --text-color: #1f2937;
21
+ --card-bg: #ffffff;
22
+ --primary-color: #6366f1; /* Indigo */
23
+ --secondary-color: #a855f7; /* Purple */
24
+ --accent-color: #10b981; /* Emerald */
25
+ --danger-color: #ef4444;
26
+ --border-color: #e5e7eb;
27
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
28
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
29
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
30
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
31
+ --font-main: 'Outfit', sans-serif;
32
+ }
33
+
34
+ [data-theme="dark"] {
35
+ /* Dark Theme Variables */
36
+ --bg-color: #0f172a;
37
+ --text-color: #f3f4f6;
38
+ --card-bg: #1e293b;
39
+ --primary-color: #818cf8;
40
+ --secondary-color: #c084fc;
41
+ --accent-color: #34d399;
42
+ --danger-color: #f87171;
43
+ --border-color: #334155;
44
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
45
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.3);
46
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.3);
47
+ }
48
+
49
+ * {
50
+ margin: 0;
51
+ padding: 0;
52
+ box-sizing: border-box;
53
+ }
54
+
55
+ body {
56
+ font-family: var(--font-main);
57
+ background-color: var(--bg-color);
58
+ color: var(--text-color);
59
+ transition: var(--transition);
60
+ min-height: 100vh;
61
+ display: flex;
62
+ flex-direction: column;
63
+ overflow-x: hidden;
64
+ }
65
+
66
+ /* --- Header --- */
67
+ header {
68
+ background: rgba(255, 255, 255, 0.0);
69
+ backdrop-filter: blur(10px);
70
+ padding: 1rem 2rem;
71
+ display: flex;
72
+ justify-content: space-between;
73
+ align-items: center;
74
+ position: sticky;
75
+ top: 0;
76
+ z-index: 100;
77
+ border-bottom: 1px solid var(--border-color);
78
+ background-color: var(--card-bg);
79
+ }
80
+
81
+ .logo {
82
+ font-size: 1.5rem;
83
+ font-weight: 700;
84
+ background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
85
+ -webkit-background-clip: text;
86
+ background-clip: text;
87
+ color: transparent;
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 0.5rem;
91
+ }
92
+
93
+ .anycoder-link {
94
+ font-size: 0.9rem;
95
+ font-weight: 600;
96
+ color: var(--text-color);
97
+ text-decoration: none;
98
+ padding: 0.5rem 1rem;
99
+ border-radius: 2rem;
100
+ background: linear-gradient(90deg, rgba(99, 102, 241, 0.1), rgba(168, 85, 247, 0.1));
101
+ border: 1px solid var(--border-color);
102
+ transition: var(--transition);
103
+ }
104
+
105
+ .anycoder-link:hover {
106
+ transform: translateY(-2px);
107
+ box-shadow: var(--shadow-md);
108
+ background: linear-gradient(90deg, rgba(99, 102, 241, 0.2), rgba(168, 85, 247, 0.2));
109
+ }
110
+
111
+ .theme-toggle {
112
+ background: none;
113
+ border: none;
114
+ color: var(--text-color);
115
+ font-size: 1.2rem;
116
+ cursor: pointer;
117
+ padding: 0.5rem;
118
+ border-radius: 50%;
119
+ transition: var(--transition);
120
+ }
121
+
122
+ .theme-toggle:hover {
123
+ background-color: rgba(128, 128, 128, 0.1);
124
+ }
125
+
126
+ /* --- Main Layout --- */
127
+ main {
128
+ flex: 1;
129
+ padding: 2rem;
130
+ width: 100%;
131
+ display: flex;
132
+ justify-content: center;
133
+ align-items: flex-start;
134
+ }
135
+
136
+ .card {
137
+ background-color: var(--card-bg);
138
+ border-radius: 1.5rem;
139
+ padding: 2rem;
140
+ box-shadow: var(--shadow-md);
141
+ border: 1px solid var(--border-color);
142
+ transition: var(--transition);
143
+ display: flex;
144
+ flex-direction: column;
145
+ width: 100%;
146
+ max-width: 700px; /* Centered width */
147
+ min-height: 600px;
148
+ }
149
+
150
+ .card:hover {
151
+ box-shadow: var(--shadow-lg);
152
+ }
153
+
154
+ h2 {
155
+ font-size: 1.5rem;
156
+ margin-bottom: 2rem;
157
+ font-weight: 700;
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 0.75rem;
161
+ color: var(--text-color);
162
+ }
163
+
164
+ .btn {
165
+ padding: 0.75rem 1.5rem;
166
+ border-radius: 0.75rem;
167
+ border: none;
168
+ font-weight: 600;
169
+ cursor: pointer;
170
+ transition: var(--transition);
171
+ font-family: var(--font-main);
172
+ display: flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+ gap: 0.5rem;
176
+ font-size: 1rem;
177
+ }
178
+
179
+ .btn-primary {
180
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
181
+ color: white;
182
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
183
+ }
184
+
185
+ .btn-primary:hover {
186
+ filter: brightness(1.1);
187
+ box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4);
188
+ }
189
+
190
+ .btn-icon {
191
+ background-color: transparent;
192
+ border: 1px solid var(--border-color);
193
+ color: var(--text-color);
194
+ padding: 0.75rem;
195
+ width: 50px; /* Fixed width for icon button */
196
+ }
197
+
198
+ .btn-icon:hover {
199
+ border-color: var(--primary-color);
200
+ color: var(--primary-color);
201
+ background-color: rgba(99, 102, 241, 0.05);
202
+ }
203
+
204
+ /* Recording Animation */
205
+ .btn-icon.recording {
206
+ background-color: var(--danger-color);
207
+ color: white;
208
+ border-color: var(--danger-color);
209
+ animation: pulse 1.5s infinite;
210
+ }
211
+
212
+ @keyframes pulse {
213
+ 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
214
+ 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
215
+ 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
216
+ }
217
+
218
+ /* --- Tasks Section --- */
219
+ .task-input-group {
220
+ display: flex;
221
+ gap: 0.75rem;
222
+ margin-bottom: 2rem;
223
+ }
224
+
225
+ .task-input {
226
+ flex: 1;
227
+ padding: 1rem;
228
+ border-radius: 0.75rem;
229
+ border: 1px solid var(--border-color);
230
+ background-color: var(--bg-color);
231
+ color: var(--text-color);
232
+ outline: none;
233
+ font-family: var(--font-main);
234
+ font-size: 1rem;
235
+ transition: var(--transition);
236
+ }
237
+
238
+ .task-input:focus {
239
+ border-color: var(--primary-color);
240
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
241
+ }
242
+
243
+ .task-list {
244
+ list-style: none;
245
+ overflow-y: auto;
246
+ flex: 1; /* Fill remaining space */
247
+ padding-right: 0.5rem;
248
+ }
249
+
250
+ /* Custom Scrollbar */
251
+ .task-list::-webkit-scrollbar {
252
+ width: 6px;
253
+ }
254
+ .task-list::-webkit-scrollbar-track {
255
+ background: transparent;
256
+ }
257
+ .task-list::-webkit-scrollbar-thumb {
258
+ background-color: var(--border-color);
259
+ border-radius: 20px;
260
+ }
261
+
262
+ .task-item {
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: space-between;
266
+ padding: 1rem;
267
+ background-color: var(--bg-color);
268
+ border-radius: 1rem;
269
+ margin-bottom: 0.75rem;
270
+ border: 1px solid transparent;
271
+ transition: var(--transition);
272
+ animation: slideIn 0.3s ease;
273
+ }
274
+
275
+ @keyframes slideIn {
276
+ from { opacity: 0; transform: translateY(10px); }
277
+ to { opacity: 1; transform: translateY(0); }
278
+ }
279
+
280
+ .task-item:hover {
281
+ border-color: var(--primary-color);
282
+ transform: translateX(4px);
283
+ }
284
+
285
+ .task-content {
286
+ display: flex;
287
+ align-items: center;
288
+ gap: 1rem;
289
+ flex: 1;
290
+ cursor: pointer;
291
+ }
292
+
293
+ .custom-checkbox {
294
+ width: 24px;
295
+ height: 24px;
296
+ border: 2px solid var(--primary-color);
297
+ border-radius: 8px;
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ transition: var(--transition);
302
+ flex-shrink: 0;
303
+ }
304
+
305
+ .task-item.completed .custom-checkbox {
306
+ background-color: var(--primary-color);
307
+ }
308
+
309
+ .custom-checkbox i {
310
+ color: white;
311
+ font-size: 0.8rem;
312
+ opacity: 0;
313
+ transform: scale(0);
314
+ transition: var(--transition);
315
+ }
316
+
317
+ .task-item.completed .custom-checkbox i {
318
+ opacity: 1;
319
+ transform: scale(1);
320
+ }
321
+
322
+ .task-text {
323
+ transition: var(--transition);
324
+ font-size: 1.05rem;
325
+ word-break: break-word;
326
+ }
327
+
328
+ .task-item.completed .task-text {
329
+ text-decoration: line-through;
330
+ color: #9ca3af;
331
+ }
332
+
333
+ .delete-btn {
334
+ background: none;
335
+ border: none;
336
+ color: #9ca3af;
337
+ cursor: pointer;
338
+ padding: 0.5rem;
339
+ margin-left: 0.5rem;
340
+ transition: var(--transition);
341
+ border-radius: 0.5rem;
342
+ }
343
+
344
+ .delete-btn:hover {
345
+ color: var(--danger-color);
346
+ background-color: rgba(239, 68, 68, 0.1);
347
+ }
348
+
349
+ .empty-state {
350
+ text-align: center;
351
+ color: #9ca3af;
352
+ margin-top: 4rem;
353
+ display: none;
354
+ }
355
+
356
+ .empty-state i {
357
+ font-size: 3rem;
358
+ margin-bottom: 1rem;
359
+ opacity: 0.5;
360
+ }
361
+
362
+ /* Footer */
363
+ footer {
364
+ text-align: center;
365
+ padding: 2rem;
366
+ color: #6b7280;
367
+ font-size: 0.9rem;
368
+ margin-top: auto;
369
+ }
370
+
371
+ /* Mobile Responsiveness */
372
+ @media (max-width: 640px) {
373
+ header {
374
+ flex-direction: column;
375
+ gap: 1rem;
376
+ }
377
+ main {
378
+ padding: 1rem;
379
+ }
380
+ .card {
381
+ min-height: auto;
382
+ padding: 1.5rem;
383
+ }
384
+ .task-input-group {
385
+ flex-wrap: wrap;
386
+ }
387
+ .task-input {
388
+ width: 100%;
389
+ min-width: 100%;
390
+ }
391
+ #micBtn, #addTaskBtn {
392
+ flex: 1;
393
+ }
394
+ }
395
+ </style>
396
+ </head>
397
+ <body>
398
+
399
+ <header>
400
+ <div class="logo">
401
+ <i class="fa-solid fa-check-double"></i> Fokus & Flow
402
+ </div>
403
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with anycoder</a>
404
+ <button class="theme-toggle" id="themeToggle" aria-label="Thema wechseln">
405
+ <i class="fa-solid fa-moon"></i>
406
+ </button>
407
+ </header>
408
+
409
+ <main>
410
+ <!-- Tasks Section (Sole Focus) -->
411
+ <section class="card tasks-section">
412
+ <h2><i class="fa-solid fa-list-check" style="color: var(--secondary-color)"></i> Deine Aufgaben</h2>
413
+
414
+ <div class="task-input-group">
415
+ <input type="text" class="task-input" id="taskInput" placeholder="Was möchtest du erledigen?">
416
+
417
+ <!-- Microphone Button -->
418
+ <button class="btn btn-icon" id="micBtn" aria-label="Spracheingabe starten">
419
+ <i class="fa-solid fa-microphone"></i>
420
+ </button>
421
+
422
+ <button class="btn btn-primary" id="addTaskBtn">
423
+ <i class="fa-solid fa-plus"></i> <span class="btn-text">Hinzufügen</span>
424
+ </button>
425
+ </div>
426
+
427
+ <div class="empty-state" id="emptyState">
428
+ <i class="fa-solid fa-clipboard-list"></i>
429
+ <p>Keine Aufgaben vorhanden. <br>Füge eine neue Aufgabe hinzu!</p>
430
+ </div>
431
+
432
+ <ul class="task-list" id="taskList">
433
+ <!-- Tasks will be added here -->
434
+ </ul>
435
+ </section>
436
+ </main>
437
+
438
+ <footer>
439
+ &copy; 2023 Fokus & Flow. Alle Rechte vorbehalten.
440
+ </footer>
441
+
442
+ <script>
443
+ // --- Theme Logic ---
444
+ const themeToggle = document.getElementById('themeToggle');
445
+ const body = document.body;
446
+ const icon = themeToggle.querySelector('i');
447
+
448
+ // Check local storage
449
+ if (localStorage.getItem('theme') === 'dark') {
450
+ body.setAttribute('data-theme', 'dark');
451
+ icon.classList.replace('fa-moon', 'fa-sun');
452
+ }
453
+
454
+ themeToggle.addEventListener('click', () => {
455
+ if (body.getAttribute('data-theme') === 'dark') {
456
+ body.removeAttribute('data-theme');
457
+ localStorage.setItem('theme', 'light');
458
+ icon.classList.replace('fa-sun', 'fa-moon');
459
+ } else {
460
+ body.setAttribute('data-theme', 'dark');
461
+ localStorage.setItem('theme', 'dark');
462
+ icon.classList.replace('fa-moon', 'fa-sun');
463
+ }
464
+ });
465
+
466
+ // --- Task Logic ---
467
+ const taskInput = document.getElementById('taskInput');
468
+ const addTaskBtn = document.getElementById('addTaskBtn');
469
+ const taskList = document.getElementById('taskList');
470
+ const emptyState = document.getElementById('emptyState');
471
+ const micBtn = document.getElementById('micBtn');
472
+
473
+ let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
474
+
475
+ function renderTasks() {
476
+ taskList.innerHTML = '';
477
+
478
+ if (tasks.length === 0) {
479
+ emptyState.style.display = 'block';
480
+ } else {
481
+ emptyState.style.display = 'none';
482
+ }
483
+
484
+ tasks.forEach((task, index) => {
485
+ const li = document.createElement('li');
486
+ li.className = `task-item ${task.completed ? 'completed' : ''}`;
487
+
488
+ li.innerHTML = `
489
+ <div class="task-content" onclick="toggleTask(${index})">
490
+ <div class="custom-checkbox">
491
+ <i class="fa-solid fa-check"></i>
492
+ </div>
493
+ <span class="task-text">${escapeHtml(task.text)}</span>
494
+ </div>
495
+ <button class="delete-btn" onclick="deleteTask(${index})" aria-label="Löschen">
496
+ <i class="fa-solid fa-trash"></i>
497
+ </button>
498
+ `;
499
+ taskList.appendChild(li);
500
+ });
501
+
502
+ localStorage.setItem('tasks', JSON.stringify(tasks));
503
+ }
504
+
505
+ function addTask() {
506
+ const text = taskInput.value.trim();
507
+ if (text) {
508
+ tasks.push({ text, completed: false });
509
+ taskInput.value = '';
510
+ renderTasks();
511
+ taskInput.focus();
512
+ }
513
+ }
514
+
515
+ // Helper to prevent XSS
516
+ function escapeHtml(text) {
517
+ const map = {
518
+ '&': '&amp;',
519
+ '<': '&lt;',
520
+ '>': '&gt;',
521
+ '"': '&quot;',
522
+ "'": '&#039;'
523
+ };
524
+ return text.replace(/[&<>"']/g, function(m) { return map[m]; });
525
+ }
526
+
527
+ window.toggleTask = (index) => {
528
+ tasks[index].completed = !tasks[index].completed;
529
+ renderTasks();
530
+ };
531
+
532
+ window.deleteTask = (index) => {
533
+ tasks.splice(index, 1);
534
+ renderTasks();
535
+ };
536
+
537
+ addTaskBtn.addEventListener('click', addTask);
538
+ taskInput.addEventListener('keypress', (e) => {
539
+ if (e.key === 'Enter') addTask();
540
+ });
541
+
542
+ // --- Speech Recognition Logic ---
543
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
544
+
545
+ if (SpeechRecognition) {
546
+ const recognition = new SpeechRecognition();
547
+ recognition.continuous = false;
548
+ recognition.lang = 'de-DE';
549
+ recognition.interimResults = false;
550
+
551
+ micBtn.addEventListener('click', () => {
552
+ if (micBtn.classList.contains('recording')) {
553
+ recognition.stop();
554
+ } else {
555
+ recognition.start();
556
+ }
557
+ });
558
+
559
+ recognition.onstart = () => {
560
+ micBtn.classList.add('recording');
561
+ micBtn.querySelector('i').classList.remove('fa-microphone');
562
+ micBtn.querySelector('i').classList.add('fa-microphone-lines');
563
+ };
564
+
565
+ recognition.onend = () => {
566
+ micBtn.classList.remove('recording');
567
+ micBtn.querySelector('i').classList.add('fa-microphone');
568
+ micBtn.querySelector('i').classList.remove('fa-microphone-lines');
569
+ };
570
+
571
+ recognition.onresult = (event) => {
572
+ const transcript = event.results[0][0].transcript;
573
+
574
+ // Append if there is already text, otherwise set
575
+ if (taskInput.value.trim().length > 0) {
576
+ taskInput.value += ' ' + transcript;
577
+ } else {
578
+ taskInput.value = transcript;
579
+ }
580
+
581
+ taskInput.focus();
582
+ };
583
+
584
+ recognition.onerror = (event) => {
585
+ console.error('Speech recognition error', event.error);
586
+ micBtn.classList.remove('recording');
587
+ alert('Spracherkennung fehlgeschlagen oder keine Berechtigung.');
588
+ };
589
+ } else {
590
+ // Hide mic button if not supported
591
+ micBtn.style.display = 'none';
592
+ console.log('Web Speech API not supported in this browser.');
593
+ }
594
+
595
+ // Initialize
596
+ renderTasks();
597
+ </script>
598
+ </body>
599
+ </html>