Multimedix commited on
Commit
f013dd0
·
verified ·
1 Parent(s): df015a9

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1217 -19
index.html CHANGED
@@ -1,19 +1,1217 @@
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>Haushaltsbuch Pro - Ausgaben & Einnahmen Tracker</title>
7
+
8
+ <!-- Chart.js -->
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+
11
+ <!-- Lucide Icons -->
12
+ <script src="https://unpkg.com/lucide@latest"></script>
13
+
14
+ <style>
15
+ * {
16
+ margin: 0;
17
+ padding: 0;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ :root {
22
+ --primary: #6366f1;
23
+ --primary-dark: #4f46e5;
24
+ --secondary: #22d3ee;
25
+ --success: #10b981;
26
+ --danger: #ef4444;
27
+ --warning: #f59e0b;
28
+ --dark: #1e293b;
29
+ --light: #f8fafc;
30
+ --gray: #64748b;
31
+ --border: #e2e8f0;
32
+ --shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
33
+ --shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
34
+ }
35
+
36
+ body {
37
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
38
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
39
+ min-height: 100vh;
40
+ color: var(--dark);
41
+ }
42
+
43
+ .container {
44
+ max-width: 1400px;
45
+ margin: 0 auto;
46
+ padding: 20px;
47
+ }
48
+
49
+ header {
50
+ background: rgba(255, 255, 255, 0.98);
51
+ border-radius: 20px;
52
+ padding: 25px 30px;
53
+ margin-bottom: 30px;
54
+ box-shadow: var(--shadow-lg);
55
+ backdrop-filter: blur(10px);
56
+ animation: slideDown 0.5s ease-out;
57
+ }
58
+
59
+ .header-content {
60
+ display: flex;
61
+ justify-content: space-between;
62
+ align-items: center;
63
+ flex-wrap: wrap;
64
+ gap: 20px;
65
+ }
66
+
67
+ .logo {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 15px;
71
+ }
72
+
73
+ .logo i {
74
+ width: 45px;
75
+ height: 45px;
76
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
77
+ border-radius: 12px;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ color: white;
82
+ }
83
+
84
+ .logo h1 {
85
+ font-size: 28px;
86
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
87
+ -webkit-background-clip: text;
88
+ -webkit-text-fill-color: transparent;
89
+ }
90
+
91
+ .header-actions {
92
+ display: flex;
93
+ gap: 12px;
94
+ flex-wrap: wrap;
95
+ }
96
+
97
+ .btn {
98
+ padding: 10px 20px;
99
+ border: none;
100
+ border-radius: 10px;
101
+ font-size: 14px;
102
+ font-weight: 600;
103
+ cursor: pointer;
104
+ transition: all 0.3s ease;
105
+ display: inline-flex;
106
+ align-items: center;
107
+ gap: 8px;
108
+ white-space: nowrap;
109
+ }
110
+
111
+ .btn-primary {
112
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
113
+ color: white;
114
+ }
115
+
116
+ .btn-primary:hover {
117
+ transform: translateY(-2px);
118
+ box-shadow: 0 10px 20px -5px rgba(99, 102, 241, 0.5);
119
+ }
120
+
121
+ .btn-secondary {
122
+ background: white;
123
+ color: var(--dark);
124
+ border: 2px solid var(--border);
125
+ }
126
+
127
+ .btn-secondary:hover {
128
+ background: var(--light);
129
+ border-color: var(--primary);
130
+ color: var(--primary);
131
+ }
132
+
133
+ .btn-success {
134
+ background: var(--success);
135
+ color: white;
136
+ }
137
+
138
+ .btn-danger {
139
+ background: var(--danger);
140
+ color: white;
141
+ }
142
+
143
+ .dashboard {
144
+ display: grid;
145
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
146
+ gap: 20px;
147
+ margin-bottom: 30px;
148
+ }
149
+
150
+ .stat-card {
151
+ background: rgba(255, 255, 255, 0.98);
152
+ padding: 25px;
153
+ border-radius: 15px;
154
+ box-shadow: var(--shadow);
155
+ transition: all 0.3s ease;
156
+ animation: fadeInUp 0.5s ease-out;
157
+ position: relative;
158
+ overflow: hidden;
159
+ }
160
+
161
+ .stat-card::before {
162
+ content: '';
163
+ position: absolute;
164
+ top: 0;
165
+ left: 0;
166
+ width: 4px;
167
+ height: 100%;
168
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
169
+ }
170
+
171
+ .stat-card:hover {
172
+ transform: translateY(-5px);
173
+ box-shadow: var(--shadow-lg);
174
+ }
175
+
176
+ .stat-card.income::before {
177
+ background: var(--success);
178
+ }
179
+
180
+ .stat-card.expense::before {
181
+ background: var(--danger);
182
+ }
183
+
184
+ .stat-card.balance::before {
185
+ background: var(--warning);
186
+ }
187
+
188
+ .stat-label {
189
+ font-size: 13px;
190
+ color: var(--gray);
191
+ text-transform: uppercase;
192
+ letter-spacing: 1px;
193
+ margin-bottom: 8px;
194
+ display: flex;
195
+ align-items: center;
196
+ gap: 8px;
197
+ }
198
+
199
+ .stat-value {
200
+ font-size: 28px;
201
+ font-weight: 700;
202
+ color: var(--dark);
203
+ }
204
+
205
+ .main-content {
206
+ display: grid;
207
+ grid-template-columns: 1fr 1fr;
208
+ gap: 30px;
209
+ margin-bottom: 30px;
210
+ }
211
+
212
+ @media (max-width: 968px) {
213
+ .main-content {
214
+ grid-template-columns: 1fr;
215
+ }
216
+ }
217
+
218
+ .card {
219
+ background: rgba(255, 255, 255, 0.98);
220
+ border-radius: 20px;
221
+ padding: 30px;
222
+ box-shadow: var(--shadow-lg);
223
+ animation: fadeInUp 0.6s ease-out;
224
+ }
225
+
226
+ .card-header {
227
+ display: flex;
228
+ justify-content: space-between;
229
+ align-items: center;
230
+ margin-bottom: 25px;
231
+ padding-bottom: 15px;
232
+ border-bottom: 2px solid var(--border);
233
+ }
234
+
235
+ .card-title {
236
+ font-size: 20px;
237
+ font-weight: 700;
238
+ color: var(--dark);
239
+ display: flex;
240
+ align-items: center;
241
+ gap: 10px;
242
+ }
243
+
244
+ .form-group {
245
+ margin-bottom: 20px;
246
+ }
247
+
248
+ label {
249
+ display: block;
250
+ font-size: 14px;
251
+ font-weight: 600;
252
+ color: var(--dark);
253
+ margin-bottom: 8px;
254
+ }
255
+
256
+ input, select, textarea {
257
+ width: 100%;
258
+ padding: 12px 15px;
259
+ border: 2px solid var(--border);
260
+ border-radius: 10px;
261
+ font-size: 14px;
262
+ transition: all 0.3s ease;
263
+ background: white;
264
+ }
265
+
266
+ input:focus, select:focus, textarea:focus {
267
+ outline: none;
268
+ border-color: var(--primary);
269
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
270
+ }
271
+
272
+ .input-group {
273
+ display: flex;
274
+ gap: 10px;
275
+ }
276
+
277
+ .input-group input {
278
+ flex: 1;
279
+ }
280
+
281
+ .transaction-list {
282
+ max-height: 400px;
283
+ overflow-y: auto;
284
+ padding-right: 10px;
285
+ }
286
+
287
+ .transaction-list::-webkit-scrollbar {
288
+ width: 6px;
289
+ }
290
+
291
+ .transaction-list::-webkit-scrollbar-track {
292
+ background: var(--light);
293
+ border-radius: 10px;
294
+ }
295
+
296
+ .transaction-list::-webkit-scrollbar-thumb {
297
+ background: var(--gray);
298
+ border-radius: 10px;
299
+ }
300
+
301
+ .transaction-item {
302
+ display: flex;
303
+ justify-content: space-between;
304
+ align-items: center;
305
+ padding: 15px;
306
+ margin-bottom: 12px;
307
+ background: var(--light);
308
+ border-radius: 12px;
309
+ transition: all 0.3s ease;
310
+ animation: slideIn 0.3s ease-out;
311
+ }
312
+
313
+ .transaction-item:hover {
314
+ background: white;
315
+ box-shadow: 0 5px 15px -3px rgba(0, 0, 0, 0.1);
316
+ transform: translateX(5px);
317
+ }
318
+
319
+ .transaction-info {
320
+ flex: 1;
321
+ }
322
+
323
+ .transaction-category {
324
+ display: inline-block;
325
+ padding: 4px 10px;
326
+ background: var(--primary);
327
+ color: white;
328
+ border-radius: 20px;
329
+ font-size: 11px;
330
+ font-weight: 600;
331
+ text-transform: uppercase;
332
+ margin-right: 10px;
333
+ }
334
+
335
+ .transaction-date {
336
+ font-size: 12px;
337
+ color: var(--gray);
338
+ margin-top: 5px;
339
+ }
340
+
341
+ .transaction-amount {
342
+ font-size: 18px;
343
+ font-weight: 700;
344
+ margin-right: 15px;
345
+ }
346
+
347
+ .transaction-amount.income {
348
+ color: var(--success);
349
+ }
350
+
351
+ .transaction-amount.expense {
352
+ color: var(--danger);
353
+ }
354
+
355
+ .delete-btn {
356
+ background: none;
357
+ border: none;
358
+ color: var(--danger);
359
+ cursor: pointer;
360
+ padding: 5px;
361
+ transition: all 0.3s ease;
362
+ }
363
+
364
+ .delete-btn:hover {
365
+ transform: scale(1.2);
366
+ }
367
+
368
+ .chart-container {
369
+ position: relative;
370
+ height: 300px;
371
+ margin-top: 20px;
372
+ }
373
+
374
+ .tabs {
375
+ display: flex;
376
+ gap: 10px;
377
+ margin-bottom: 20px;
378
+ border-bottom: 2px solid var(--border);
379
+ }
380
+
381
+ .tab {
382
+ padding: 12px 20px;
383
+ background: none;
384
+ border: none;
385
+ font-size: 14px;
386
+ font-weight: 600;
387
+ color: var(--gray);
388
+ cursor: pointer;
389
+ transition: all 0.3s ease;
390
+ position: relative;
391
+ }
392
+
393
+ .tab.active {
394
+ color: var(--primary);
395
+ }
396
+
397
+ .tab.active::after {
398
+ content: '';
399
+ position: absolute;
400
+ bottom: -2px;
401
+ left: 0;
402
+ right: 0;
403
+ height: 2px;
404
+ background: var(--primary);
405
+ }
406
+
407
+ .tab-content {
408
+ display: none;
409
+ }
410
+
411
+ .tab-content.active {
412
+ display: block;
413
+ animation: fadeIn 0.3s ease-out;
414
+ }
415
+
416
+ .modal {
417
+ display: none;
418
+ position: fixed;
419
+ top: 0;
420
+ left: 0;
421
+ width: 100%;
422
+ height: 100%;
423
+ background: rgba(0, 0, 0, 0.5);
424
+ backdrop-filter: blur(5px);
425
+ z-index: 1000;
426
+ animation: fadeIn 0.3s ease-out;
427
+ }
428
+
429
+ .modal.active {
430
+ display: flex;
431
+ align-items: center;
432
+ justify-content: center;
433
+ }
434
+
435
+ .modal-content {
436
+ background: white;
437
+ padding: 30px;
438
+ border-radius: 20px;
439
+ max-width: 500px;
440
+ width: 90%;
441
+ max-height: 80vh;
442
+ overflow-y: auto;
443
+ animation: slideUp 0.3s ease-out;
444
+ }
445
+
446
+ .modal-header {
447
+ display: flex;
448
+ justify-content: space-between;
449
+ align-items: center;
450
+ margin-bottom: 20px;
451
+ }
452
+
453
+ .modal-title {
454
+ font-size: 24px;
455
+ font-weight: 700;
456
+ color: var(--dark);
457
+ }
458
+
459
+ .close-modal {
460
+ background: none;
461
+ border: none;
462
+ font-size: 24px;
463
+ color: var(--gray);
464
+ cursor: pointer;
465
+ transition: all 0.3s ease;
466
+ }
467
+
468
+ .close-modal:hover {
469
+ color: var(--danger);
470
+ transform: rotate(90deg);
471
+ }
472
+
473
+ .file-input-wrapper {
474
+ position: relative;
475
+ overflow: hidden;
476
+ display: inline-block;
477
+ width: 100%;
478
+ }
479
+
480
+ .file-input-wrapper input[type=file] {
481
+ position: absolute;
482
+ left: -9999px;
483
+ }
484
+
485
+ .file-input-label {
486
+ display: block;
487
+ padding: 12px 20px;
488
+ background: var(--light);
489
+ border: 2px dashed var(--border);
490
+ border-radius: 10px;
491
+ text-align: center;
492
+ cursor: pointer;
493
+ transition: all 0.3s ease;
494
+ }
495
+
496
+ .file-input-label:hover {
497
+ background: white;
498
+ border-color: var(--primary);
499
+ }
500
+
501
+ .toast {
502
+ position: fixed;
503
+ bottom: 30px;
504
+ right: 30px;
505
+ padding: 15px 20px;
506
+ background: white;
507
+ border-radius: 10px;
508
+ box-shadow: var(--shadow-lg);
509
+ display: none;
510
+ align-items: center;
511
+ gap: 10px;
512
+ animation: slideInRight 0.3s ease-out;
513
+ z-index: 2000;
514
+ }
515
+
516
+ .toast.show {
517
+ display: flex;
518
+ }
519
+
520
+ .toast.success {
521
+ border-left: 4px solid var(--success);
522
+ }
523
+
524
+ .toast.error {
525
+ border-left: 4px solid var(--danger);
526
+ }
527
+
528
+ .toast.info {
529
+ border-left: 4px solid var(--primary);
530
+ }
531
+
532
+ @keyframes slideDown {
533
+ from {
534
+ opacity: 0;
535
+ transform: translateY(-20px);
536
+ }
537
+ to {
538
+ opacity: 1;
539
+ transform: translateY(0);
540
+ }
541
+ }
542
+
543
+ @keyframes fadeInUp {
544
+ from {
545
+ opacity: 0;
546
+ transform: translateY(20px);
547
+ }
548
+ to {
549
+ opacity: 1;
550
+ transform: translateY(0);
551
+ }
552
+ }
553
+
554
+ @keyframes slideIn {
555
+ from {
556
+ opacity: 0;
557
+ transform: translateX(-20px);
558
+ }
559
+ to {
560
+ opacity: 1;
561
+ transform: translateX(0);
562
+ }
563
+ }
564
+
565
+ @keyframes slideUp {
566
+ from {
567
+ opacity: 0;
568
+ transform: translateY(20px);
569
+ }
570
+ to {
571
+ opacity: 1;
572
+ transform: translateY(0);
573
+ }
574
+ }
575
+
576
+ @keyframes slideInRight {
577
+ from {
578
+ transform: translateX(100%);
579
+ }
580
+ to {
581
+ transform: translateX(0);
582
+ }
583
+ }
584
+
585
+ @keyframes fadeIn {
586
+ from {
587
+ opacity: 0;
588
+ }
589
+ to {
590
+ opacity: 1;
591
+ }
592
+ }
593
+
594
+ .footer {
595
+ text-align: center;
596
+ padding: 20px;
597
+ color: white;
598
+ font-size: 14px;
599
+ }
600
+
601
+ .footer a {
602
+ color: var(--secondary);
603
+ text-decoration: none;
604
+ font-weight: 600;
605
+ transition: all 0.3s ease;
606
+ }
607
+
608
+ .footer a:hover {
609
+ text-decoration: underline;
610
+ }
611
+
612
+ @media (max-width: 768px) {
613
+ .container {
614
+ padding: 10px;
615
+ }
616
+
617
+ .header-content {
618
+ flex-direction: column;
619
+ text-align: center;
620
+ }
621
+
622
+ .dashboard {
623
+ grid-template-columns: 1fr;
624
+ }
625
+
626
+ .card {
627
+ padding: 20px;
628
+ }
629
+
630
+ .modal-content {
631
+ padding: 20px;
632
+ }
633
+ }
634
+ </style>
635
+ </head>
636
+ <body>
637
+ <div class="container">
638
+ <header>
639
+ <div class="header-content">
640
+ <div class="logo">
641
+ <i data-lucide="wallet"></i>
642
+ <h1>Haushaltsbuch Pro</h1>
643
+ </div>
644
+ <div class="header-actions">
645
+ <button class="btn btn-secondary" onclick="openImportModal()">
646
+ <i data-lucide="upload" style="width: 16px; height: 16px;"></i>
647
+ CSV Import
648
+ </button>
649
+ <button class="btn btn-secondary" onclick="exportCSV()">
650
+ <i data-lucide="download" style="width: 16px; height: 16px;"></i>
651
+ CSV Export
652
+ </button>
653
+ <button class="btn btn-danger" onclick="clearAllData()">
654
+ <i data-lucide="trash-2" style="width: 16px; height: 16px;"></i>
655
+ Alle Daten löschen
656
+ </button>
657
+ </div>
658
+ </div>
659
+ </header>
660
+
661
+ <div class="dashboard">
662
+ <div class="stat-card income">
663
+ <div class="stat-label">
664
+ <i data-lucide="trending-up" style="width: 16px; height: 16px;"></i>
665
+ Gesamteinnahmen
666
+ </div>
667
+ <div class="stat-value" id="totalIncome">€0,00</div>
668
+ </div>
669
+ <div class="stat-card expense">
670
+ <div class="stat-label">
671
+ <i data-lucide="trending-down" style="width: 16px; height: 16px;"></i>
672
+ Gesamtausgaben
673
+ </div>
674
+ <div class="stat-value" id="totalExpense">€0,00</div>
675
+ </div>
676
+ <div class="stat-card balance">
677
+ <div class="stat-label">
678
+ <i data-lucide="balance" style="width: 16px; height: 16px;"></i>
679
+ Kontostand
680
+ </div>
681
+ <div class="stat-value" id="balance">€0,00</div>
682
+ </div>
683
+ </div>
684
+
685
+ <div class="main-content">
686
+ <div class="card">
687
+ <div class="card-header">
688
+ <h2 class="card-title">
689
+ <i data-lucide="plus-circle"></i>
690
+ Neue Transaktion
691
+ </h2>
692
+ </div>
693
+ <form id="transactionForm">
694
+ <div class="form-group">
695
+ <label for="type">Typ</label>
696
+ <select id="type" required>
697
+ <option value="">Bitte wählen</option>
698
+ <option value="income">Einnahme</option>
699
+ <option value="expense">Ausgabe</option>
700
+ </select>
701
+ </div>
702
+ <div class="form-group">
703
+ <label for="amount">Betrag (€)</label>
704
+ <input type="number" id="amount" step="0.01" min="0" placeholder="0,00" required>
705
+ </div>
706
+ <div class="form-group">
707
+ <label for="category">Kategorie</label>
708
+ <select id="category" required>
709
+ <option value="">Bitte wählen</option>
710
+ </select>
711
+ </div>
712
+ <div class="form-group">
713
+ <label for="description">Beschreibung</label>
714
+ <input type="text" id="description" placeholder="z.B. Lebensmittel, Gehalt, Miete" required>
715
+ </div>
716
+ <div class="form-group">
717
+ <label for="date">Datum</label>
718
+ <input type="date" id="date" required>
719
+ </div>
720
+ <button type="submit" class="btn btn-primary" style="width: 100%;">
721
+ <i data-lucide="save" style="width: 16px; height: 16px;"></i>
722
+ Transaktion speichern
723
+ </button>
724
+ </form>
725
+ </div>
726
+
727
+ <div class="card">
728
+ <div class="card-header">
729
+ <h2 class="card-title">
730
+ <i data-lucide="list"></i>
731
+ Letzte Transaktionen
732
+ </h2>
733
+ <button class="btn btn-secondary" onclick="refreshTransactions()">
734
+ <i data-lucide="refresh-cw" style="width: 16px; height: 16px;"></i>
735
+ </button>
736
+ </div>
737
+ <div class="transaction-list" id="transactionList">
738
+ <!-- Transactions will be added here -->
739
+ </div>
740
+ </div>
741
+ </div>
742
+
743
+ <div class="card">
744
+ <div class="card-header">
745
+ <h2 class="card-title">
746
+ <i data-lucide="bar-chart-2"></i>
747
+ Auswertungen
748
+ </h2>
749
+ </div>
750
+ <div class="tabs">
751
+ <button class="tab active" onclick="switchTab('monthly')">Monatlich</button>
752
+ <button class="tab" onclick="switchTab('category')">Nach Kategorie</button>
753
+ <button class="tab" onclick="switchTab('trend')">Trend</button>
754
+ </div>
755
+ <div class="tab-content active" id="monthly-tab">
756
+ <div class="chart-container">
757
+ <canvas id="monthlyChart"></canvas>
758
+ </div>
759
+ </div>
760
+ <div class="tab-content" id="category-tab">
761
+ <div class="chart-container">
762
+ <canvas id="categoryChart"></canvas>
763
+ </div>
764
+ </div>
765
+ <div class="tab-content" id="trend-tab">
766
+ <div class="chart-container">
767
+ <canvas id="trendChart"></canvas>
768
+ </div>
769
+ </div>
770
+ </div>
771
+
772
+ <footer class="footer">
773
+ <p>© 2024 Haushaltsbuch Pro | Gebaut mit <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p>
774
+ </footer>
775
+ </div>
776
+
777
+ <!-- Import Modal -->
778
+ <div class="modal" id="importModal">
779
+ <div class="modal-content">
780
+ <div class="modal-header">
781
+ <h3 class="modal-title">CSV Import</h3>
782
+ <button class="close-modal" onclick="closeImportModal()">×</button>
783
+ </div>
784
+ <div class="form-group">
785
+ <label>Wählen Sie eine CSV-Datei aus</label>
786
+ <div class="file-input-wrapper">
787
+ <input type="file" id="csvFile" accept=".csv" onchange="handleFileSelect(event)">
788
+ <label for="csvFile" class="file-input-label">
789
+ <i data-lucide="file-text" style="width: 24px; height: 24px; margin-bottom: 10px;"></i>
790
+ <div>Klicken Sie hier oder ziehen Sie eine Datei hierher</div>
791
+ <div style="font-size: 12px; color: var(--gray); margin-top: 5px;">
792
+ Format: Typ,Betrag,Kategorie,Beschreibung,Datum
793
+ </div>
794
+ </label>
795
+ </div>
796
+ </div>
797
+ <button class="btn btn-primary" onclick="importCSV()" style="width: 100%; margin-top: 20px;">
798
+ Importieren
799
+ </button>
800
+ </div>
801
+ </div>
802
+
803
+ <!-- Toast Notification -->
804
+ <div class="toast" id="toast">
805
+ <i data-lucide="check-circle" style="width: 20px; height: 20px;"></i>
806
+ <span id="toastMessage"></span>
807
+ </div>
808
+
809
+ <script>
810
+ // Initialize Lucide icons
811
+ lucide.createIcons();
812
+
813
+ // Data Management
814
+ let transactions = JSON.parse(localStorage.getItem('transactions')) || [];
815
+ let monthlyChart, categoryChart, trendChart;
816
+
817
+ // Categories
818
+ const incomeCategories = ['Gehalt', 'Nebeneinkommen', 'Investitionen', 'Geschenk', 'Rückerstattung', 'Sonstige'];
819
+ const expenseCategories = ['Lebensmittel', 'Miete', 'Transport', 'Unterhaltung', 'Rechnungen', 'Gesundheit', 'Kleidung', 'Bildung', 'Restaurants', 'Shopping', 'Sonstige'];
820
+
821
+ // Initialize
822
+ document.addEventListener('DOMContentLoaded', function() {
823
+ // Set today's date
824
+ document.getElementById('date').valueAsDate = new Date();
825
+
826
+ // Update categories based on type
827
+ document.getElementById('type').addEventListener('change', updateCategories);
828
+
829
+ // Form submission
830
+ document.getElementById('transactionForm').addEventListener('submit', addTransaction);
831
+
832
+ // Initial load
833
+ updateDashboard();
834
+ displayTransactions();
835
+ initializeCharts();
836
+ });
837
+
838
+ function updateCategories() {
839
+ const type = document.getElementById('type').value;
840
+ const categorySelect = document.getElementById('category');
841
+ categorySelect.innerHTML = '<option value="">Bitte wählen</option>';
842
+
843
+ const categories = type === 'income' ? incomeCategories : expenseCategories;
844
+ categories.forEach(cat => {
845
+ categorySelect.innerHTML += `<option value="${cat}">${cat}</option>`;
846
+ });
847
+ }
848
+
849
+ function addTransaction(e) {
850
+ e.preventDefault();
851
+
852
+ const transaction = {
853
+ id: Date.now(),
854
+ type: document.getElementById('type').value,
855
+ amount: parseFloat(document.getElementById('amount').value),
856
+ category: document.getElementById('category').value,
857
+ description: document.getElementById('description').value,
858
+ date: document.getElementById('date').value
859
+ };
860
+
861
+ transactions.unshift(transaction);
862
+ saveTransactions();
863
+
864
+ // Reset form
865
+ document.getElementById('transactionForm').reset();
866
+ document.getElementById('date').valueAsDate = new Date();
867
+
868
+ // Update UI
869
+ updateDashboard();
870
+ displayTransactions();
871
+ updateCharts();
872
+
873
+ showToast('Transaktion erfolgreich hinzugefügt!', 'success');
874
+ }
875
+
876
+ function deleteTransaction(id) {
877
+ if (confirm('Möchten Sie diese Transaktion wirklich löschen?')) {
878
+ transactions = transactions.filter(t => t.id !== id);
879
+ saveTransactions();
880
+ updateDashboard();
881
+ displayTransactions();
882
+ updateCharts();
883
+ showToast('Transaktion gelöscht', 'info');
884
+ }
885
+ }
886
+
887
+ function saveTransactions() {
888
+ localStorage.setItem('transactions', JSON.stringify(transactions));
889
+ }
890
+
891
+ function updateDashboard() {
892
+ const income = transactions
893
+ .filter(t => t.type === 'income')
894
+ .reduce((sum, t) => sum + t.amount, 0);
895
+
896
+ const expense = transactions
897
+ .filter(t => t.type === 'expense')
898
+ .reduce((sum, t) => sum + t.amount, 0);
899
+
900
+ const balance = income - expense;
901
+
902
+ document.getElementById('totalIncome').textContent = formatCurrency(income);
903
+ document.getElementById('totalExpense').textContent = formatCurrency(expense);
904
+ document.getElementById('balance').textContent = formatCurrency(balance);
905
+
906
+ // Update balance color
907
+ const balanceElement = document.getElementById('balance');
908
+ if (balance < 0) {
909
+ balanceElement.style.color = 'var(--danger)';
910
+ } else if (balance > 0) {
911
+ balanceElement.style.color = 'var(--success)';
912
+ }
913
+ }
914
+
915
+ function displayTransactions() {
916
+ const listElement = document.getElementById('transactionList');
917
+ const recentTransactions = transactions.slice(0, 10);
918
+
919
+ if (recentTransactions.length === 0) {
920
+ listElement.innerHTML = '<div style="text-align: center; color: var(--gray); padding: 40px;">Keine Transaktionen vorhanden</div>';
921
+ return;
922
+ }
923
+
924
+ listElement.innerHTML = recentTransactions.map(t => `
925
+ <div class="transaction-item">
926
+ <div class="transaction-info">
927
+ <span class="transaction-category" style="background: ${t.type === 'income' ? 'var(--success)' : 'var(--danger)'}">
928
+ ${t.category}
929
+ </span>
930
+ <div style="font-weight: 600; margin-top: 5px;">${t.description}</div>
931
+ <div class="transaction-date">${formatDate(t.date)}</div>
932
+ </div>
933
+ <div class="transaction-amount ${t.type}">
934
+ ${t.type === 'income' ? '+' : '-'}${formatCurrency(t.amount)}
935
+ </div>
936
+ <button class="delete-btn" onclick="deleteTransaction(${t.id})">
937
+ <i data-lucide="trash-2" style="width: 18px; height: 18px;"></i>
938
+ </button>
939
+ </div>
940
+ `).join('');
941
+
942
+ // Re-initialize icons
943
+ lucide.createIcons();
944
+ }
945
+
946
+ function initializeCharts() {
947
+ // Monthly Chart
948
+ const monthlyCtx = document.getElementById('monthlyChart').getContext('2d');
949
+ monthlyChart = new Chart(monthlyCtx, {
950
+ type: 'bar',
951
+ data: {
952
+ labels: [],
953
+ datasets: [{
954
+ label: 'Einnahmen',
955
+ data: [],
956
+ backgroundColor: 'rgba(16, 185, 129, 0.8)',
957
+ borderRadius: 8
958
+ }, {
959
+ label: 'Ausgaben',
960
+ data: [],
961
+ backgroundColor: 'rgba(239, 68, 68, 0.8)',
962
+ borderRadius: 8
963
+ }]
964
+ },
965
+ options: {
966
+ responsive: true,
967
+ maintainAspectRatio: false,
968
+ plugins: {
969
+ legend: {
970
+ position: 'top',
971
+ }
972
+ },
973
+ scales: {
974
+ y: {
975
+ beginAtZero: true,
976
+ ticks: {
977
+ callback: function(value) {
978
+ return '€' + value.toLocaleString('de-DE');
979
+ }
980
+ }
981
+ }
982
+ }
983
+ }
984
+ });
985
+
986
+ // Category Chart
987
+ const categoryCtx = document.getElementById('categoryChart').getContext('2d');
988
+ categoryChart = new Chart(categoryCtx, {
989
+ type: 'doughnut',
990
+ data: {
991
+ labels: [],
992
+ datasets: [{
993
+ data: [],
994
+ backgroundColor: [
995
+ '#6366f1', '#8b5cf6', '#ec4899', '#f43f5e',
996
+ '#ef4444', '#f97316', '#f59e0b', '#eab308',
997
+ '#84cc16', '#22c55e', '#10b981', '#14b8a6'
998
+ ],
999
+ borderWidth: 0
1000
+ }]
1001
+ },
1002
+ options: {
1003
+ responsive: true,
1004
+ maintainAspectRatio: false,
1005
+ plugins: {
1006
+ legend: {
1007
+ position: 'right',
1008
+ }
1009
+ }
1010
+ }
1011
+ });
1012
+
1013
+ // Trend Chart
1014
+ const trendCtx = document.getElementById('trendChart').getContext('2d');
1015
+ trendChart = new Chart(trendCtx, {
1016
+ type: 'line',
1017
+ data: {
1018
+ labels: [],
1019
+ datasets: [{
1020
+ label: 'Kontostand',
1021
+ data: [],
1022
+ borderColor: '#6366f1',
1023
+ backgroundColor: 'rgba(99, 102, 241, 0.1)',
1024
+ tension: 0.4,
1025
+ fill: true
1026
+ }]
1027
+ },
1028
+ options: {
1029
+ responsive: true,
1030
+ maintainAspectRatio: false,
1031
+ plugins: {
1032
+ legend: {
1033
+ display: false
1034
+ }
1035
+ },
1036
+ scales: {
1037
+ y: {
1038
+ beginAtZero: false,
1039
+ ticks: {
1040
+ callback: function(value) {
1041
+ return '€' + value.toLocaleString('de-DE');
1042
+ }
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+ });
1048
+
1049
+ updateCharts();
1050
+ }
1051
+
1052
+ function updateCharts() {
1053
+ // Update Monthly Chart
1054
+ const monthlyData = getMonthlyData();
1055
+ monthlyChart.data.labels = monthlyData.labels;
1056
+ monthlyChart.data.datasets[0].data = monthlyData.income;
1057
+ monthlyChart.data.datasets[1].data = monthlyData.expense;
1058
+ monthlyChart.update();
1059
+
1060
+ // Update Category Chart
1061
+ const categoryData = getCategoryData();
1062
+ categoryChart.data.labels = categoryData.labels;
1063
+ categoryChart.data.datasets[0].data = categoryData.data;
1064
+ categoryChart.update();
1065
+
1066
+ // Update Trend Chart
1067
+ const trendData = getTrendData();
1068
+ trendChart.data.labels = trendData.labels;
1069
+ trendChart.data.datasets[0].data = trendData.balance;
1070
+ trendChart.update();
1071
+ }
1072
+
1073
+ function getMonthlyData() {
1074
+ const last6Months = [];
1075
+ const incomeData = [];
1076
+ const expenseData = [];
1077
+
1078
+ for (let i = 5; i >= 0; i--) {
1079
+ const date = new Date();
1080
+ date.setMonth(date.getMonth() - i);
1081
+ const monthKey = date.toISOString().slice(0, 7);
1082
+
1083
+ const monthTransactions = transactions.filter(t => t.date.startsWith(monthKey));
1084
+ const income = monthTransactions
1085
+ .filter(t => t.type === 'income')
1086
+ .reduce((sum, t) => sum + t.amount, 0);
1087
+ const expense = monthTransactions
1088
+ .filter(t => t.type === 'expense')
1089
+ .reduce((sum, t) => sum + t.amount, 0);
1090
+
1091
+ const monthName = date.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
1092
+ last6Months.push(monthName);
1093
+ incomeData.push(income);
1094
+ expenseData.push(expense);
1095
+ }
1096
+
1097
+ return {
1098
+ labels: last6Months,
1099
+ income: incomeData,
1100
+ expense: expenseData
1101
+ };
1102
+ }
1103
+
1104
+ function getCategoryData() {
1105
+ const categoryTotals = {};
1106
+
1107
+ transactions
1108
+ .filter(t => t.type === 'expense')
1109
+ .forEach(t => {
1110
+ categoryTotals[t.category] = (categoryTotals[t.category] || 0) + t.amount;
1111
+ });
1112
+
1113
+ return {
1114
+ labels: Object.keys(categoryTotals),
1115
+ data: Object.values(categoryTotals)
1116
+ };
1117
+ }
1118
+
1119
+ function getTrendData() {
1120
+ const sortedTransactions = [...transactions].sort((a, b) => new Date(a.date) - new Date(b.date));
1121
+ const labels = [];
1122
+ const balanceData = [];
1123
+ let runningBalance = 0;
1124
+
1125
+ sortedTransactions.forEach(t => {
1126
+ if (t.type === 'income') {
1127
+ runningBalance += t.amount;
1128
+ } else {
1129
+ runningBalance -= t.amount;
1130
+ }
1131
+
1132
+ labels.push(formatDate(t.date));
1133
+ balanceData.push(runningBalance);
1134
+ });
1135
+
1136
+ return {
1137
+ labels: labels.slice(-30), // Last 30 transactions
1138
+ balance: balanceData.slice(-30)
1139
+ };
1140
+ }
1141
+
1142
+ function switchTab(tabName) {
1143
+ // Update tabs
1144
+ document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
1145
+ event.target.classList.add('active');
1146
+
1147
+ // Update content
1148
+ document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
1149
+ document.getElementById(`${tabName}-tab`).classList.add('active');
1150
+ }
1151
+
1152
+ function refreshTransactions() {
1153
+ displayTransactions();
1154
+ showToast('Transaktionen aktualisiert', 'info');
1155
+ }
1156
+
1157
+ function openImportModal() {
1158
+ document.getElementById('importModal').classList.add('active');
1159
+ }
1160
+
1161
+ function closeImportModal() {
1162
+ document.getElementById('importModal').classList.remove('active');
1163
+ }
1164
+
1165
+ function handleFileSelect(event) {
1166
+ const file = event.target.files[0];
1167
+ if (file) {
1168
+ const fileName = file.name;
1169
+ document.querySelector('.file-input-label div').textContent = fileName;
1170
+ }
1171
+ }
1172
+
1173
+ function importCSV() {
1174
+ const fileInput = document.getElementById('csvFile');
1175
+ const file = fileInput.files[0];
1176
+
1177
+ if (!file) {
1178
+ showToast('Bitte wählen Sie eine Datei aus', 'error');
1179
+ return;
1180
+ }
1181
+
1182
+ const reader = new FileReader();
1183
+ reader.onload = function(e) {
1184
+ try {
1185
+ const lines = e.target.result.split('\n');
1186
+ const newTransactions = [];
1187
+
1188
+ lines.forEach((line, index) => {
1189
+ if (index === 0 || !line.trim()) return; // Skip header or empty lines
1190
+
1191
+ const parts = line.split(',');
1192
+ if (parts.length >= 5) {
1193
+ const transaction = {
1194
+ id: Date.now() + index,
1195
+ type: parts[0].trim(),
1196
+ amount: parseFloat(parts[1].trim()),
1197
+ category: parts[2].trim(),
1198
+ description: parts[3].trim(),
1199
+ date: parts[4].trim()
1200
+ };
1201
+
1202
+ if (transaction.type && !isNaN(transaction.amount) && transaction.category && transaction.description && transaction.date) {
1203
+ newTransactions.push(transaction);
1204
+ }
1205
+ }
1206
+ });
1207
+
1208
+ if (newTransactions.length > 0) {
1209
+ transactions = [...newTransactions, ...transactions];
1210
+ saveTransactions();
1211
+ updateDashboard();
1212
+ displayTransactions();
1213
+ updateCharts();
1214
+ closeImportModal();
1215
+ showToast(`${newTransactions.length} Transaktionen importiert`, 'success');
1216
+ } else {
1217
+ showToast('Keine gültigen Transaktionen in der Datei