NOT-OMEGA commited on
Commit
967075f
·
verified ·
1 Parent(s): 73966a8

Delete frontend

Browse files
frontend/css/main.css DELETED
@@ -1,891 +0,0 @@
1
- /* ============================================
2
- AutoForge — Design System
3
- Dark developer-tool UI with glassmorphism
4
- ============================================ */
5
-
6
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
7
-
8
- /* ── CSS Variables ─────────────────────────── */
9
-
10
- :root {
11
- /* Base palette */
12
- --bg-primary: #0a0e17;
13
- --bg-secondary: #111827;
14
- --bg-tertiary: #1a2236;
15
- --bg-card: rgba(17, 24, 39, 0.7);
16
- --bg-glass: rgba(17, 24, 39, 0.5);
17
-
18
- /* Accent palette */
19
- --accent-primary: #6366f1;
20
- --accent-secondary: #818cf8;
21
- --accent-glow: rgba(99, 102, 241, 0.3);
22
- --accent-success: #34d399;
23
- --accent-warning: #fbbf24;
24
- --accent-danger: #f87171;
25
- --accent-info: #38bdf8;
26
-
27
- /* Gradients */
28
- --gradient-brand: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%);
29
- --gradient-card: linear-gradient(135deg, rgba(99,102,241,0.08) 0%, rgba(168,85,247,0.05) 100%);
30
- --gradient-glow: radial-gradient(600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(99,102,241,0.06), transparent 40%);
31
-
32
- /* Text */
33
- --text-primary: #f1f5f9;
34
- --text-secondary: #94a3b8;
35
- --text-muted: #64748b;
36
- --text-on-accent: #ffffff;
37
-
38
- /* Borders */
39
- --border-primary: rgba(148, 163, 184, 0.1);
40
- --border-secondary: rgba(148, 163, 184, 0.06);
41
- --border-accent: rgba(99, 102, 241, 0.3);
42
-
43
- /* Sizing */
44
- --sidebar-width: 260px;
45
- --header-height: 64px;
46
- --radius-sm: 6px;
47
- --radius-md: 10px;
48
- --radius-lg: 16px;
49
- --radius-xl: 20px;
50
-
51
- /* Shadows */
52
- --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
53
- --shadow-md: 0 4px 12px rgba(0,0,0,0.3);
54
- --shadow-lg: 0 8px 30px rgba(0,0,0,0.4);
55
- --shadow-glow: 0 0 20px var(--accent-glow);
56
-
57
- /* Timing */
58
- --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
59
- --transition-normal: 250ms cubic-bezier(0.4, 0, 0.2, 1);
60
- --transition-slow: 400ms cubic-bezier(0.4, 0, 0.2, 1);
61
-
62
- /* Typography */
63
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
64
- --font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
65
- }
66
-
67
-
68
- /* ── Reset ─────────────────────────────────── */
69
-
70
- *, *::before, *::after {
71
- box-sizing: border-box;
72
- margin: 0;
73
- padding: 0;
74
- }
75
-
76
- html {
77
- font-size: 16px;
78
- scroll-behavior: smooth;
79
- -webkit-font-smoothing: antialiased;
80
- -moz-osx-font-smoothing: grayscale;
81
- }
82
-
83
- body {
84
- font-family: var(--font-sans);
85
- background: var(--bg-primary);
86
- color: var(--text-primary);
87
- line-height: 1.6;
88
- min-height: 100vh;
89
- overflow-x: hidden;
90
- }
91
-
92
- a {
93
- color: var(--accent-secondary);
94
- text-decoration: none;
95
- transition: color var(--transition-fast);
96
- }
97
-
98
- a:hover {
99
- color: var(--accent-primary);
100
- }
101
-
102
- button {
103
- font-family: inherit;
104
- cursor: pointer;
105
- }
106
-
107
- input, textarea, select {
108
- font-family: inherit;
109
- }
110
-
111
-
112
- /* ── Animated Background ───────────────────── */
113
-
114
- .bg-mesh {
115
- position: fixed;
116
- inset: 0;
117
- z-index: -1;
118
- background: var(--bg-primary);
119
- overflow: hidden;
120
- }
121
-
122
- .bg-mesh::before {
123
- content: '';
124
- position: absolute;
125
- top: -50%;
126
- left: -50%;
127
- width: 200%;
128
- height: 200%;
129
- background:
130
- radial-gradient(ellipse 600px 600px at 20% 30%, rgba(99,102,241,0.08) 0%, transparent 70%),
131
- radial-gradient(ellipse 500px 500px at 80% 20%, rgba(168,85,247,0.06) 0%, transparent 70%),
132
- radial-gradient(ellipse 400px 400px at 60% 80%, rgba(236,72,153,0.04) 0%, transparent 70%);
133
- animation: meshFloat 20s ease-in-out infinite;
134
- }
135
-
136
- @keyframes meshFloat {
137
- 0%, 100% { transform: translate(0, 0) rotate(0deg); }
138
- 33% { transform: translate(2%, -2%) rotate(1deg); }
139
- 66% { transform: translate(-1%, 1%) rotate(-0.5deg); }
140
- }
141
-
142
-
143
- /* ── Login Page ────────────────────────────── */
144
-
145
- .login-container {
146
- display: flex;
147
- align-items: center;
148
- justify-content: center;
149
- min-height: 100vh;
150
- padding: 2rem;
151
- }
152
-
153
- .login-card {
154
- width: 100%;
155
- max-width: 420px;
156
- background: var(--bg-card);
157
- backdrop-filter: blur(20px);
158
- -webkit-backdrop-filter: blur(20px);
159
- border: 1px solid var(--border-primary);
160
- border-radius: var(--radius-xl);
161
- padding: 2.5rem;
162
- box-shadow: var(--shadow-lg);
163
- animation: cardAppear 0.6s var(--transition-slow) both;
164
- }
165
-
166
- @keyframes cardAppear {
167
- from {
168
- opacity: 0;
169
- transform: translateY(20px) scale(0.97);
170
- }
171
- to {
172
- opacity: 1;
173
- transform: translateY(0) scale(1);
174
- }
175
- }
176
-
177
- .login-logo {
178
- text-align: center;
179
- margin-bottom: 2rem;
180
- }
181
-
182
- .login-logo h1 {
183
- font-size: 1.75rem;
184
- font-weight: 700;
185
- background: var(--gradient-brand);
186
- -webkit-background-clip: text;
187
- -webkit-text-fill-color: transparent;
188
- background-clip: text;
189
- letter-spacing: -0.5px;
190
- }
191
-
192
- .login-logo p {
193
- color: var(--text-muted);
194
- font-size: 0.875rem;
195
- margin-top: 0.25rem;
196
- }
197
-
198
- .login-tabs {
199
- display: flex;
200
- gap: 0;
201
- margin-bottom: 1.5rem;
202
- border-radius: var(--radius-md);
203
- overflow: hidden;
204
- border: 1px solid var(--border-primary);
205
- }
206
-
207
- .login-tab {
208
- flex: 1;
209
- padding: 0.625rem;
210
- background: transparent;
211
- border: none;
212
- color: var(--text-muted);
213
- font-size: 0.875rem;
214
- font-weight: 500;
215
- transition: all var(--transition-fast);
216
- }
217
-
218
- .login-tab.active {
219
- background: var(--accent-primary);
220
- color: var(--text-on-accent);
221
- }
222
-
223
- .login-tab:hover:not(.active) {
224
- color: var(--text-primary);
225
- background: var(--bg-tertiary);
226
- }
227
-
228
-
229
- /* ── Forms ─────────────────────────────────── */
230
-
231
- .form-group {
232
- margin-bottom: 1.25rem;
233
- }
234
-
235
- .form-label {
236
- display: block;
237
- font-size: 0.8125rem;
238
- font-weight: 500;
239
- color: var(--text-secondary);
240
- margin-bottom: 0.375rem;
241
- letter-spacing: 0.02em;
242
- }
243
-
244
- .form-input {
245
- width: 100%;
246
- padding: 0.75rem 1rem;
247
- background: var(--bg-tertiary);
248
- border: 1px solid var(--border-primary);
249
- border-radius: var(--radius-md);
250
- color: var(--text-primary);
251
- font-size: 0.9375rem;
252
- transition: all var(--transition-fast);
253
- outline: none;
254
- }
255
-
256
- .form-input::placeholder {
257
- color: var(--text-muted);
258
- }
259
-
260
- .form-input:focus {
261
- border-color: var(--accent-primary);
262
- box-shadow: 0 0 0 3px var(--accent-glow);
263
- }
264
-
265
- .form-input:hover:not(:focus) {
266
- border-color: rgba(148, 163, 184, 0.2);
267
- }
268
-
269
- .form-error {
270
- display: none;
271
- margin-top: 1rem;
272
- padding: 0.75rem 1rem;
273
- background: rgba(248, 113, 113, 0.1);
274
- border: 1px solid rgba(248, 113, 113, 0.2);
275
- border-radius: var(--radius-sm);
276
- color: var(--accent-danger);
277
- font-size: 0.8125rem;
278
- animation: shake 0.3s ease-in-out;
279
- }
280
-
281
- .form-error.visible {
282
- display: block;
283
- }
284
-
285
- @keyframes shake {
286
- 0%, 100% { transform: translateX(0); }
287
- 25% { transform: translateX(-4px); }
288
- 75% { transform: translateX(4px); }
289
- }
290
-
291
-
292
- /* ── Buttons ───────────────────────────────── */
293
-
294
- .btn {
295
- display: inline-flex;
296
- align-items: center;
297
- justify-content: center;
298
- gap: 0.5rem;
299
- padding: 0.75rem 1.5rem;
300
- border: none;
301
- border-radius: var(--radius-md);
302
- font-size: 0.9375rem;
303
- font-weight: 600;
304
- transition: all var(--transition-fast);
305
- position: relative;
306
- overflow: hidden;
307
- }
308
-
309
- .btn::after {
310
- content: '';
311
- position: absolute;
312
- inset: 0;
313
- background: rgba(255,255,255,0);
314
- transition: background var(--transition-fast);
315
- }
316
-
317
- .btn:hover::after {
318
- background: rgba(255,255,255,0.06);
319
- }
320
-
321
- .btn:active {
322
- transform: scale(0.97);
323
- }
324
-
325
- .btn-primary {
326
- background: var(--gradient-brand);
327
- color: var(--text-on-accent);
328
- box-shadow: var(--shadow-glow);
329
- }
330
-
331
- .btn-primary:hover {
332
- box-shadow: 0 0 30px var(--accent-glow);
333
- }
334
-
335
- .btn-primary:disabled {
336
- opacity: 0.5;
337
- cursor: not-allowed;
338
- box-shadow: none;
339
- }
340
-
341
- .btn-secondary {
342
- background: var(--bg-tertiary);
343
- color: var(--text-primary);
344
- border: 1px solid var(--border-primary);
345
- }
346
-
347
- .btn-secondary:hover {
348
- border-color: var(--border-accent);
349
- }
350
-
351
- .btn-block {
352
- width: 100%;
353
- }
354
-
355
- .btn-sm {
356
- padding: 0.5rem 1rem;
357
- font-size: 0.8125rem;
358
- }
359
-
360
-
361
- /* ── App Layout ────────────────────────────── */
362
-
363
- .app-layout {
364
- display: flex;
365
- min-height: 100vh;
366
- }
367
-
368
- .sidebar {
369
- position: fixed;
370
- top: 0;
371
- left: 0;
372
- width: var(--sidebar-width);
373
- height: 100vh;
374
- background: var(--bg-card);
375
- backdrop-filter: blur(20px);
376
- -webkit-backdrop-filter: blur(20px);
377
- border-right: 1px solid var(--border-primary);
378
- display: flex;
379
- flex-direction: column;
380
- z-index: 100;
381
- transition: transform var(--transition-normal);
382
- }
383
-
384
- .sidebar-header {
385
- padding: 1.5rem;
386
- border-bottom: 1px solid var(--border-primary);
387
- }
388
-
389
- .sidebar-brand {
390
- font-size: 1.25rem;
391
- font-weight: 700;
392
- background: var(--gradient-brand);
393
- -webkit-background-clip: text;
394
- -webkit-text-fill-color: transparent;
395
- background-clip: text;
396
- }
397
-
398
- .sidebar-subtitle {
399
- font-size: 0.75rem;
400
- color: var(--text-muted);
401
- margin-top: 0.125rem;
402
- }
403
-
404
- .sidebar-nav {
405
- flex: 1;
406
- padding: 1rem 0.75rem;
407
- display: flex;
408
- flex-direction: column;
409
- gap: 0.25rem;
410
- }
411
-
412
- .nav-link {
413
- display: flex;
414
- align-items: center;
415
- gap: 0.75rem;
416
- padding: 0.75rem 1rem;
417
- border-radius: var(--radius-md);
418
- color: var(--text-secondary);
419
- font-size: 0.875rem;
420
- font-weight: 500;
421
- transition: all var(--transition-fast);
422
- text-decoration: none;
423
- position: relative;
424
- }
425
-
426
- .nav-link:hover {
427
- background: var(--bg-tertiary);
428
- color: var(--text-primary);
429
- }
430
-
431
- .nav-link.active {
432
- background: rgba(99, 102, 241, 0.12);
433
- color: var(--accent-secondary);
434
- }
435
-
436
- .nav-link.active::before {
437
- content: '';
438
- position: absolute;
439
- left: 0;
440
- top: 50%;
441
- transform: translateY(-50%);
442
- width: 3px;
443
- height: 60%;
444
- background: var(--accent-primary);
445
- border-radius: 0 2px 2px 0;
446
- }
447
-
448
- .nav-icon {
449
- font-size: 1.125rem;
450
- width: 1.25rem;
451
- text-align: center;
452
- }
453
-
454
- .sidebar-footer {
455
- padding: 1rem 0.75rem;
456
- border-top: 1px solid var(--border-primary);
457
- }
458
-
459
- .user-badge {
460
- display: flex;
461
- align-items: center;
462
- gap: 0.75rem;
463
- padding: 0.625rem 0.75rem;
464
- border-radius: var(--radius-md);
465
- transition: background var(--transition-fast);
466
- cursor: pointer;
467
- }
468
-
469
- .user-badge:hover {
470
- background: var(--bg-tertiary);
471
- }
472
-
473
- .user-avatar {
474
- width: 36px;
475
- height: 36px;
476
- border-radius: 50%;
477
- background: var(--gradient-brand);
478
- display: flex;
479
- align-items: center;
480
- justify-content: center;
481
- font-weight: 600;
482
- font-size: 0.875rem;
483
- color: var(--text-on-accent);
484
- flex-shrink: 0;
485
- }
486
-
487
- .user-info {
488
- overflow: hidden;
489
- }
490
-
491
- .user-name {
492
- font-size: 0.8125rem;
493
- font-weight: 600;
494
- color: var(--text-primary);
495
- white-space: nowrap;
496
- overflow: hidden;
497
- text-overflow: ellipsis;
498
- }
499
-
500
- .user-role {
501
- font-size: 0.6875rem;
502
- color: var(--text-muted);
503
- }
504
-
505
-
506
- /* ── Main Content ──────────────────────────── */
507
-
508
- .main-content {
509
- flex: 1;
510
- margin-left: var(--sidebar-width);
511
- min-height: 100vh;
512
- }
513
-
514
- .page-header {
515
- padding: 2rem 2.5rem 1.5rem;
516
- border-bottom: 1px solid var(--border-secondary);
517
- }
518
-
519
- .page-title {
520
- font-size: 1.5rem;
521
- font-weight: 700;
522
- letter-spacing: -0.5px;
523
- }
524
-
525
- .page-subtitle {
526
- font-size: 0.875rem;
527
- color: var(--text-muted);
528
- margin-top: 0.25rem;
529
- }
530
-
531
- .page-body {
532
- padding: 2rem 2.5rem;
533
- }
534
-
535
-
536
- /* ── Cards ─────────────────────────────────── */
537
-
538
- .card {
539
- background: var(--bg-card);
540
- backdrop-filter: blur(12px);
541
- border: 1px solid var(--border-primary);
542
- border-radius: var(--radius-lg);
543
- padding: 1.5rem;
544
- transition: all var(--transition-normal);
545
- }
546
-
547
- .card:hover {
548
- border-color: var(--border-accent);
549
- box-shadow: var(--shadow-glow);
550
- }
551
-
552
- .card-header {
553
- display: flex;
554
- align-items: center;
555
- justify-content: space-between;
556
- margin-bottom: 1rem;
557
- }
558
-
559
- .card-title {
560
- font-size: 1rem;
561
- font-weight: 600;
562
- }
563
-
564
-
565
- /* ── Stats Grid ────────────────────────────── */
566
-
567
- .stats-grid {
568
- display: grid;
569
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
570
- gap: 1.25rem;
571
- margin-bottom: 2rem;
572
- }
573
-
574
- .stat-card {
575
- background: var(--gradient-card);
576
- border: 1px solid var(--border-primary);
577
- border-radius: var(--radius-lg);
578
- padding: 1.25rem 1.5rem;
579
- transition: all var(--transition-normal);
580
- }
581
-
582
- .stat-card:hover {
583
- border-color: var(--border-accent);
584
- transform: translateY(-2px);
585
- box-shadow: var(--shadow-glow);
586
- }
587
-
588
- .stat-label {
589
- font-size: 0.75rem;
590
- font-weight: 500;
591
- color: var(--text-muted);
592
- text-transform: uppercase;
593
- letter-spacing: 0.06em;
594
- }
595
-
596
- .stat-value {
597
- font-size: 2rem;
598
- font-weight: 700;
599
- margin-top: 0.25rem;
600
- background: var(--gradient-brand);
601
- -webkit-background-clip: text;
602
- -webkit-text-fill-color: transparent;
603
- background-clip: text;
604
- }
605
-
606
- .stat-change {
607
- font-size: 0.75rem;
608
- color: var(--accent-success);
609
- margin-top: 0.25rem;
610
- }
611
-
612
-
613
- /* ── Workflow List ─────────────────────────── */
614
-
615
- .workflow-list {
616
- display: flex;
617
- flex-direction: column;
618
- gap: 0.75rem;
619
- }
620
-
621
- .workflow-item {
622
- display: flex;
623
- align-items: center;
624
- gap: 1rem;
625
- padding: 1rem 1.25rem;
626
- background: var(--bg-card);
627
- border: 1px solid var(--border-primary);
628
- border-radius: var(--radius-md);
629
- transition: all var(--transition-fast);
630
- cursor: pointer;
631
- }
632
-
633
- .workflow-item:hover {
634
- border-color: var(--border-accent);
635
- background: var(--bg-tertiary);
636
- }
637
-
638
- .workflow-status {
639
- width: 10px;
640
- height: 10px;
641
- border-radius: 50%;
642
- flex-shrink: 0;
643
- }
644
-
645
- .workflow-status.pending { background: var(--accent-warning); box-shadow: 0 0 8px rgba(251,191,36,0.4); }
646
- .workflow-status.running { background: var(--accent-info); box-shadow: 0 0 8px rgba(56,189,248,0.4); animation: pulse 2s infinite; }
647
- .workflow-status.success { background: var(--accent-success); box-shadow: 0 0 8px rgba(52,211,153,0.4); }
648
- .workflow-status.failed { background: var(--accent-danger); box-shadow: 0 0 8px rgba(248,113,113,0.4); }
649
-
650
- @keyframes pulse {
651
- 0%, 100% { opacity: 1; }
652
- 50% { opacity: 0.4; }
653
- }
654
-
655
- .workflow-details {
656
- flex: 1;
657
- min-width: 0;
658
- }
659
-
660
- .workflow-prompt {
661
- font-size: 0.875rem;
662
- font-weight: 500;
663
- white-space: nowrap;
664
- overflow: hidden;
665
- text-overflow: ellipsis;
666
- }
667
-
668
- .workflow-meta {
669
- font-size: 0.75rem;
670
- color: var(--text-muted);
671
- margin-top: 0.125rem;
672
- }
673
-
674
- .workflow-arrow {
675
- color: var(--text-muted);
676
- transition: transform var(--transition-fast);
677
- }
678
-
679
- .workflow-item:hover .workflow-arrow {
680
- transform: translateX(4px);
681
- color: var(--accent-secondary);
682
- }
683
-
684
-
685
- /* ── Create Workflow ───────────────────────── */
686
-
687
- .create-section {
688
- margin-bottom: 2rem;
689
- }
690
-
691
- .prompt-input {
692
- width: 100%;
693
- min-height: 120px;
694
- padding: 1rem;
695
- background: var(--bg-tertiary);
696
- border: 1px solid var(--border-primary);
697
- border-radius: var(--radius-md);
698
- color: var(--text-primary);
699
- font-family: var(--font-mono);
700
- font-size: 0.875rem;
701
- resize: vertical;
702
- transition: all var(--transition-fast);
703
- outline: none;
704
- }
705
-
706
- .prompt-input::placeholder {
707
- color: var(--text-muted);
708
- }
709
-
710
- .prompt-input:focus {
711
- border-color: var(--accent-primary);
712
- box-shadow: 0 0 0 3px var(--accent-glow);
713
- }
714
-
715
- .create-actions {
716
- display: flex;
717
- justify-content: flex-end;
718
- margin-top: 1rem;
719
- }
720
-
721
-
722
- /* ── Empty State ───────────────────────────── */
723
-
724
- .empty-state {
725
- display: flex;
726
- flex-direction: column;
727
- align-items: center;
728
- justify-content: center;
729
- padding: 3rem;
730
- text-align: center;
731
- }
732
-
733
- .empty-icon {
734
- font-size: 3rem;
735
- margin-bottom: 1rem;
736
- opacity: 0.3;
737
- }
738
-
739
- .empty-title {
740
- font-size: 1.125rem;
741
- font-weight: 600;
742
- margin-bottom: 0.5rem;
743
- }
744
-
745
- .empty-text {
746
- font-size: 0.875rem;
747
- color: var(--text-muted);
748
- max-width: 360px;
749
- }
750
-
751
-
752
- /* ── Status Badge ──────────────────────────── */
753
-
754
- .badge {
755
- display: inline-flex;
756
- align-items: center;
757
- padding: 0.25rem 0.625rem;
758
- border-radius: 100px;
759
- font-size: 0.6875rem;
760
- font-weight: 600;
761
- text-transform: uppercase;
762
- letter-spacing: 0.04em;
763
- }
764
-
765
- .badge-pending { background: rgba(251,191,36,0.15); color: var(--accent-warning); }
766
- .badge-running { background: rgba(56,189,248,0.15); color: var(--accent-info); }
767
- .badge-success { background: rgba(52,211,153,0.15); color: var(--accent-success); }
768
- .badge-failed { background: rgba(248,113,113,0.15); color: var(--accent-danger); }
769
-
770
-
771
- /* ── Spinner ───────────────────────────────── */
772
-
773
- .spinner {
774
- width: 20px;
775
- height: 20px;
776
- border: 2px solid rgba(255,255,255,0.1);
777
- border-top-color: var(--accent-primary);
778
- border-radius: 50%;
779
- animation: spin 0.6s linear infinite;
780
- }
781
-
782
- @keyframes spin {
783
- to { transform: rotate(360deg); }
784
- }
785
-
786
-
787
- /* ── Responsive ────────────────────────────── */
788
-
789
- @media (max-width: 768px) {
790
- .sidebar {
791
- transform: translateX(-100%);
792
- }
793
-
794
- .sidebar.open {
795
- transform: translateX(0);
796
- }
797
-
798
- .main-content {
799
- margin-left: 0;
800
- }
801
-
802
- .page-header,
803
- .page-body {
804
- padding-left: 1.25rem;
805
- padding-right: 1.25rem;
806
- }
807
-
808
- .stats-grid {
809
- grid-template-columns: 1fr;
810
- }
811
- }
812
-
813
-
814
- /* ── Scrollbar ─────────────────────────────── */
815
-
816
- ::-webkit-scrollbar {
817
- width: 6px;
818
- height: 6px;
819
- }
820
-
821
- ::-webkit-scrollbar-track {
822
- background: transparent;
823
- }
824
-
825
- ::-webkit-scrollbar-thumb {
826
- background: var(--border-primary);
827
- border-radius: 3px;
828
- }
829
-
830
- ::-webkit-scrollbar-thumb:hover {
831
- background: var(--text-muted);
832
- }
833
-
834
-
835
- /* ── Toast ─────────────────────────────────── */
836
-
837
- .toast-container {
838
- position: fixed;
839
- top: 1.5rem;
840
- right: 1.5rem;
841
- z-index: 9999;
842
- display: flex;
843
- flex-direction: column;
844
- gap: 0.75rem;
845
- }
846
-
847
- .toast {
848
- padding: 0.875rem 1.25rem;
849
- background: var(--bg-card);
850
- backdrop-filter: blur(20px);
851
- border: 1px solid var(--border-primary);
852
- border-radius: var(--radius-md);
853
- box-shadow: var(--shadow-lg);
854
- font-size: 0.875rem;
855
- animation: toastIn 0.3s ease-out;
856
- max-width: 380px;
857
- }
858
-
859
- .toast.success { border-left: 3px solid var(--accent-success); }
860
- .toast.error { border-left: 3px solid var(--accent-danger); }
861
- .toast.info { border-left: 3px solid var(--accent-info); }
862
-
863
- @keyframes toastIn {
864
- from { opacity: 0; transform: translateX(20px); }
865
- to { opacity: 1; transform: translateX(0); }
866
- }
867
-
868
- .toast-exit {
869
- animation: toastOut 0.2s ease-in forwards;
870
- }
871
-
872
- @keyframes toastOut {
873
- to { opacity: 0; transform: translateX(20px); }
874
- }
875
-
876
-
877
- /* ── Page Transitions ──────────────────────── */
878
-
879
- .page-section {
880
- display: none;
881
- }
882
-
883
- .page-section.active {
884
- display: block;
885
- animation: fadeIn 0.3s ease-out;
886
- }
887
-
888
- @keyframes fadeIn {
889
- from { opacity: 0; transform: translateY(8px); }
890
- to { opacity: 1; transform: translateY(0); }
891
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/css/style.css DELETED
@@ -1,894 +0,0 @@
1
- /* ═══════════════════════════════════════════════════════════════════
2
- AutoForge — Design System
3
- Dark developer-tool aesthetic with glassmorphism
4
- ═══════════════════════════════════════════════════════════════════ */
5
-
6
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
7
-
8
- /* ── CSS Custom Properties ───────────────────────────────────────── */
9
-
10
- :root {
11
- /* Background */
12
- --bg-primary: #0a0a0f;
13
- --bg-secondary: #12121a;
14
- --bg-tertiary: #1a1a28;
15
- --bg-surface: rgba(255, 255, 255, 0.03);
16
- --bg-surface-hover: rgba(255, 255, 255, 0.06);
17
- --bg-glass: rgba(18, 18, 26, 0.75);
18
-
19
- /* Accent gradient */
20
- --accent-blue: #00d4ff;
21
- --accent-purple: #7b2ff7;
22
- --accent-pink: #f72fff;
23
- --gradient-primary: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
24
- --gradient-secondary: linear-gradient(135deg, var(--accent-purple), var(--accent-pink));
25
- --gradient-glow: linear-gradient(135deg, rgba(0, 212, 255, 0.15), rgba(123, 47, 247, 0.15));
26
-
27
- /* Text */
28
- --text-primary: #e8e8f0;
29
- --text-secondary: #9898b0;
30
- --text-muted: #5e5e78;
31
- --text-accent: var(--accent-blue);
32
-
33
- /* Status */
34
- --status-success: #00e88f;
35
- --status-warning: #ffb800;
36
- --status-error: #ff4060;
37
- --status-pending: #5e5e78;
38
-
39
- /* Borders */
40
- --border-subtle: rgba(255, 255, 255, 0.06);
41
- --border-medium: rgba(255, 255, 255, 0.1);
42
- --border-accent: rgba(0, 212, 255, 0.3);
43
-
44
- /* Shadows */
45
- --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
46
- --shadow-md: 0 4px 20px rgba(0, 0, 0, 0.4);
47
- --shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.5);
48
- --shadow-glow: 0 0 30px rgba(0, 212, 255, 0.1);
49
-
50
- /* Spacing */
51
- --space-xs: 0.25rem;
52
- --space-sm: 0.5rem;
53
- --space-md: 1rem;
54
- --space-lg: 1.5rem;
55
- --space-xl: 2rem;
56
- --space-2xl: 3rem;
57
-
58
- /* Radius */
59
- --radius-sm: 6px;
60
- --radius-md: 10px;
61
- --radius-lg: 16px;
62
- --radius-xl: 24px;
63
-
64
- /* Typography */
65
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
66
- --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
67
-
68
- /* Transitions */
69
- --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
70
- --transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
71
- --transition-slow: 400ms cubic-bezier(0.4, 0, 0.2, 1);
72
-
73
- /* Layout */
74
- --sidebar-width: 260px;
75
- --header-height: 64px;
76
- }
77
-
78
- /* ── Reset ───────────────────────────────────────────────────────── */
79
-
80
- *, *::before, *::after {
81
- margin: 0;
82
- padding: 0;
83
- box-sizing: border-box;
84
- }
85
-
86
- html {
87
- font-size: 16px;
88
- -webkit-font-smoothing: antialiased;
89
- -moz-osx-font-smoothing: grayscale;
90
- }
91
-
92
- body {
93
- font-family: var(--font-sans);
94
- background: var(--bg-primary);
95
- color: var(--text-primary);
96
- line-height: 1.6;
97
- min-height: 100vh;
98
- overflow-x: hidden;
99
- }
100
-
101
- a {
102
- color: var(--text-accent);
103
- text-decoration: none;
104
- transition: color var(--transition-fast);
105
- }
106
-
107
- a:hover {
108
- color: var(--accent-purple);
109
- }
110
-
111
- /* ── Scrollbar ───────────────────────────────────────────────────── */
112
-
113
- ::-webkit-scrollbar {
114
- width: 8px;
115
- height: 8px;
116
- }
117
-
118
- ::-webkit-scrollbar-track {
119
- background: var(--bg-secondary);
120
- }
121
-
122
- ::-webkit-scrollbar-thumb {
123
- background: var(--bg-tertiary);
124
- border-radius: 4px;
125
- }
126
-
127
- ::-webkit-scrollbar-thumb:hover {
128
- background: rgba(255, 255, 255, 0.15);
129
- }
130
-
131
- /* ── Glass Panel ─────────────────────────────────────────────────── */
132
-
133
- .glass {
134
- background: var(--bg-glass);
135
- backdrop-filter: blur(16px);
136
- -webkit-backdrop-filter: blur(16px);
137
- border: 1px solid var(--border-subtle);
138
- border-radius: var(--radius-lg);
139
- }
140
-
141
- .glass-strong {
142
- background: rgba(18, 18, 26, 0.9);
143
- backdrop-filter: blur(24px);
144
- -webkit-backdrop-filter: blur(24px);
145
- border: 1px solid var(--border-medium);
146
- border-radius: var(--radius-lg);
147
- }
148
-
149
- /* ── Layout ──────────────────────────────────────────────────────── */
150
-
151
- .app-layout {
152
- display: flex;
153
- min-height: 100vh;
154
- }
155
-
156
- .sidebar {
157
- position: fixed;
158
- left: 0;
159
- top: 0;
160
- width: var(--sidebar-width);
161
- height: 100vh;
162
- background: var(--bg-glass);
163
- backdrop-filter: blur(20px);
164
- -webkit-backdrop-filter: blur(20px);
165
- border-right: 1px solid var(--border-subtle);
166
- display: flex;
167
- flex-direction: column;
168
- z-index: 100;
169
- transition: transform var(--transition-base);
170
- }
171
-
172
- .sidebar-header {
173
- padding: var(--space-xl);
174
- border-bottom: 1px solid var(--border-subtle);
175
- }
176
-
177
- .sidebar-brand {
178
- display: flex;
179
- align-items: center;
180
- gap: var(--space-sm);
181
- }
182
-
183
- .sidebar-brand .logo {
184
- width: 36px;
185
- height: 36px;
186
- background: var(--gradient-primary);
187
- border-radius: var(--radius-sm);
188
- display: flex;
189
- align-items: center;
190
- justify-content: center;
191
- font-weight: 700;
192
- font-size: 1.1rem;
193
- color: #fff;
194
- }
195
-
196
- .sidebar-brand h1 {
197
- font-size: 1.2rem;
198
- font-weight: 700;
199
- background: var(--gradient-primary);
200
- -webkit-background-clip: text;
201
- -webkit-text-fill-color: transparent;
202
- background-clip: text;
203
- }
204
-
205
- .sidebar-nav {
206
- flex: 1;
207
- padding: var(--space-md);
208
- display: flex;
209
- flex-direction: column;
210
- gap: var(--space-xs);
211
- }
212
-
213
- .nav-item {
214
- display: flex;
215
- align-items: center;
216
- gap: var(--space-md);
217
- padding: var(--space-sm) var(--space-md);
218
- border-radius: var(--radius-md);
219
- color: var(--text-secondary);
220
- font-size: 0.9rem;
221
- font-weight: 500;
222
- transition: all var(--transition-fast);
223
- cursor: pointer;
224
- border: 1px solid transparent;
225
- text-decoration: none;
226
- }
227
-
228
- .nav-item:hover {
229
- background: var(--bg-surface-hover);
230
- color: var(--text-primary);
231
- border-color: var(--border-subtle);
232
- }
233
-
234
- .nav-item.active {
235
- background: var(--gradient-glow);
236
- color: var(--text-accent);
237
- border-color: var(--border-accent);
238
- }
239
-
240
- .nav-item .icon {
241
- width: 20px;
242
- height: 20px;
243
- display: flex;
244
- align-items: center;
245
- justify-content: center;
246
- font-size: 1.1rem;
247
- }
248
-
249
- .sidebar-footer {
250
- padding: var(--space-md) var(--space-xl);
251
- border-top: 1px solid var(--border-subtle);
252
- }
253
-
254
- .main-content {
255
- margin-left: var(--sidebar-width);
256
- flex: 1;
257
- padding: var(--space-2xl);
258
- min-height: 100vh;
259
- }
260
-
261
- /* ── Page Header ─────────────────────────────────────────────────── */
262
-
263
- .page-header {
264
- margin-bottom: var(--space-2xl);
265
- }
266
-
267
- .page-header h2 {
268
- font-size: 1.75rem;
269
- font-weight: 700;
270
- margin-bottom: var(--space-xs);
271
- }
272
-
273
- .page-header p {
274
- color: var(--text-secondary);
275
- font-size: 0.95rem;
276
- }
277
-
278
- /* ── Cards ───────────────────────────────────────────────────────── */
279
-
280
- .card {
281
- background: var(--bg-surface);
282
- border: 1px solid var(--border-subtle);
283
- border-radius: var(--radius-lg);
284
- padding: var(--space-xl);
285
- transition: all var(--transition-base);
286
- }
287
-
288
- .card:hover {
289
- border-color: var(--border-medium);
290
- box-shadow: var(--shadow-md);
291
- transform: translateY(-2px);
292
- }
293
-
294
- .card-grid {
295
- display: grid;
296
- grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
297
- gap: var(--space-lg);
298
- }
299
-
300
- .card-header {
301
- display: flex;
302
- align-items: center;
303
- justify-content: space-between;
304
- margin-bottom: var(--space-md);
305
- }
306
-
307
- .card-title {
308
- font-size: 1rem;
309
- font-weight: 600;
310
- }
311
-
312
- /* ── Status Badges ───────────────────────────────────────────────── */
313
-
314
- .badge {
315
- display: inline-flex;
316
- align-items: center;
317
- padding: var(--space-xs) var(--space-sm);
318
- border-radius: 999px;
319
- font-size: 0.75rem;
320
- font-weight: 600;
321
- text-transform: uppercase;
322
- letter-spacing: 0.05em;
323
- }
324
-
325
- .badge-pending {
326
- background: rgba(94, 94, 120, 0.2);
327
- color: var(--status-pending);
328
- border: 1px solid rgba(94, 94, 120, 0.3);
329
- }
330
-
331
- .badge-running {
332
- background: rgba(0, 212, 255, 0.1);
333
- color: var(--accent-blue);
334
- border: 1px solid rgba(0, 212, 255, 0.3);
335
- animation: pulse-glow 2s infinite;
336
- }
337
-
338
- .badge-completed {
339
- background: rgba(0, 232, 143, 0.1);
340
- color: var(--status-success);
341
- border: 1px solid rgba(0, 232, 143, 0.3);
342
- }
343
-
344
- .badge-failed {
345
- background: rgba(255, 64, 96, 0.1);
346
- color: var(--status-error);
347
- border: 1px solid rgba(255, 64, 96, 0.3);
348
- }
349
-
350
- /* ── Buttons ─────────────────────────────────────────────────────── */
351
-
352
- .btn {
353
- display: inline-flex;
354
- align-items: center;
355
- justify-content: center;
356
- gap: var(--space-sm);
357
- padding: 0.65rem 1.5rem;
358
- border-radius: var(--radius-md);
359
- font-family: var(--font-sans);
360
- font-size: 0.9rem;
361
- font-weight: 600;
362
- cursor: pointer;
363
- border: 1px solid transparent;
364
- transition: all var(--transition-fast);
365
- outline: none;
366
- }
367
-
368
- .btn:active {
369
- transform: scale(0.97);
370
- }
371
-
372
- .btn-primary {
373
- background: var(--gradient-primary);
374
- color: #fff;
375
- border: none;
376
- box-shadow: 0 4px 15px rgba(0, 212, 255, 0.25);
377
- }
378
-
379
- .btn-primary:hover {
380
- box-shadow: 0 6px 25px rgba(0, 212, 255, 0.35);
381
- transform: translateY(-1px);
382
- }
383
-
384
- .btn-secondary {
385
- background: var(--bg-surface);
386
- color: var(--text-primary);
387
- border: 1px solid var(--border-medium);
388
- }
389
-
390
- .btn-secondary:hover {
391
- background: var(--bg-surface-hover);
392
- border-color: var(--border-accent);
393
- }
394
-
395
- .btn-ghost {
396
- background: transparent;
397
- color: var(--text-secondary);
398
- border: none;
399
- }
400
-
401
- .btn-ghost:hover {
402
- color: var(--text-primary);
403
- background: var(--bg-surface);
404
- }
405
-
406
- .btn-danger {
407
- background: rgba(255, 64, 96, 0.15);
408
- color: var(--status-error);
409
- border: 1px solid rgba(255, 64, 96, 0.3);
410
- }
411
-
412
- .btn-danger:hover {
413
- background: rgba(255, 64, 96, 0.25);
414
- }
415
-
416
- .btn-lg {
417
- padding: 0.85rem 2rem;
418
- font-size: 1rem;
419
- }
420
-
421
- .btn-sm {
422
- padding: 0.4rem 0.9rem;
423
- font-size: 0.8rem;
424
- }
425
-
426
- /* ── Forms ────────────────────────────────────────────────────────── */
427
-
428
- .form-group {
429
- margin-bottom: var(--space-lg);
430
- }
431
-
432
- .form-label {
433
- display: block;
434
- font-size: 0.85rem;
435
- font-weight: 500;
436
- color: var(--text-secondary);
437
- margin-bottom: var(--space-sm);
438
- text-transform: uppercase;
439
- letter-spacing: 0.05em;
440
- }
441
-
442
- .form-input {
443
- width: 100%;
444
- padding: 0.75rem 1rem;
445
- background: var(--bg-surface);
446
- border: 1px solid var(--border-subtle);
447
- border-radius: var(--radius-md);
448
- color: var(--text-primary);
449
- font-family: var(--font-sans);
450
- font-size: 0.95rem;
451
- transition: all var(--transition-fast);
452
- outline: none;
453
- }
454
-
455
- .form-input:focus {
456
- border-color: var(--accent-blue);
457
- box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.1);
458
- }
459
-
460
- .form-input::placeholder {
461
- color: var(--text-muted);
462
- }
463
-
464
- textarea.form-input {
465
- resize: vertical;
466
- min-height: 120px;
467
- font-family: var(--font-mono);
468
- font-size: 0.9rem;
469
- line-height: 1.7;
470
- }
471
-
472
- /* ── Auth Layout ─────────────────────────────────────────────────── */
473
-
474
- .auth-layout {
475
- display: flex;
476
- align-items: center;
477
- justify-content: center;
478
- min-height: 100vh;
479
- padding: var(--space-xl);
480
- position: relative;
481
- }
482
-
483
- .auth-layout::before {
484
- content: '';
485
- position: absolute;
486
- top: -50%;
487
- left: -50%;
488
- width: 200%;
489
- height: 200%;
490
- background: radial-gradient(ellipse at 30% 20%, rgba(0, 212, 255, 0.08) 0%, transparent 50%),
491
- radial-gradient(ellipse at 70% 80%, rgba(123, 47, 247, 0.08) 0%, transparent 50%);
492
- animation: bg-drift 20s ease-in-out infinite alternate;
493
- pointer-events: none;
494
- }
495
-
496
- .auth-card {
497
- width: 100%;
498
- max-width: 440px;
499
- padding: var(--space-2xl);
500
- position: relative;
501
- z-index: 1;
502
- }
503
-
504
- .auth-header {
505
- text-align: center;
506
- margin-bottom: var(--space-2xl);
507
- }
508
-
509
- .auth-header .logo-large {
510
- width: 64px;
511
- height: 64px;
512
- background: var(--gradient-primary);
513
- border-radius: var(--radius-md);
514
- display: flex;
515
- align-items: center;
516
- justify-content: center;
517
- font-size: 1.8rem;
518
- font-weight: 700;
519
- color: #fff;
520
- margin: 0 auto var(--space-lg);
521
- box-shadow: 0 8px 30px rgba(0, 212, 255, 0.25);
522
- }
523
-
524
- .auth-header h2 {
525
- font-size: 1.5rem;
526
- font-weight: 700;
527
- margin-bottom: var(--space-xs);
528
- }
529
-
530
- .auth-header p {
531
- color: var(--text-secondary);
532
- font-size: 0.9rem;
533
- }
534
-
535
- .auth-toggle {
536
- text-align: center;
537
- margin-top: var(--space-xl);
538
- color: var(--text-secondary);
539
- font-size: 0.9rem;
540
- }
541
-
542
- .auth-toggle a {
543
- font-weight: 600;
544
- }
545
-
546
- .form-error {
547
- color: var(--status-error);
548
- font-size: 0.85rem;
549
- margin-top: var(--space-sm);
550
- display: none;
551
- }
552
-
553
- .form-error.visible {
554
- display: block;
555
- }
556
-
557
- /* ── Workflow Card ───────────────────────────────────────────────── */
558
-
559
- .workflow-card {
560
- cursor: pointer;
561
- }
562
-
563
- .workflow-card .prompt-preview {
564
- color: var(--text-secondary);
565
- font-size: 0.9rem;
566
- line-height: 1.5;
567
- margin-bottom: var(--space-md);
568
- display: -webkit-box;
569
- -webkit-line-clamp: 3;
570
- -webkit-box-orient: vertical;
571
- overflow: hidden;
572
- }
573
-
574
- .workflow-card .meta {
575
- display: flex;
576
- align-items: center;
577
- justify-content: space-between;
578
- font-size: 0.8rem;
579
- color: var(--text-muted);
580
- }
581
-
582
- /* ── Create Workflow Card ────────────────────────────────────────── */
583
-
584
- .create-card {
585
- border: 2px dashed var(--border-medium);
586
- background: transparent;
587
- display: flex;
588
- flex-direction: column;
589
- align-items: center;
590
- justify-content: center;
591
- min-height: 200px;
592
- cursor: pointer;
593
- transition: all var(--transition-base);
594
- }
595
-
596
- .create-card:hover {
597
- border-color: var(--accent-blue);
598
- background: var(--gradient-glow);
599
- }
600
-
601
- .create-card .icon-large {
602
- width: 48px;
603
- height: 48px;
604
- border-radius: 50%;
605
- background: var(--gradient-primary);
606
- display: flex;
607
- align-items: center;
608
- justify-content: center;
609
- font-size: 1.5rem;
610
- color: #fff;
611
- margin-bottom: var(--space-md);
612
- }
613
-
614
- .create-card p {
615
- color: var(--text-secondary);
616
- font-weight: 500;
617
- }
618
-
619
- /* ── Modal ────────────────────────────────────────────────────────── */
620
-
621
- .modal-overlay {
622
- position: fixed;
623
- inset: 0;
624
- background: rgba(0, 0, 0, 0.6);
625
- backdrop-filter: blur(4px);
626
- display: flex;
627
- align-items: center;
628
- justify-content: center;
629
- z-index: 1000;
630
- opacity: 0;
631
- visibility: hidden;
632
- transition: all var(--transition-base);
633
- }
634
-
635
- .modal-overlay.active {
636
- opacity: 1;
637
- visibility: visible;
638
- }
639
-
640
- .modal {
641
- width: 100%;
642
- max-width: 560px;
643
- padding: var(--space-2xl);
644
- transform: translateY(20px) scale(0.95);
645
- transition: transform var(--transition-base);
646
- }
647
-
648
- .modal-overlay.active .modal {
649
- transform: translateY(0) scale(1);
650
- }
651
-
652
- .modal-header {
653
- display: flex;
654
- align-items: center;
655
- justify-content: space-between;
656
- margin-bottom: var(--space-xl);
657
- }
658
-
659
- .modal-header h3 {
660
- font-size: 1.25rem;
661
- font-weight: 700;
662
- }
663
-
664
- .modal-close {
665
- width: 32px;
666
- height: 32px;
667
- border-radius: 50%;
668
- background: var(--bg-surface);
669
- border: 1px solid var(--border-subtle);
670
- color: var(--text-secondary);
671
- cursor: pointer;
672
- display: flex;
673
- align-items: center;
674
- justify-content: center;
675
- font-size: 1.1rem;
676
- transition: all var(--transition-fast);
677
- }
678
-
679
- .modal-close:hover {
680
- background: var(--bg-surface-hover);
681
- color: var(--text-primary);
682
- }
683
-
684
- /* ── Stats Bar ───────────────────────────────────────────────────── */
685
-
686
- .stats-bar {
687
- display: grid;
688
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
689
- gap: var(--space-lg);
690
- margin-bottom: var(--space-2xl);
691
- }
692
-
693
- .stat-card {
694
- padding: var(--space-lg);
695
- }
696
-
697
- .stat-card .stat-value {
698
- font-size: 2rem;
699
- font-weight: 700;
700
- background: var(--gradient-primary);
701
- -webkit-background-clip: text;
702
- -webkit-text-fill-color: transparent;
703
- background-clip: text;
704
- }
705
-
706
- .stat-card .stat-label {
707
- font-size: 0.8rem;
708
- color: var(--text-muted);
709
- text-transform: uppercase;
710
- letter-spacing: 0.06em;
711
- margin-top: var(--space-xs);
712
- }
713
-
714
- /* ── Empty State ─────────────────────────────────────────────────── */
715
-
716
- .empty-state {
717
- text-align: center;
718
- padding: var(--space-2xl) * 2;
719
- color: var(--text-muted);
720
- }
721
-
722
- .empty-state .icon-empty {
723
- font-size: 3rem;
724
- margin-bottom: var(--space-lg);
725
- opacity: 0.5;
726
- }
727
-
728
- .empty-state h3 {
729
- font-size: 1.1rem;
730
- color: var(--text-secondary);
731
- margin-bottom: var(--space-sm);
732
- }
733
-
734
- /* ── Loading Spinner ─────────────────────────────────────────────── */
735
-
736
- .spinner {
737
- width: 24px;
738
- height: 24px;
739
- border: 3px solid var(--border-subtle);
740
- border-top-color: var(--accent-blue);
741
- border-radius: 50%;
742
- animation: spin 0.8s linear infinite;
743
- }
744
-
745
- .spinner-sm {
746
- width: 16px;
747
- height: 16px;
748
- border-width: 2px;
749
- }
750
-
751
- /* ── Notifications ───────────────────────────────────────────────── */
752
-
753
- .toast {
754
- position: fixed;
755
- bottom: var(--space-xl);
756
- right: var(--space-xl);
757
- padding: var(--space-md) var(--space-lg);
758
- border-radius: var(--radius-md);
759
- font-size: 0.9rem;
760
- font-weight: 500;
761
- z-index: 2000;
762
- transform: translateY(100px);
763
- opacity: 0;
764
- transition: all var(--transition-base);
765
- }
766
-
767
- .toast.visible {
768
- transform: translateY(0);
769
- opacity: 1;
770
- }
771
-
772
- .toast-success {
773
- background: rgba(0, 232, 143, 0.15);
774
- border: 1px solid rgba(0, 232, 143, 0.3);
775
- color: var(--status-success);
776
- }
777
-
778
- .toast-error {
779
- background: rgba(255, 64, 96, 0.15);
780
- border: 1px solid rgba(255, 64, 96, 0.3);
781
- color: var(--status-error);
782
- }
783
-
784
- /* ── Placeholder Pages ───────────────────────────────────────────── */
785
-
786
- .placeholder-content {
787
- display: flex;
788
- flex-direction: column;
789
- align-items: center;
790
- justify-content: center;
791
- min-height: 400px;
792
- text-align: center;
793
- }
794
-
795
- .placeholder-content .icon-placeholder {
796
- font-size: 4rem;
797
- margin-bottom: var(--space-lg);
798
- opacity: 0.3;
799
- }
800
-
801
- .placeholder-content h3 {
802
- font-size: 1.3rem;
803
- margin-bottom: var(--space-sm);
804
- }
805
-
806
- .placeholder-content p {
807
- color: var(--text-muted);
808
- max-width: 400px;
809
- }
810
-
811
- /* ── User Menu ───────────────────────────────────────────────────── */
812
-
813
- .user-menu {
814
- display: flex;
815
- align-items: center;
816
- gap: var(--space-sm);
817
- padding: var(--space-sm) var(--space-md);
818
- border-radius: var(--radius-md);
819
- cursor: pointer;
820
- transition: background var(--transition-fast);
821
- }
822
-
823
- .user-menu:hover {
824
- background: var(--bg-surface-hover);
825
- }
826
-
827
- .user-avatar {
828
- width: 32px;
829
- height: 32px;
830
- border-radius: 50%;
831
- background: var(--gradient-primary);
832
- display: flex;
833
- align-items: center;
834
- justify-content: center;
835
- font-weight: 700;
836
- font-size: 0.85rem;
837
- color: #fff;
838
- }
839
-
840
- .user-name {
841
- font-size: 0.85rem;
842
- font-weight: 500;
843
- color: var(--text-secondary);
844
- }
845
-
846
- /* ── Animations ──────────────────────────────────────────────────── */
847
-
848
- @keyframes spin {
849
- to { transform: rotate(360deg); }
850
- }
851
-
852
- @keyframes pulse-glow {
853
- 0%, 100% { opacity: 1; }
854
- 50% { opacity: 0.7; }
855
- }
856
-
857
- @keyframes bg-drift {
858
- 0% { transform: translate(0, 0) rotate(0deg); }
859
- 100% { transform: translate(-2%, -2%) rotate(1deg); }
860
- }
861
-
862
- @keyframes fade-in {
863
- from { opacity: 0; transform: translateY(10px); }
864
- to { opacity: 1; transform: translateY(0); }
865
- }
866
-
867
- .fade-in {
868
- animation: fade-in 0.4s ease-out forwards;
869
- }
870
-
871
- /* ── Responsive ──────────────────────────────────────────────────── */
872
-
873
- @media (max-width: 768px) {
874
- .sidebar {
875
- transform: translateX(-100%);
876
- }
877
-
878
- .sidebar.open {
879
- transform: translateX(0);
880
- }
881
-
882
- .main-content {
883
- margin-left: 0;
884
- padding: var(--space-lg);
885
- }
886
-
887
- .card-grid {
888
- grid-template-columns: 1fr;
889
- }
890
-
891
- .stats-bar {
892
- grid-template-columns: repeat(2, 1fr);
893
- }
894
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/dashboard.html DELETED
@@ -1,121 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="AutoForge Dashboard — Manage your AI coding workflows">
7
- <title>AutoForge — Dashboard</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <div class="app-layout">
12
- <!-- Sidebar -->
13
- <nav class="sidebar" id="sidebar">
14
- <div class="sidebar-header">
15
- <div class="sidebar-brand">
16
- <div class="logo">⚡</div>
17
- <h1>AutoForge</h1>
18
- </div>
19
- </div>
20
-
21
- <div class="sidebar-nav">
22
- <a href="dashboard.html" class="nav-item active">
23
- <span class="icon">📊</span>
24
- <span>Dashboard</span>
25
- </a>
26
- <a href="workflow.html" class="nav-item">
27
- <span class="icon">⚙️</span>
28
- <span>Workflow</span>
29
- </a>
30
- <a href="history.html" class="nav-item">
31
- <span class="icon">📜</span>
32
- <span>History</span>
33
- </a>
34
- <a href="settings.html" class="nav-item">
35
- <span class="icon">🔧</span>
36
- <span>Settings</span>
37
- </a>
38
- </div>
39
-
40
- <div class="sidebar-footer">
41
- <div class="user-menu" id="logout-btn">
42
- <div class="user-avatar" id="user-avatar">U</div>
43
- <span class="user-name" id="user-display-name">User</span>
44
- </div>
45
- </div>
46
- </nav>
47
-
48
- <!-- Main Content -->
49
- <main class="main-content">
50
- <div class="page-header">
51
- <h2>Dashboard</h2>
52
- <p>Overview of your autonomous coding workflows</p>
53
- </div>
54
-
55
- <!-- Stats -->
56
- <div class="stats-bar">
57
- <div class="stat-card card glass">
58
- <div class="stat-value" id="stat-total">0</div>
59
- <div class="stat-label">Total Workflows</div>
60
- </div>
61
- <div class="stat-card card glass">
62
- <div class="stat-value" id="stat-pending">0</div>
63
- <div class="stat-label">Pending</div>
64
- </div>
65
- <div class="stat-card card glass">
66
- <div class="stat-value" id="stat-completed">0</div>
67
- <div class="stat-label">Completed</div>
68
- </div>
69
- <div class="stat-card card glass">
70
- <div class="stat-value" id="stat-failed">0</div>
71
- <div class="stat-label">Failed</div>
72
- </div>
73
- </div>
74
-
75
- <!-- Workflows Grid -->
76
- <div class="card-header" style="margin-bottom: 1rem;">
77
- <h3 class="card-title">Recent Workflows</h3>
78
- <button class="btn btn-primary" onclick="App.openCreateModal()">
79
- + New Workflow
80
- </button>
81
- </div>
82
-
83
- <div class="card-grid" id="workflows-list">
84
- <div class="spinner" style="margin: 3rem auto;"></div>
85
- </div>
86
- </main>
87
- </div>
88
-
89
- <!-- Create Workflow Modal -->
90
- <div class="modal-overlay" id="create-modal">
91
- <div class="modal glass-strong">
92
- <div class="modal-header">
93
- <h3>Create New Workflow</h3>
94
- <button class="modal-close" onclick="App.closeCreateModal()">✕</button>
95
- </div>
96
-
97
- <div class="form-group">
98
- <label class="form-label" for="workflow-prompt">What would you like to build?</label>
99
- <textarea class="form-input" id="workflow-prompt"
100
- placeholder="e.g. Create a small Python calculator package with add, subtract, multiply and divide functions, including tests and proper division-by-zero handling."></textarea>
101
- </div>
102
-
103
- <div style="display: flex; gap: 0.75rem; justify-content: flex-end;">
104
- <button class="btn btn-secondary" onclick="App.closeCreateModal()">Cancel</button>
105
- <button class="btn btn-primary" onclick="App.createWorkflow()">Create Workflow</button>
106
- </div>
107
- </div>
108
- </div>
109
-
110
- <script src="/js/api.js"></script>
111
- <script src="/js/auth.js"></script>
112
- <script src="/js/router.js"></script>
113
- <script src="/js/app.js"></script>
114
- <script>
115
- if (Router.init()) {
116
- App.initSidebar();
117
- App.loadWorkflows();
118
- }
119
- </script>
120
- </body>
121
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/history.html DELETED
@@ -1,104 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="AutoForge Workflow History">
7
- <title>AutoForge — History</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <div class="app-layout">
12
- <!-- Sidebar -->
13
- <nav class="sidebar">
14
- <div class="sidebar-header">
15
- <div class="sidebar-brand">
16
- <div class="logo">⚡</div>
17
- <h1>AutoForge</h1>
18
- </div>
19
- </div>
20
- <div class="sidebar-nav">
21
- <a href="dashboard.html" class="nav-item">
22
- <span class="icon">📊</span><span>Dashboard</span>
23
- </a>
24
- <a href="workflow.html" class="nav-item">
25
- <span class="icon">⚙️</span><span>Workflow</span>
26
- </a>
27
- <a href="history.html" class="nav-item active">
28
- <span class="icon">📜</span><span>History</span>
29
- </a>
30
- <a href="settings.html" class="nav-item">
31
- <span class="icon">🔧</span><span>Settings</span>
32
- </a>
33
- </div>
34
- <div class="sidebar-footer">
35
- <div class="user-menu" id="logout-btn">
36
- <div class="user-avatar" id="user-avatar">U</div>
37
- <span class="user-name" id="user-display-name">User</span>
38
- </div>
39
- </div>
40
- </nav>
41
-
42
- <!-- Main Content -->
43
- <main class="main-content">
44
- <div class="page-header">
45
- <h2>History</h2>
46
- <p>Browse all past workflow executions</p>
47
- </div>
48
-
49
- <div id="history-list">
50
- <div class="spinner" style="margin: 3rem auto;"></div>
51
- </div>
52
- </main>
53
- </div>
54
-
55
- <script src="/js/api.js"></script>
56
- <script src="/js/auth.js"></script>
57
- <script src="/js/router.js"></script>
58
- <script src="/js/app.js"></script>
59
- <script>
60
- if (Router.init()) {
61
- App.initSidebar();
62
- loadHistory();
63
- }
64
-
65
- async function loadHistory() {
66
- try {
67
- const workflows = await API.get('/api/workflows');
68
- const container = document.getElementById('history-list');
69
-
70
- if (workflows.length === 0) {
71
- container.innerHTML = `
72
- <div class="placeholder-content">
73
- <div class="icon-placeholder">📜</div>
74
- <h3>No history yet</h3>
75
- <p>Your completed workflows will appear here.</p>
76
- </div>
77
- `;
78
- return;
79
- }
80
-
81
- container.innerHTML = `
82
- <div class="card-grid">
83
- ${workflows.map((wf, i) => `
84
- <div class="card workflow-card fade-in" style="animation-delay: ${i * 0.05}s"
85
- onclick="window.location.href='/workflow.html?id=${wf.id}'">
86
- <div class="card-header">
87
- <span class="badge badge-${wf.status}">${wf.status}</span>
88
- <span class="meta">${new Date(wf.created_at).toLocaleDateString()}</span>
89
- </div>
90
- <div class="prompt-preview">${wf.prompt}</div>
91
- <div class="meta">
92
- <span>ID: ${wf.id.substring(0, 8)}…</span>
93
- </div>
94
- </div>
95
- `).join('')}
96
- </div>
97
- `;
98
- } catch (err) {
99
- App.showToast(err.message, 'error');
100
- }
101
- }
102
- </script>
103
- </body>
104
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/index.html DELETED
@@ -1,22 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="AutoForge — Autonomous AI Coding System">
7
- <title>AutoForge</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <script src="/js/api.js"></script>
12
- <script src="/js/auth.js"></script>
13
- <script>
14
- // Redirect based on auth state
15
- if (Auth.isAuthenticated()) {
16
- window.location.replace('/dashboard.html');
17
- } else {
18
- window.location.replace('/login.html');
19
- }
20
- </script>
21
- </body>
22
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/api.js DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * AutoForge API Client
3
- *
4
- * Wraps fetch() with JWT injection, error handling, and base URL management.
5
- */
6
-
7
- const API = (() => {
8
- const BASE_URL = '';
9
-
10
- /**
11
- * Make an authenticated API request.
12
- */
13
- async function request(method, path, body = null) {
14
- const headers = { 'Content-Type': 'application/json' };
15
-
16
- const token = localStorage.getItem('autoforge_token');
17
- if (token) {
18
- headers['Authorization'] = `Bearer ${token}`;
19
- }
20
-
21
- const options = { method, headers };
22
- if (body) {
23
- options.body = JSON.stringify(body);
24
- }
25
-
26
- const response = await fetch(`${BASE_URL}${path}`, options);
27
-
28
- if (response.status === 401) {
29
- localStorage.removeItem('autoforge_token');
30
- localStorage.removeItem('autoforge_user');
31
- window.location.href = '/login.html';
32
- throw new Error('Session expired');
33
- }
34
-
35
- const data = await response.json();
36
-
37
- if (!response.ok) {
38
- const message = data.detail || `Request failed (${response.status})`;
39
- throw new Error(message);
40
- }
41
-
42
- return data;
43
- }
44
-
45
- return {
46
- get: (path) => request('GET', path),
47
- post: (path, body) => request('POST', path, body),
48
- put: (path, body) => request('PUT', path, body),
49
- delete: (path) => request('DELETE', path),
50
- };
51
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/app.js DELETED
@@ -1,174 +0,0 @@
1
- /**
2
- * AutoForge Dashboard Application Logic
3
- */
4
-
5
- const App = (() => {
6
- let workflows = [];
7
-
8
- // ── Toast Notifications ─────────────────────────────────────────
9
-
10
- function showToast(message, type = 'success') {
11
- // Remove existing toasts
12
- document.querySelectorAll('.toast').forEach(t => t.remove());
13
-
14
- const toast = document.createElement('div');
15
- toast.className = `toast toast-${type}`;
16
- toast.textContent = message;
17
- document.body.appendChild(toast);
18
-
19
- requestAnimationFrame(() => toast.classList.add('visible'));
20
-
21
- setTimeout(() => {
22
- toast.classList.remove('visible');
23
- setTimeout(() => toast.remove(), 300);
24
- }, 3000);
25
- }
26
-
27
- // ── Sidebar ─────────────────────────────────────────────────────
28
-
29
- function initSidebar() {
30
- const user = Auth.getUser();
31
- const userNameEl = document.getElementById('user-display-name');
32
- const userAvatarEl = document.getElementById('user-avatar');
33
- const logoutBtn = document.getElementById('logout-btn');
34
-
35
- if (user && userNameEl) {
36
- userNameEl.textContent = user.username;
37
- }
38
- if (user && userAvatarEl) {
39
- userAvatarEl.textContent = user.username.charAt(0).toUpperCase();
40
- }
41
- if (logoutBtn) {
42
- logoutBtn.addEventListener('click', (e) => {
43
- e.preventDefault();
44
- Auth.logout();
45
- });
46
- }
47
-
48
- // Highlight current nav item
49
- const currentPage = window.location.pathname.split('/').pop() || 'dashboard.html';
50
- document.querySelectorAll('.nav-item').forEach(item => {
51
- const href = item.getAttribute('href');
52
- if (href && currentPage === href) {
53
- item.classList.add('active');
54
- }
55
- });
56
- }
57
-
58
- // ── Workflows ───────────────────────────────────────────────────
59
-
60
- async function loadWorkflows() {
61
- try {
62
- workflows = await API.get('/api/workflows');
63
- renderWorkflows();
64
- updateStats();
65
- } catch (err) {
66
- showToast(err.message, 'error');
67
- }
68
- }
69
-
70
- function renderWorkflows() {
71
- const container = document.getElementById('workflows-list');
72
- if (!container) return;
73
-
74
- if (workflows.length === 0) {
75
- container.innerHTML = `
76
- <div class="empty-state fade-in">
77
- <div class="icon-empty">⚡</div>
78
- <h3>No workflows yet</h3>
79
- <p>Create your first workflow to get started with autonomous code generation.</p>
80
- </div>
81
- `;
82
- return;
83
- }
84
-
85
- container.innerHTML = workflows.map((wf, i) => `
86
- <div class="card workflow-card fade-in" style="animation-delay: ${i * 0.05}s" onclick="App.viewWorkflow('${wf.id}')">
87
- <div class="card-header">
88
- <span class="badge badge-${wf.status}">${wf.status}</span>
89
- <span class="meta">${_formatDate(wf.created_at)}</span>
90
- </div>
91
- <div class="prompt-preview">${_escapeHtml(wf.prompt)}</div>
92
- <div class="meta">
93
- <span>ID: ${wf.id.substring(0, 8)}…</span>
94
- </div>
95
- </div>
96
- `).join('');
97
- }
98
-
99
- function updateStats() {
100
- const totalEl = document.getElementById('stat-total');
101
- const pendingEl = document.getElementById('stat-pending');
102
- const completedEl = document.getElementById('stat-completed');
103
- const failedEl = document.getElementById('stat-failed');
104
-
105
- if (totalEl) totalEl.textContent = workflows.length;
106
- if (pendingEl) pendingEl.textContent = workflows.filter(w => w.status === 'pending').length;
107
- if (completedEl) completedEl.textContent = workflows.filter(w => w.status === 'completed').length;
108
- if (failedEl) failedEl.textContent = workflows.filter(w => w.status === 'failed').length;
109
- }
110
-
111
- // ── Create Workflow ─────────────────────────────────────────────
112
-
113
- function openCreateModal() {
114
- const overlay = document.getElementById('create-modal');
115
- if (overlay) overlay.classList.add('active');
116
- }
117
-
118
- function closeCreateModal() {
119
- const overlay = document.getElementById('create-modal');
120
- if (overlay) overlay.classList.remove('active');
121
- const input = document.getElementById('workflow-prompt');
122
- if (input) input.value = '';
123
- }
124
-
125
- async function createWorkflow() {
126
- const input = document.getElementById('workflow-prompt');
127
- const prompt = input ? input.value.trim() : '';
128
- if (!prompt) {
129
- showToast('Please enter a prompt', 'error');
130
- return;
131
- }
132
-
133
- try {
134
- const wf = await API.post('/api/workflows', { prompt });
135
- showToast('Workflow created successfully!');
136
- closeCreateModal();
137
- await loadWorkflows();
138
- } catch (err) {
139
- showToast(err.message, 'error');
140
- }
141
- }
142
-
143
- function viewWorkflow(id) {
144
- window.location.href = `/workflow.html?id=${id}`;
145
- }
146
-
147
- // ── Helpers ─────────────────────────────────────────────────────
148
-
149
- function _formatDate(iso) {
150
- const d = new Date(iso);
151
- return d.toLocaleDateString('en-US', {
152
- month: 'short', day: 'numeric', year: 'numeric',
153
- hour: '2-digit', minute: '2-digit',
154
- });
155
- }
156
-
157
- function _escapeHtml(str) {
158
- const div = document.createElement('div');
159
- div.textContent = str;
160
- return div.innerHTML;
161
- }
162
-
163
- // ── Public API ──────────────────────────────────────────────────
164
-
165
- return {
166
- showToast,
167
- initSidebar,
168
- loadWorkflows,
169
- openCreateModal,
170
- closeCreateModal,
171
- createWorkflow,
172
- viewWorkflow,
173
- };
174
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/auth.js DELETED
@@ -1,58 +0,0 @@
1
- /**
2
- * AutoForge Authentication Helpers
3
- */
4
-
5
- const Auth = (() => {
6
- const TOKEN_KEY = 'autoforge_token';
7
- const USER_KEY = 'autoforge_user';
8
-
9
- function getToken() {
10
- return localStorage.getItem(TOKEN_KEY);
11
- }
12
-
13
- function isAuthenticated() {
14
- return !!getToken();
15
- }
16
-
17
- function saveSession(token, user = null) {
18
- localStorage.setItem(TOKEN_KEY, token);
19
- if (user) {
20
- localStorage.setItem(USER_KEY, JSON.stringify(user));
21
- }
22
- }
23
-
24
- function getUser() {
25
- const data = localStorage.getItem(USER_KEY);
26
- return data ? JSON.parse(data) : null;
27
- }
28
-
29
- function logout() {
30
- localStorage.removeItem(TOKEN_KEY);
31
- localStorage.removeItem(USER_KEY);
32
- window.location.href = '/login.html';
33
- }
34
-
35
- async function signup(username, email, password) {
36
- const data = await API.post('/api/auth/signup', { username, email, password });
37
- saveSession(data.access_token);
38
-
39
- // Fetch full user profile
40
- const user = await API.get('/api/auth/me');
41
- localStorage.setItem(USER_KEY, JSON.stringify(user));
42
-
43
- return user;
44
- }
45
-
46
- async function login(username, password) {
47
- const data = await API.post('/api/auth/login', { username, password });
48
- saveSession(data.access_token);
49
-
50
- // Fetch full user profile
51
- const user = await API.get('/api/auth/me');
52
- localStorage.setItem(USER_KEY, JSON.stringify(user));
53
-
54
- return user;
55
- }
56
-
57
- return { getToken, isAuthenticated, saveSession, getUser, logout, signup, login };
58
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/router.js DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * AutoForge Router — Simple navigation guard
3
- */
4
-
5
- const Router = (() => {
6
- const PUBLIC_PAGES = ['/login.html', '/login'];
7
-
8
- function init() {
9
- const path = window.location.pathname;
10
- const isPublic = PUBLIC_PAGES.some(p => path.endsWith(p));
11
-
12
- if (!Auth.isAuthenticated() && !isPublic) {
13
- window.location.href = '/login.html';
14
- return false;
15
- }
16
-
17
- if (Auth.isAuthenticated() && isPublic) {
18
- window.location.href = '/dashboard.html';
19
- return false;
20
- }
21
-
22
- return true;
23
- }
24
-
25
- return { init };
26
- })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/login.html DELETED
@@ -1,125 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="Sign in to AutoForge — Autonomous AI Coding System">
7
- <title>AutoForge — Sign In</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <div class="auth-layout">
12
- <div class="auth-card glass-strong">
13
- <div class="auth-header">
14
- <div class="logo-large">⚡</div>
15
- <h2 id="auth-title">Welcome back</h2>
16
- <p id="auth-subtitle">Sign in to your AutoForge account</p>
17
- </div>
18
-
19
- <form id="auth-form" onsubmit="return false;">
20
- <!-- Signup-only fields -->
21
- <div id="signup-fields" style="display: none;">
22
- <div class="form-group">
23
- <label class="form-label" for="signup-email">Email</label>
24
- <input class="form-input" type="email" id="signup-email" placeholder="you@example.com" autocomplete="email">
25
- </div>
26
- </div>
27
-
28
- <div class="form-group">
29
- <label class="form-label" for="auth-username">Username</label>
30
- <input class="form-input" type="text" id="auth-username" placeholder="Enter your username" autocomplete="username" required>
31
- </div>
32
-
33
- <div class="form-group">
34
- <label class="form-label" for="auth-password">Password</label>
35
- <input class="form-input" type="password" id="auth-password" placeholder="Enter your password" autocomplete="current-password" required>
36
- </div>
37
-
38
- <div id="auth-error" class="form-error"></div>
39
-
40
- <button type="submit" class="btn btn-primary btn-lg" id="auth-submit" style="width: 100%; margin-top: 0.5rem;">
41
- Sign In
42
- </button>
43
- </form>
44
-
45
- <div class="auth-toggle">
46
- <span id="toggle-text">Don't have an account?</span>
47
- <a href="#" id="toggle-link" onclick="toggleAuthMode(event)">Sign Up</a>
48
- </div>
49
- </div>
50
- </div>
51
-
52
- <script src="/js/api.js"></script>
53
- <script src="/js/auth.js"></script>
54
- <script src="/js/router.js"></script>
55
- <script>
56
- let isLoginMode = true;
57
-
58
- // Redirect if already authenticated
59
- Router.init();
60
-
61
- // Form submit handler
62
- document.getElementById('auth-form').addEventListener('submit', handleAuth);
63
-
64
- async function handleAuth(e) {
65
- e.preventDefault();
66
- const errorEl = document.getElementById('auth-error');
67
- errorEl.classList.remove('visible');
68
-
69
- const username = document.getElementById('auth-username').value.trim();
70
- const password = document.getElementById('auth-password').value;
71
-
72
- if (!username || !password) {
73
- showError('Please fill in all fields');
74
- return;
75
- }
76
-
77
- const submitBtn = document.getElementById('auth-submit');
78
- submitBtn.disabled = true;
79
- submitBtn.innerHTML = '<div class="spinner spinner-sm"></div>';
80
-
81
- try {
82
- if (isLoginMode) {
83
- await Auth.login(username, password);
84
- } else {
85
- const email = document.getElementById('signup-email').value.trim();
86
- if (!email) {
87
- showError('Please enter your email');
88
- return;
89
- }
90
- await Auth.signup(username, email, password);
91
- }
92
- window.location.href = '/dashboard.html';
93
- } catch (err) {
94
- showError(err.message);
95
- } finally {
96
- submitBtn.disabled = false;
97
- submitBtn.textContent = isLoginMode ? 'Sign In' : 'Create Account';
98
- }
99
- }
100
-
101
- function toggleAuthMode(e) {
102
- e.preventDefault();
103
- isLoginMode = !isLoginMode;
104
-
105
- document.getElementById('auth-title').textContent = isLoginMode ? 'Welcome back' : 'Create account';
106
- document.getElementById('auth-subtitle').textContent = isLoginMode
107
- ? 'Sign in to your AutoForge account'
108
- : 'Get started with AutoForge';
109
- document.getElementById('signup-fields').style.display = isLoginMode ? 'none' : 'block';
110
- document.getElementById('auth-submit').textContent = isLoginMode ? 'Sign In' : 'Create Account';
111
- document.getElementById('toggle-text').textContent = isLoginMode ? "Don't have an account?" : 'Already have an account?';
112
- document.getElementById('toggle-link').textContent = isLoginMode ? 'Sign Up' : 'Sign In';
113
-
114
- // Clear error
115
- document.getElementById('auth-error').classList.remove('visible');
116
- }
117
-
118
- function showError(message) {
119
- const el = document.getElementById('auth-error');
120
- el.textContent = message;
121
- el.classList.add('visible');
122
- }
123
- </script>
124
- </body>
125
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/settings.html DELETED
@@ -1,97 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="AutoForge Settings">
7
- <title>AutoForge — Settings</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <div class="app-layout">
12
- <!-- Sidebar -->
13
- <nav class="sidebar">
14
- <div class="sidebar-header">
15
- <div class="sidebar-brand">
16
- <div class="logo">⚡</div>
17
- <h1>AutoForge</h1>
18
- </div>
19
- </div>
20
- <div class="sidebar-nav">
21
- <a href="dashboard.html" class="nav-item">
22
- <span class="icon">📊</span><span>Dashboard</span>
23
- </a>
24
- <a href="workflow.html" class="nav-item">
25
- <span class="icon">⚙️</span><span>Workflow</span>
26
- </a>
27
- <a href="history.html" class="nav-item">
28
- <span class="icon">📜</span><span>History</span>
29
- </a>
30
- <a href="settings.html" class="nav-item active">
31
- <span class="icon">🔧</span><span>Settings</span>
32
- </a>
33
- </div>
34
- <div class="sidebar-footer">
35
- <div class="user-menu" id="logout-btn">
36
- <div class="user-avatar" id="user-avatar">U</div>
37
- <span class="user-name" id="user-display-name">User</span>
38
- </div>
39
- </div>
40
- </nav>
41
-
42
- <!-- Main Content -->
43
- <main class="main-content">
44
- <div class="page-header">
45
- <h2>Settings</h2>
46
- <p>Configure your AutoForge environment</p>
47
- </div>
48
-
49
- <div class="card glass fade-in" style="max-width: 640px; margin-bottom: 1.5rem;">
50
- <div class="card-header">
51
- <span class="card-title">LLM Configuration</span>
52
- </div>
53
- <div class="form-group">
54
- <label class="form-label" for="gemini-key">Gemini API Key</label>
55
- <input class="form-input" type="password" id="gemini-key" placeholder="Your API key (stored server-side via .env)" disabled>
56
- </div>
57
- <div class="form-group">
58
- <label class="form-label" for="gemini-model">Model</label>
59
- <input class="form-input" type="text" id="gemini-model" placeholder="gemini-2.0-flash" disabled>
60
- </div>
61
- <p style="color: var(--text-muted); font-size: 0.85rem;">
62
- LLM settings are configured via the <code style="color: var(--accent-blue);">.env</code> file on the server.
63
- UI-based configuration will be available in a future phase.
64
- </p>
65
- </div>
66
-
67
- <div class="card glass fade-in" style="max-width: 640px; animation-delay: 0.1s;">
68
- <div class="card-header">
69
- <span class="card-title">Account</span>
70
- </div>
71
- <div id="account-info" style="color: var(--text-secondary); margin-bottom: 1rem;">
72
- Loading…
73
- </div>
74
- <button class="btn btn-danger" onclick="Auth.logout()">Sign Out</button>
75
- </div>
76
- </main>
77
- </div>
78
-
79
- <script src="/js/api.js"></script>
80
- <script src="/js/auth.js"></script>
81
- <script src="/js/router.js"></script>
82
- <script src="/js/app.js"></script>
83
- <script>
84
- if (Router.init()) {
85
- App.initSidebar();
86
- const user = Auth.getUser();
87
- if (user) {
88
- document.getElementById('account-info').innerHTML = `
89
- <p><strong>Username:</strong> ${user.username}</p>
90
- <p><strong>Email:</strong> ${user.email}</p>
91
- <p><strong>Member since:</strong> ${new Date(user.created_at).toLocaleDateString()}</p>
92
- `;
93
- }
94
- }
95
- </script>
96
- </body>
97
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/workflow.html DELETED
@@ -1,118 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="AutoForge Workflow Details">
7
- <title>AutoForge — Workflow</title>
8
- <link rel="stylesheet" href="/css/style.css">
9
- </head>
10
- <body>
11
- <div class="app-layout">
12
- <!-- Sidebar -->
13
- <nav class="sidebar">
14
- <div class="sidebar-header">
15
- <div class="sidebar-brand">
16
- <div class="logo">⚡</div>
17
- <h1>AutoForge</h1>
18
- </div>
19
- </div>
20
- <div class="sidebar-nav">
21
- <a href="dashboard.html" class="nav-item">
22
- <span class="icon">📊</span><span>Dashboard</span>
23
- </a>
24
- <a href="workflow.html" class="nav-item active">
25
- <span class="icon">⚙️</span><span>Workflow</span>
26
- </a>
27
- <a href="history.html" class="nav-item">
28
- <span class="icon">📜</span><span>History</span>
29
- </a>
30
- <a href="settings.html" class="nav-item">
31
- <span class="icon">🔧</span><span>Settings</span>
32
- </a>
33
- </div>
34
- <div class="sidebar-footer">
35
- <div class="user-menu" id="logout-btn">
36
- <div class="user-avatar" id="user-avatar">U</div>
37
- <span class="user-name" id="user-display-name">User</span>
38
- </div>
39
- </div>
40
- </nav>
41
-
42
- <!-- Main Content -->
43
- <main class="main-content">
44
- <div class="page-header">
45
- <h2>Workflow Details</h2>
46
- <p id="workflow-id-display">Loading…</p>
47
- </div>
48
-
49
- <div id="workflow-detail">
50
- <div class="spinner" style="margin: 3rem auto;"></div>
51
- </div>
52
- </main>
53
- </div>
54
-
55
- <script src="/js/api.js"></script>
56
- <script src="/js/auth.js"></script>
57
- <script src="/js/router.js"></script>
58
- <script src="/js/app.js"></script>
59
- <script>
60
- if (Router.init()) {
61
- App.initSidebar();
62
-
63
- const params = new URLSearchParams(window.location.search);
64
- const id = params.get('id');
65
-
66
- if (id) {
67
- loadWorkflowDetail(id);
68
- } else {
69
- document.getElementById('workflow-detail').innerHTML = `
70
- <div class="placeholder-content">
71
- <div class="icon-placeholder">⚙️</div>
72
- <h3>Select a Workflow</h3>
73
- <p>Choose a workflow from the dashboard to view its details and execution progress.</p>
74
- </div>
75
- `;
76
- }
77
-
78
- async function loadWorkflowDetail(workflowId) {
79
- try {
80
- const wf = await API.get(`/api/workflows/${workflowId}`);
81
- document.getElementById('workflow-id-display').textContent = `ID: ${wf.id}`;
82
- document.getElementById('workflow-detail').innerHTML = `
83
- <div class="card glass fade-in" style="margin-bottom: 1.5rem;">
84
- <div class="card-header">
85
- <span class="card-title">Prompt</span>
86
- <span class="badge badge-${wf.status}">${wf.status}</span>
87
- </div>
88
- <p style="color: var(--text-secondary); line-height: 1.7; font-family: var(--font-mono); font-size: 0.9rem;">${wf.prompt}</p>
89
- </div>
90
- <div class="card glass fade-in" style="animation-delay: 0.1s;">
91
- <div class="card-header">
92
- <span class="card-title">Tasks</span>
93
- <span class="badge badge-pending">${wf.tasks.length} task(s)</span>
94
- </div>
95
- ${wf.tasks.length === 0
96
- ? '<p style="color: var(--text-muted);">No tasks created yet. DAG execution will populate tasks in a future phase.</p>'
97
- : wf.tasks.map(t => `
98
- <div style="padding: 0.75rem; border-bottom: 1px solid var(--border-subtle);">
99
- <strong>${t.task_type}</strong> — <span class="badge badge-${t.status}">${t.status}</span>
100
- </div>
101
- `).join('')
102
- }
103
- </div>
104
- `;
105
- } catch (err) {
106
- document.getElementById('workflow-detail').innerHTML = `
107
- <div class="placeholder-content">
108
- <div class="icon-placeholder">❌</div>
109
- <h3>Error</h3>
110
- <p>${err.message}</p>
111
- </div>
112
- `;
113
- }
114
- }
115
- }
116
- </script>
117
- </body>
118
- </html>