Z User commited on
Commit
2476d62
Β·
1 Parent(s): 3fa1cf7

fix: Redesign UI to match DeepSeek chat style

Browse files

- Clean white/light gray background (not dark)
- Centered layout with proper sidebar
- All settings VISIBLE and accessible:
- Model selector in header
- Temperature slider
- Max tokens setting
- Storage mode indicator (Local/HF Hub/Bucket)
- Theme toggle (light/dark)
- Export buttons
- Left sidebar with New Chat, history, file explorer
- Clean message bubbles (user right, AI left)
- Code blocks with syntax styling
- Professional typography and spacing
- Responsive design for all screen sizes

Files changed (1) hide show
  1. index.html +1142 -721
index.html CHANGED
@@ -7,66 +7,58 @@
7
  <meta name="description" content="AI-powered code agent with MCP support, multiple 1B models, and Gemini CLI patterns">
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
11
  <style>
12
  /* ═══════════════════════════════════════════════════════
13
- SONICODER V2 - FUTURISTIC UI DESIGN SYSTEM
14
- Premium AI Code Agent Interface
15
  ═══════════════════════════════════════════════════════ */
16
 
17
- /* ═══ CSS VARIABLES & DESIGN TOKENS ═══ */
18
  :root {
19
  /* Core Colors */
20
- --bg-deep: #050810;
21
- --bg-primary: #0a0e17;
22
- --bg-secondary: #0d1321;
23
- --bg-tertiary: #111827;
24
- --bg-elevated: #151d2e;
25
 
26
- /* Glass Effect Colors */
27
- --glass-bg: rgba(15, 23, 42, 0.65);
28
- --glass-bg-light: rgba(20, 30, 50, 0.5);
29
- --glass-border: rgba(100, 180, 255, 0.12);
30
- --glass-border-hover: rgba(0, 212, 255, 0.25);
31
- --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
32
-
33
- /* Accent Colors - Neon */
34
- --cyan: #00d4ff;
35
- --cyan-bright: #5eeaff;
36
- --cyan-dim: #007a94;
37
- --cyan-glow: rgba(0, 212, 255, 0.4);
38
- --cyan-glow-subtle: rgba(0, 212, 255, 0.15);
39
-
40
- --purple: #a855f7;
41
- --purple-bright: #c084fc;
42
- --purple-dim: #7c3aed;
43
- --purple-glow: rgba(168, 85, 247, 0.4);
44
- --purple-glow-subtle: rgba(168, 85, 247, 0.15);
45
-
46
- --green: #39ff14;
47
- --green-dim: #22c55e;
48
- --green-glow: rgba(57, 255, 20, 0.35);
49
 
50
- --amber: #ffb300;
51
- --amber-glow: rgba(255, 179, 0, 0.3);
 
 
 
52
 
53
- --red: #ff5555;
54
- --red-glow: rgba(255, 85, 85, 0.3);
 
 
55
 
56
- /* Text Colors */
57
- --text-primary: #f1f5f9;
58
- --text-secondary: #94a3b8;
59
- --text-muted: #64748b;
60
- --text-accent: var(--cyan);
 
 
 
 
61
 
62
- /* Border Colors */
63
- --border-default: rgba(71, 85, 105, 0.3);
64
- --border-focus: var(--cyan);
65
- --border-glow: 0 0 0 1px var(--cyan), 0 0 20px var(--cyan-glow);
 
66
 
67
  /* Typography */
68
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
69
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
70
 
71
  /* Spacing & Sizing */
72
  --radius-sm: 6px;
@@ -74,13 +66,17 @@
74
  --radius-lg: 16px;
75
  --radius-xl: 24px;
76
  --header-height: 56px;
77
- --sidebar-width: 260px;
78
 
79
  /* Transitions */
80
- --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
81
- --transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
82
- --transition-slow: 400ms cubic-bezier(0.4, 0, 0.2, 1);
83
- --transition-spring: 500ms cubic-bezier(0.34, 1.56, 0.64, 1);
 
 
 
 
84
 
85
  /* Z-Index Scale */
86
  --z-base: 1;
@@ -90,6 +86,30 @@
90
  --z-toast: 2000;
91
  }
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  /* ═══ RESET & BASE ═══ */
94
  *, *::before, *::after {
95
  box-sizing: border-box;
@@ -104,16 +124,15 @@ html {
104
 
105
  body {
106
  height: 100%;
107
- background: var(--bg-deep);
108
  color: var(--text-primary);
109
  font-family: var(--font-sans);
110
  line-height: 1.6;
111
  overflow: hidden;
112
- position: relative;
113
  }
114
 
115
  ::selection {
116
- background: var(--cyan-glow);
117
  color: white;
118
  }
119
 
@@ -129,103 +148,10 @@ body {
129
  ::-webkit-scrollbar-thumb {
130
  background: var(--border-default);
131
  border-radius: 3px;
132
- transition: background var(--transition-fast);
133
  }
134
 
135
  ::-webkit-scrollbar-thumb:hover {
136
- background: var(--cyan-dim);
137
- }
138
-
139
- /* ═══ ANIMATED BACKGROUND SYSTEM ═══ */
140
- .bg-canvas {
141
- position: fixed;
142
- inset: 0;
143
- z-index: 0;
144
- overflow: hidden;
145
- pointer-events: none;
146
- }
147
-
148
- .bg-gradient-mesh {
149
- position: absolute;
150
- inset: 0;
151
- background:
152
- radial-gradient(ellipse 80% 60% at 20% 10%, rgba(0, 212, 255, 0.08) 0%, transparent 50%),
153
- radial-gradient(ellipse 60% 80% at 80% 90%, rgba(168, 85, 247, 0.06) 0%, transparent 50%),
154
- radial-gradient(ellipse 50% 50% at 50% 50%, rgba(57, 255, 20, 0.03) 0%, transparent 60%);
155
- animation: meshFloat 20s ease-in-out infinite alternate;
156
- }
157
-
158
- @keyframes meshFloat {
159
- 0% { transform: scale(1) rotate(0deg); opacity: 1; }
160
- 50% { transform: scale(1.1) rotate(1deg); opacity: 0.9; }
161
- 100% { transform: scale(1) rotate(-1deg); opacity: 1; }
162
- }
163
-
164
- .particles-container {
165
- position: absolute;
166
- inset: 0;
167
- }
168
-
169
- .particle {
170
- position: absolute;
171
- width: 2px;
172
- height: 2px;
173
- background: var(--cyan);
174
- border-radius: 50%;
175
- box-shadow: 0 0 6px var(--cyan-glow), 0 0 12px var(--cyan-glow-subtle);
176
- opacity: 0;
177
- animation: particleFloat linear infinite;
178
- }
179
-
180
- .particle:nth-child(odd) {
181
- background: var(--purple);
182
- box-shadow: 0 0 6px var(--purple-glow), 0 0 12px var(--purple-glow-subtle);
183
- }
184
-
185
- @keyframes particleFloat {
186
- 0% {
187
- opacity: 0;
188
- transform: translateY(100vh) scale(0);
189
- }
190
- 10% {
191
- opacity: 0.6;
192
- transform: translateY(90vh) scale(1);
193
- }
194
- 90% {
195
- opacity: 0.6;
196
- transform: translateY(10vh) scale(1);
197
- }
198
- 100% {
199
- opacity: 0;
200
- transform: translateY(-10vh) scale(0);
201
- }
202
- }
203
-
204
- .grid-overlay {
205
- position: absolute;
206
- inset: 0;
207
- background-image:
208
- linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px),
209
- linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px);
210
- background-size: 50px 50px;
211
- mask-image: radial-gradient(ellipse at center, black 30%, transparent 70%);
212
- -webkit-mask-image: radial-gradient(ellipse at center, black 30%, transparent 70%);
213
- }
214
-
215
- .scanline {
216
- position: absolute;
217
- top: 0;
218
- left: 0;
219
- right: 0;
220
- height: 2px;
221
- background: linear-gradient(90deg, transparent, var(--cyan-glow-subtle), transparent);
222
- animation: scanlineMove 8s linear infinite;
223
- opacity: 0.5;
224
- }
225
-
226
- @keyframes scanlineMove {
227
- 0% { top: -2px; }
228
- 100% { top: 100%; }
229
  }
230
 
231
  /* ═══ MAIN LAYOUT ═══ */
@@ -244,25 +170,13 @@ body {
244
  display: flex;
245
  align-items: center;
246
  justify-content: space-between;
247
- padding: 0 16px;
248
- background: var(--glass-bg);
249
- backdrop-filter: blur(20px);
250
- -webkit-backdrop-filter: blur(20px);
251
- border-bottom: 1px solid var(--glass-border);
252
  position: relative;
253
  z-index: var(--z-panel);
254
  }
255
 
256
- .header::before {
257
- content: '';
258
- position: absolute;
259
- bottom: 0;
260
- left: 0;
261
- right: 0;
262
- height: 1px;
263
- background: linear-gradient(90deg, transparent, var(--cyan-glow-subtle), var(--purple-glow-subtle), transparent);
264
- }
265
-
266
  .header-left {
267
  display: flex;
268
  align-items: center;
@@ -274,46 +188,24 @@ body {
274
  align-items: center;
275
  gap: 10px;
276
  cursor: pointer;
277
- transition: transform var(--transition-fast);
278
  }
279
 
280
  .logo:hover {
281
- transform: scale(1.02);
282
  }
283
 
284
  .logo-icon {
285
- width: 36px;
286
- height: 36px;
287
- background: linear-gradient(135deg, var(--cyan), var(--purple));
288
  border-radius: var(--radius-md);
289
  display: flex;
290
  align-items: center;
291
  justify-content: center;
292
- font-size: 18px;
293
  font-weight: 700;
294
  color: white;
295
- box-shadow: 0 4px 15px var(--cyan-glow), 0 0 30px var(--purple-glow-subtle);
296
- animation: logoPulse 3s ease-in-out infinite;
297
- position: relative;
298
- overflow: hidden;
299
- }
300
-
301
- .logo-icon::after {
302
- content: '';
303
- position: absolute;
304
- inset: -50%;
305
- background: conic-gradient(from 0deg, transparent, rgba(255,255,255,0.3), transparent);
306
- animation: logoShine 4s linear infinite;
307
- }
308
-
309
- @keyframes logoPulse {
310
- 0%, 100% { box-shadow: 0 4px 15px var(--cyan-glow), 0 0 30px var(--purple-glow-subtle); }
311
- 50% { box-shadow: 0 4px 25px var(--cyan-glow), 0 0 40px var(--purple-glow); }
312
- }
313
-
314
- @keyframes logoShine {
315
- from { transform: rotate(0deg); }
316
- to { transform: rotate(360deg); }
317
  }
318
 
319
  .logo-text {
@@ -323,20 +215,17 @@ body {
323
  }
324
 
325
  .logo-title {
326
- font-size: 16px;
327
  font-weight: 700;
328
- letter-spacing: -0.5px;
329
- background: linear-gradient(135deg, var(--text-primary), var(--cyan-bright));
330
- -webkit-background-clip: text;
331
- -webkit-text-fill-color: transparent;
332
- background-clip: text;
333
  }
334
 
335
  .logo-version {
336
  font-size: 10px;
337
  color: var(--text-muted);
338
  text-transform: uppercase;
339
- letter-spacing: 1px;
340
  font-weight: 500;
341
  }
342
 
@@ -344,25 +233,66 @@ body {
344
  display: flex;
345
  align-items: center;
346
  gap: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  }
348
 
349
  .model-selector {
350
  display: flex;
351
  align-items: center;
352
  gap: 8px;
353
- padding: 6px 14px;
354
- background: var(--glass-bg-light);
355
- border: 1px solid var(--glass-border);
356
  border-radius: var(--radius-xl);
357
  cursor: pointer;
358
  transition: all var(--transition-fast);
 
359
  position: relative;
360
- overflow: hidden;
361
  }
362
 
363
  .model-selector:hover {
364
- border-color: var(--glass-border-hover);
365
- box-shadow: 0 0 20px var(--cyan-glow-subtle);
366
  }
367
 
368
  .model-dot {
@@ -374,39 +304,72 @@ body {
374
  }
375
 
376
  .model-dot.ready {
377
- background: var(--green);
378
- box-shadow: 0 0 8px var(--green-glow);
379
- animation: dotPulse 2s ease-in-out infinite;
380
  }
381
 
382
  .model-dot.loading {
383
- background: var(--amber);
384
- animation: dotSpin 1s linear infinite;
385
  }
386
 
387
  .model-dot.error {
388
- background: var(--red);
389
- box-shadow: 0 0 8px var(--red-glow);
390
- }
391
-
392
- @keyframes dotPulse {
393
- 0%, 100% { transform: scale(1); opacity: 1; }
394
- 50% { transform: scale(1.2); opacity: 0.7; }
395
  }
396
 
397
- @keyframes dotSpin {
398
- 0% { transform: rotate(0deg); }
399
- 100% { transform: rotate(360deg); }
400
  }
401
 
402
  .model-text {
403
- font-size: 12px;
404
  font-weight: 500;
405
  color: var(--text-secondary);
406
- max-width: 120px;
 
 
 
 
 
 
 
 
 
 
 
 
407
  overflow: hidden;
408
- text-overflow: ellipsis;
409
- white-space: nowrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  }
411
 
412
  .header-right {
@@ -425,17 +388,18 @@ body {
425
  display: flex;
426
  align-items: center;
427
  gap: 6px;
428
- padding: 5px 12px;
429
- background: var(--glass-bg-light);
430
- border: 1px solid var(--glass-border);
431
  border-radius: var(--radius-xl);
432
- font-size: 11px;
433
  font-weight: 500;
 
434
  transition: all var(--transition-fast);
435
  }
436
 
437
  .status-pill:hover {
438
- border-color: var(--glass-border-hover);
439
  }
440
 
441
  .status-pill .dot {
@@ -447,44 +411,57 @@ body {
447
 
448
  .status-pill .dot.connected,
449
  .status-pill .dot.ready {
450
- background: var(--green);
451
- box-shadow: 0 0 6px var(--green-glow);
452
  }
453
 
454
- .status-pill .dot.disconnected {
455
- background: var(--red);
 
456
  }
457
 
458
  .status-pill .dot.loading {
459
- background: var(--amber);
460
- animation: dotSpin 1s linear infinite;
461
  }
462
 
463
  .btn-icon {
464
- width: 34px;
465
- height: 34px;
466
  display: flex;
467
  align-items: center;
468
  justify-content: center;
469
- background: var(--glass-bg-light);
470
- border: 1px solid var(--glass-border);
471
  border-radius: var(--radius-md);
472
  color: var(--text-secondary);
473
  cursor: pointer;
474
  transition: all var(--transition-fast);
475
- font-size: 14px;
476
  }
477
 
478
  .btn-icon:hover {
479
- background: var(--glass-bg);
480
- border-color: var(--cyan-dim);
481
- color: var(--cyan);
482
- box-shadow: 0 0 15px var(--cyan-glow-subtle);
483
- transform: translateY(-1px);
484
  }
485
 
486
- .btn-icon:active {
487
- transform: translateY(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  }
489
 
490
  /* ═══ MAIN CONTENT AREA ═══ */
@@ -499,10 +476,8 @@ body {
499
  .sidebar {
500
  width: var(--sidebar-width);
501
  min-width: var(--sidebar-width);
502
- background: var(--glass-bg);
503
- backdrop-filter: blur(20px);
504
- -webkit-backdrop-filter: blur(20px);
505
- border-right: 1px solid var(--glass-border);
506
  display: flex;
507
  flex-direction: column;
508
  overflow: hidden;
@@ -510,56 +485,103 @@ body {
510
  z-index: var(--z-panel);
511
  }
512
 
513
- .sidebar::before {
514
- content: '';
515
- position: absolute;
516
- top: 0;
517
- right: 0;
518
- bottom: 0;
519
- width: 1px;
520
- background: linear-gradient(180deg, var(--cyan-glow-subtle), transparent, var(--purple-glow-subtle));
521
- opacity: 0.5;
522
- }
523
-
524
  .sidebar-header {
525
  padding: 16px;
526
- border-bottom: 1px solid var(--glass-border);
 
 
 
 
527
  display: flex;
528
  align-items: center;
529
- justify-content: space-between;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
530
  }
531
 
532
- .sidebar-title {
533
  font-size: 11px;
534
  font-weight: 600;
535
  text-transform: uppercase;
536
- letter-spacing: 1.5px;
537
  color: var(--text-muted);
 
 
 
 
538
  }
539
 
540
- .sidebar-actions {
541
  display: flex;
542
- gap: 4px;
 
 
 
543
  }
544
 
545
- .btn-sidebar-action {
546
- width: 24px;
547
- height: 24px;
548
  display: flex;
549
  align-items: center;
550
- justify-content: center;
551
- background: transparent;
552
- border: none;
553
  border-radius: var(--radius-sm);
554
- color: var(--text-muted);
555
  cursor: pointer;
556
  transition: all var(--transition-fast);
557
- font-size: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  }
559
 
560
- .btn-sidebar-action:hover {
561
- background: var(--glass-bg-light);
562
- color: var(--cyan);
 
 
563
  }
564
 
565
  .sidebar-content {
@@ -591,20 +613,19 @@ body {
591
  }
592
 
593
  .ws-dir-name:hover {
594
- background: var(--glass-bg-light);
595
- color: var(--cyan);
596
  }
597
 
598
- .ws-dir-name::before {
599
- content: 'πŸ“';
600
- font-size: 11px;
601
- filter: grayscale(0.3);
602
  }
603
 
604
  .ws-children {
605
  margin-left: 16px;
606
  padding-left: 12px;
607
- border-left: 1px solid var(--border-default);
608
  }
609
 
610
  .ws-file {
@@ -624,14 +645,14 @@ body {
624
  }
625
 
626
  .ws-file > span:hover {
627
- background: var(--glass-bg-light);
628
- color: var(--cyan-bright);
629
  padding-left: 12px;
630
  }
631
 
632
- .ws-file > span::before {
633
- content: 'πŸ“„';
634
  font-size: 11px;
 
635
  }
636
 
637
  .ws-empty {
@@ -647,14 +668,14 @@ body {
647
  align-items: center;
648
  gap: 12px;
649
  padding: 12px;
650
- background: var(--glass-bg-light);
651
- border-bottom: 1px solid var(--glass-border);
652
  }
653
 
654
  .file-viewer-header button {
655
  padding: 6px 12px;
656
- background: var(--glass-bg);
657
- border: 1px solid var(--glass-border);
658
  border-radius: var(--radius-sm);
659
  color: var(--text-secondary);
660
  cursor: pointer;
@@ -664,8 +685,8 @@ body {
664
  }
665
 
666
  .file-viewer-header button:hover {
667
- border-color: var(--cyan-dim);
668
- color: var(--cyan);
669
  }
670
 
671
  .file-viewer-header span {
@@ -687,35 +708,18 @@ body {
687
  word-break: break-all;
688
  }
689
 
690
- /* Sidebar Sections */
691
- .sidebar-section {
692
- margin-bottom: 16px;
693
- }
694
-
695
- .sidebar-section-title {
696
- font-size: 10px;
697
- font-weight: 600;
698
- text-transform: uppercase;
699
- letter-spacing: 1px;
700
- color: var(--text-muted);
701
- padding: 8px 12px 6px;
702
- display: flex;
703
- align-items: center;
704
- gap: 6px;
705
- }
706
-
707
  /* MCP Section */
708
  .mcp-server {
709
  padding: 10px 12px;
710
- background: var(--glass-bg-light);
711
- border: 1px solid var(--glass-border);
712
  border-radius: var(--radius-md);
713
  margin-bottom: 8px;
714
  transition: all var(--transition-fast);
715
  }
716
 
717
  .mcp-server:hover {
718
- border-color: var(--glass-border-hover);
719
  }
720
 
721
  .mcp-server-header {
@@ -733,12 +737,11 @@ body {
733
  }
734
 
735
  .mcp-server-dot.connected {
736
- background: var(--green);
737
- box-shadow: 0 0 6px var(--green-glow);
738
  }
739
 
740
  .mcp-server-dot.disconnected {
741
- background: var(--red);
742
  }
743
 
744
  .mcp-server-name {
@@ -758,24 +761,18 @@ body {
758
  }
759
 
760
  .tool-badge.success {
761
- background: rgba(57, 255, 20, 0.15);
762
- color: var(--green);
763
  }
764
 
765
  .tool-badge.error {
766
- background: rgba(255, 85, 85, 0.15);
767
- color: var(--red);
768
  }
769
 
770
  .tool-badge.running {
771
- background: rgba(255, 179, 0, 0.15);
772
- color: var(--amber);
773
- animation: badgePulse 1.5s ease-in-out infinite;
774
- }
775
-
776
- @keyframes badgePulse {
777
- 0%, 100% { opacity: 1; }
778
- 50% { opacity: 0.6; }
779
  }
780
 
781
  .mcp-tools {
@@ -800,6 +797,272 @@ body {
800
  line-height: 1.6;
801
  }
802
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803
  /* ═══ CHAT AREA ═══ */
804
  .chat-area {
805
  flex: 1;
@@ -807,6 +1070,7 @@ body {
807
  flex-direction: column;
808
  overflow: hidden;
809
  position: relative;
 
810
  }
811
 
812
  .chat-messages {
@@ -822,137 +1086,72 @@ body {
822
 
823
  /* Welcome Banner */
824
  .welcome-banner {
825
- max-width: 600px;
826
- margin: 40px auto;
827
  text-align: center;
828
- padding: 40px;
829
- background: var(--glass-bg);
830
- backdrop-filter: blur(20px);
831
- -webkit-backdrop-filter: blur(20px);
832
- border: 1px solid var(--glass-border);
833
- border-radius: var(--radius-xl);
834
- position: relative;
835
- overflow: hidden;
836
- }
837
-
838
- .welcome-banner::before {
839
- content: '';
840
- position: absolute;
841
- top: 0;
842
- left: 0;
843
- right: 0;
844
- height: 1px;
845
- background: linear-gradient(90deg, transparent, var(--cyan), var(--purple), transparent);
846
- }
847
-
848
- .welcome-banner::after {
849
- content: '';
850
- position: absolute;
851
- inset: 0;
852
- background: radial-gradient(ellipse at center top, var(--cyan-glow-subtle), transparent 70%);
853
- pointer-events: none;
854
  }
855
 
856
- .banner-icon {
857
- font-size: 48px;
858
- margin-bottom: 16px;
859
- display: block;
860
- animation: bannerFloat 3s ease-in-out infinite;
861
- }
862
-
863
- @keyframes bannerFloat {
864
- 0%, 100% { transform: translateY(0); }
865
- 50% { transform: translateY(-8px); }
866
- }
867
-
868
- .banner-title {
869
- font-size: 24px;
870
- font-weight: 700;
871
- margin-bottom: 8px;
872
- background: linear-gradient(135deg, var(--text-primary), var(--cyan-bright), var(--purple-bright));
873
- -webkit-background-clip: text;
874
- -webkit-text-fill-color: transparent;
875
- background-clip: text;
876
  }
877
 
878
- .banner-model {
879
- font-size: 13px;
880
- color: var(--cyan);
881
- margin-bottom: 16px;
882
- font-family: var(--font-mono);
 
883
  }
884
 
885
- .banner-desc {
 
886
  color: var(--text-secondary);
887
- font-size: 14px;
888
- line-height: 1.7;
889
- margin-bottom: 24px;
890
- }
891
-
892
- .examples-row {
893
- display: flex;
894
- flex-wrap: wrap;
895
- gap: 8px;
896
- justify-content: center;
897
  }
898
 
899
- .examples-label {
900
- font-size: 12px;
901
- color: var(--text-muted);
902
- display: flex;
903
- align-items: center;
904
- margin-right: 4px;
905
  }
906
 
907
- .example-chip {
908
- padding: 8px 14px;
909
- background: var(--glass-bg-light);
910
- border: 1px solid var(--glass-border);
911
- border-radius: var(--radius-xl);
912
- font-size: 12px;
913
  color: var(--text-secondary);
914
  cursor: pointer;
915
  transition: all var(--transition-fast);
916
- position: relative;
917
- overflow: hidden;
918
- }
919
-
920
- .example-chip::before {
921
- content: '';
922
- position: absolute;
923
- inset: 0;
924
- background: linear-gradient(135deg, var(--cyan-glow-subtle), var(--purple-glow-subtle));
925
- opacity: 0;
926
- transition: opacity var(--transition-fast);
927
  }
928
 
929
- .example-chip:hover {
930
- border-color: var(--cyan-dim);
931
- color: var(--cyan);
 
932
  transform: translateY(-2px);
933
- box-shadow: 0 4px 20px var(--cyan-glow-subtle);
934
- }
935
-
936
- .example-chip:hover::before {
937
- opacity: 1;
938
- }
939
-
940
- .example-chip span {
941
- position: relative;
942
- z-index: 1;
943
  }
944
 
945
  /* Message Styles */
946
  .msg {
947
- margin-bottom: 20px;
948
- animation: msgSlideIn 0.3s ease-out;
949
  position: relative;
950
  }
951
 
952
  @keyframes msgSlideIn {
953
  from {
954
  opacity: 0;
955
- transform: translateY(10px);
956
  }
957
  to {
958
  opacity: 1;
@@ -967,24 +1166,13 @@ body {
967
 
968
  .msg-user .msg-content-wrapper {
969
  max-width: 75%;
970
- background: linear-gradient(135deg, rgba(0, 212, 255, 0.15), rgba(0, 212, 255, 0.05));
971
- border: 1px solid rgba(0, 212, 255, 0.2);
972
  border-radius: var(--radius-lg) var(--radius-lg) 4px var(--radius-lg);
973
  padding: 14px 18px;
974
  position: relative;
975
  }
976
 
977
- .msg-user .msg-content-wrapper::before {
978
- content: '';
979
- position: absolute;
980
- top: 0;
981
- left: 0;
982
- right: 0;
983
- height: 1px;
984
- background: linear-gradient(90deg, transparent, var(--cyan-glow-subtle), transparent);
985
- border-radius: var(--radius-lg) var(--radius-lg) 0 0;
986
- }
987
-
988
  .msg-assistant {
989
  display: flex;
990
  justify-content: flex-start;
@@ -992,10 +1180,8 @@ body {
992
 
993
  .msg-assistant .msg-content-wrapper {
994
  max-width: 85%;
995
- background: var(--glass-bg);
996
- backdrop-filter: blur(10px);
997
- -webkit-backdrop-filter: blur(10px);
998
- border: 1px solid var(--glass-border);
999
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) 4px;
1000
  padding: 14px 18px;
1001
  position: relative;
@@ -1008,11 +1194,12 @@ body {
1008
 
1009
  .msg-system .msg-content-wrapper {
1010
  max-width: 80%;
1011
- background: var(--glass-bg-light);
1012
- border: 1px dashed var(--glass-border);
1013
  border-radius: var(--radius-md);
1014
  padding: 12px 20px;
1015
  text-align: center;
 
1016
  }
1017
 
1018
  .msg-prefix {
@@ -1021,19 +1208,19 @@ body {
1021
  }
1022
 
1023
  .msg-user .msg-prefix {
1024
- color: var(--cyan);
1025
  }
1026
 
1027
  .msg-assistant .msg-prefix {
1028
- color: var(--purple);
1029
  }
1030
 
1031
  .msg-system .msg-prefix {
1032
- color: var(--amber);
1033
  }
1034
 
1035
  .msg-content {
1036
- color: var(--text-primary);
1037
  line-height: 1.7;
1038
  word-wrap: break-word;
1039
  }
@@ -1047,56 +1234,37 @@ body {
1047
  align-items: center;
1048
  gap: 6px;
1049
  padding: 4px 10px;
1050
- background: var(--purple-glow-subtle);
1051
- border: 1px solid var(--purple);
1052
  border-radius: var(--radius-sm);
1053
- font-size: 10px;
1054
  font-weight: 600;
1055
- color: var(--purple-bright);
1056
- text-transform: uppercase;
1057
- letter-spacing: 0.5px;
1058
  margin-bottom: 10px;
1059
- animation: iterationGlow 2s ease-in-out infinite;
1060
- }
1061
-
1062
- @keyframes iterationGlow {
1063
- 0%, 100% { box-shadow: 0 0 10px var(--purple-glow-subtle); }
1064
- 50% { box-shadow: 0 0 20px var(--purple-glow); }
1065
  }
1066
 
1067
  /* Code Block Styles */
1068
  .code-block-wrap {
1069
  margin: 12px 0;
1070
- background: var(--bg-deep);
1071
  border: 1px solid var(--border-default);
1072
  border-radius: var(--radius-md);
1073
  overflow: hidden;
1074
- position: relative;
1075
- }
1076
-
1077
- .code-block-wrap::before {
1078
- content: '';
1079
- position: absolute;
1080
- top: 0;
1081
- left: 0;
1082
- right: 0;
1083
- height: 1px;
1084
- background: linear-gradient(90deg, var(--cyan-glow-subtle), var(--purple-glow-subtle));
1085
  }
1086
 
1087
  .code-block-header {
1088
  display: flex;
1089
  align-items: center;
1090
  justify-content: space-between;
1091
- padding: 8px 12px;
1092
- background: var(--bg-tertiary);
1093
- border-bottom: 1px solid var(--border-default);
1094
  }
1095
 
1096
  .code-lang {
1097
  font-size: 11px;
1098
  font-weight: 500;
1099
- color: var(--cyan);
1100
  text-transform: uppercase;
1101
  letter-spacing: 0.5px;
1102
  font-family: var(--font-mono);
@@ -1104,10 +1272,10 @@ body {
1104
 
1105
  .btn-copy {
1106
  padding: 4px 10px;
1107
- background: var(--glass-bg-light);
1108
- border: 1px solid var(--glass-border);
1109
- border-radius: var(--radius-sm);
1110
- color: var(--text-muted);
1111
  font-size: 11px;
1112
  cursor: pointer;
1113
  font-family: var(--font-mono);
@@ -1115,15 +1283,14 @@ body {
1115
  }
1116
 
1117
  .btn-copy:hover {
1118
- border-color: var(--cyan-dim);
1119
- color: var(--cyan);
1120
- box-shadow: 0 0 10px var(--cyan-glow-subtle);
1121
  }
1122
 
1123
  .btn-copy.copied {
1124
- background: rgba(57, 255, 20, 0.15);
1125
- border-color: var(--green);
1126
- color: var(--green);
1127
  }
1128
 
1129
  .code-block-wrap pre {
@@ -1136,19 +1303,18 @@ body {
1136
  font-family: var(--font-mono);
1137
  font-size: 12px;
1138
  line-height: 1.7;
1139
- color: var(--code-text, #e0e0e0);
1140
- --code-text: #e2e8f0;
1141
  }
1142
 
1143
  /* Inline code */
1144
  .msg-content code:not([id]) {
1145
  padding: 2px 6px;
1146
- background: var(--bg-deep);
1147
- border: 1px solid var(--border-default);
1148
  border-radius: 4px;
1149
  font-family: var(--font-mono);
1150
  font-size: 12px;
1151
- color: var(--cyan-bright);
1152
  }
1153
 
1154
  /* Headings in messages */
@@ -1158,8 +1324,8 @@ body {
1158
  color: var(--text-primary);
1159
  }
1160
 
1161
- .msg-content h1 { font-size: 18px; color: var(--cyan-bright); }
1162
- .msg-content h2 { font-size: 16px; color: var(--purple-bright); }
1163
  .msg-content h3 { font-size: 14px; }
1164
 
1165
  .msg-content strong {
@@ -1168,30 +1334,27 @@ body {
1168
  }
1169
 
1170
  .msg-content em {
1171
- color: var(--cyan);
1172
  font-style: normal;
1173
  }
1174
 
1175
  .msg-content li {
1176
  margin-left: 20px;
1177
  margin-bottom: 4px;
1178
- list-style: none;
1179
- position: relative;
1180
  }
1181
 
1182
- .msg-content li::before {
1183
- content: 'β–Ή';
1184
- position: absolute;
1185
- left: -16px;
1186
- color: var(--cyan);
1187
  }
1188
 
1189
  /* Streaming Cursor */
1190
  .streaming-cursor {
1191
  display: inline-block;
1192
  width: 8px;
1193
- height: 16px;
1194
- background: var(--cyan);
1195
  margin-left: 2px;
1196
  vertical-align: text-bottom;
1197
  animation: cursorBlink 1s step-end infinite;
@@ -1206,17 +1369,17 @@ body {
1206
  /* Tool Call Block */
1207
  .tool-block {
1208
  margin: 12px 0;
1209
- background: var(--bg-deep);
1210
- border: 1px solid var(--border-default);
1211
  border-radius: var(--radius-md);
1212
  overflow: hidden;
1213
- animation: toolSlideIn 0.3s ease-out;
1214
  }
1215
 
1216
  @keyframes toolSlideIn {
1217
  from {
1218
  opacity: 0;
1219
- transform: translateX(-10px);
1220
  }
1221
  to {
1222
  opacity: 1;
@@ -1230,17 +1393,17 @@ body {
1230
  gap: 10px;
1231
  padding: 12px 14px;
1232
  background: var(--bg-tertiary);
1233
- border-bottom: 1px solid var(--border-default);
1234
  cursor: pointer;
1235
  transition: background var(--transition-fast);
1236
  }
1237
 
1238
  .tool-header:hover {
1239
- background: var(--bg-elevated);
1240
  }
1241
 
1242
  .tool-icon {
1243
- font-size: 16px;
1244
  }
1245
 
1246
  .tool-name {
@@ -1258,8 +1421,8 @@ body {
1258
  color: var(--text-muted);
1259
  white-space: pre-wrap;
1260
  word-break: break-all;
1261
- border-bottom: 1px solid var(--border-default);
1262
- background: rgba(0, 0, 0, 0.2);
1263
  }
1264
 
1265
  .tool-result {
@@ -1274,33 +1437,20 @@ body {
1274
  }
1275
 
1276
  .tool-result.error-output {
1277
- color: var(--red);
1278
  }
1279
 
1280
  /* ═══ INPUT AREA ═══ */
1281
  .input-area {
1282
- padding: 16px 20px;
1283
- background: var(--glass-bg);
1284
- backdrop-filter: blur(20px);
1285
- -webkit-backdrop-filter: blur(20px);
1286
- border-top: 1px solid var(--glass-border);
1287
- position: relative;
1288
- }
1289
-
1290
- .input-area::before {
1291
- content: '';
1292
- position: absolute;
1293
- top: 0;
1294
- left: 0;
1295
- right: 0;
1296
- height: 1px;
1297
- background: linear-gradient(90deg, transparent, var(--cyan-glow-subtle), var(--purple-glow-subtle), transparent);
1298
  }
1299
 
1300
  .options-bar {
1301
  display: flex;
1302
  flex-wrap: wrap;
1303
- gap: 8px;
1304
  margin-bottom: 12px;
1305
  align-items: center;
1306
  }
@@ -1312,7 +1462,7 @@ body {
1312
  }
1313
 
1314
  .option-group label {
1315
- font-size: 10px;
1316
  font-weight: 500;
1317
  text-transform: uppercase;
1318
  letter-spacing: 0.5px;
@@ -1321,8 +1471,8 @@ body {
1321
 
1322
  .option-select {
1323
  padding: 6px 10px;
1324
- background: var(--glass-bg-light);
1325
- border: 1px solid var(--glass-border);
1326
  border-radius: var(--radius-sm);
1327
  color: var(--text-secondary);
1328
  font-family: var(--font-mono);
@@ -1333,8 +1483,7 @@ body {
1333
  }
1334
 
1335
  .option-select:hover, .option-select:focus {
1336
- border-color: var(--cyan-dim);
1337
- box-shadow: 0 0 10px var(--cyan-glow-subtle);
1338
  }
1339
 
1340
  .option-checkbox {
@@ -1345,14 +1494,14 @@ body {
1345
  font-size: 11px;
1346
  color: var(--text-muted);
1347
  padding: 6px 10px;
1348
- background: var(--glass-bg-light);
1349
- border: 1px solid var(--glass-border);
1350
  border-radius: var(--radius-sm);
1351
  transition: all var(--transition-fast);
1352
  }
1353
 
1354
  .option-checkbox:hover {
1355
- border-color: var(--glass-border-hover);
1356
  }
1357
 
1358
  .option-checkbox input[type="checkbox"] {
@@ -1360,7 +1509,7 @@ body {
1360
  -webkit-appearance: none;
1361
  width: 14px;
1362
  height: 14px;
1363
- background: var(--bg-tertiary);
1364
  border: 1px solid var(--border-default);
1365
  border-radius: 3px;
1366
  cursor: pointer;
@@ -1369,9 +1518,8 @@ body {
1369
  }
1370
 
1371
  .option-checkbox input[type="checkbox"]:checked {
1372
- background: var(--cyan);
1373
- border-color: var(--cyan);
1374
- box-shadow: 0 0 8px var(--cyan-glow);
1375
  }
1376
 
1377
  .option-checkbox input[type="checkbox"]:checked::after {
@@ -1381,14 +1529,14 @@ body {
1381
  left: 50%;
1382
  transform: translate(-50%, -50%);
1383
  font-size: 10px;
1384
- color: var(--bg-deep);
1385
  font-weight: bold;
1386
  }
1387
 
1388
  .image-upload-btn {
1389
  padding: 6px 12px;
1390
- background: var(--glass-bg-light);
1391
- border: 1px solid var(--glass-border);
1392
  border-radius: var(--radius-sm);
1393
  color: var(--text-muted);
1394
  font-size: 11px;
@@ -1400,8 +1548,8 @@ body {
1400
  }
1401
 
1402
  .image-upload-btn:hover {
1403
- border-color: var(--purple-dim);
1404
- color: var(--purple);
1405
  }
1406
 
1407
  #opt-image-input {
@@ -1420,10 +1568,10 @@ body {
1420
  align-items: center;
1421
  gap: 8px;
1422
  padding: 6px 10px;
1423
- background: var(--glass-bg-light);
1424
- border: 1px solid var(--purple-dim);
1425
  border-radius: var(--radius-sm);
1426
- animation: imgAppear 0.3s ease-out;
1427
  }
1428
 
1429
  @keyframes imgAppear {
@@ -1456,7 +1604,7 @@ body {
1456
  }
1457
 
1458
  .img-preview .remove:hover {
1459
- color: var(--red);
1460
  }
1461
 
1462
  .input-row {
@@ -1476,8 +1624,8 @@ body {
1476
  max-height: 150px;
1477
  padding: 14px 18px;
1478
  padding-right: 50px;
1479
- background: var(--bg-deep);
1480
- border: 1px solid var(--glass-border);
1481
  border-radius: var(--radius-lg);
1482
  color: var(--text-primary);
1483
  font-family: var(--font-sans);
@@ -1493,12 +1641,12 @@ body {
1493
  }
1494
 
1495
  .chat-input:focus {
1496
- border-color: var(--cyan);
1497
- box-shadow: 0 0 0 3px var(--cyan-glow-subtle), 0 0 30px var(--cyan-glow-subtle);
1498
  }
1499
 
1500
  .chat-input:not(:placeholder-shown) {
1501
- border-color: var(--glass-border-hover);
1502
  }
1503
 
1504
  .input-hint {
@@ -1526,58 +1674,39 @@ body {
1526
  cursor: pointer;
1527
  font-size: 18px;
1528
  transition: all var(--transition-base);
1529
- position: relative;
1530
- overflow: hidden;
1531
  }
1532
 
1533
  .btn-send {
1534
- background: linear-gradient(135deg, var(--cyan), var(--cyan-dim));
1535
- color: var(--bg-deep);
1536
- box-shadow: 0 4px 20px var(--cyan-glow);
1537
  }
1538
 
1539
  .btn-send:hover {
1540
- transform: translateY(-2px);
1541
- box-shadow: 0 6px 30px var(--cyan-glow), 0 0 40px var(--cyan-glow-subtle);
 
1542
  }
1543
 
1544
  .btn-send:active {
1545
  transform: translateY(0);
1546
  }
1547
 
1548
- .btn-send::after {
1549
- content: '';
1550
- position: absolute;
1551
- inset: 0;
1552
- background: linear-gradient(135deg, transparent, rgba(255,255,255,0.2), transparent);
1553
- transform: translateX(-100%);
1554
- transition: transform 0.5s;
1555
- }
1556
-
1557
- .btn-send:hover::after {
1558
- transform: translateX(100%);
1559
- }
1560
-
1561
  .btn-stop {
1562
- background: linear-gradient(135deg, var(--red), #cc4444);
1563
  color: white;
1564
- box-shadow: 0 4px 20px var(--red-glow);
1565
  display: none;
1566
  }
1567
 
1568
  .btn-stop:hover {
1569
- transform: translateY(-2px);
1570
- box-shadow: 0 6px 30px var(--red-glow);
1571
  }
1572
 
1573
  /* ═══ OUTPUT PANEL (Right Side) ═══ */
1574
  .output-panel {
1575
  width: 380px;
1576
  min-width: 380px;
1577
- background: var(--glass-bg);
1578
- backdrop-filter: blur(20px);
1579
- -webkit-backdrop-filter: blur(20px);
1580
- border-left: 1px solid var(--glass-border);
1581
  display: flex;
1582
  flex-direction: column;
1583
  overflow: hidden;
@@ -1585,23 +1714,12 @@ body {
1585
  z-index: var(--z-panel);
1586
  }
1587
 
1588
- .output-panel::before {
1589
- content: '';
1590
- position: absolute;
1591
- top: 0;
1592
- left: 0;
1593
- bottom: 0;
1594
- width: 1px;
1595
- background: linear-gradient(180deg, var(--purple-glow-subtle), transparent, var(--cyan-glow-subtle));
1596
- opacity: 0.5;
1597
- }
1598
-
1599
  .output-tabs {
1600
  display: flex;
1601
  padding: 8px;
1602
  gap: 4px;
1603
- border-bottom: 1px solid var(--glass-border);
1604
- background: var(--glass-bg-light);
1605
  }
1606
 
1607
  .output-tab {
@@ -1621,13 +1739,13 @@ body {
1621
 
1622
  .output-tab:hover {
1623
  color: var(--text-secondary);
1624
- background: var(--glass-bg);
1625
  }
1626
 
1627
  .output-tab.active {
1628
- background: var(--glass-bg);
1629
- color: var(--cyan);
1630
- box-shadow: 0 0 15px var(--cyan-glow-subtle);
1631
  }
1632
 
1633
  .tab-pane {
@@ -1646,9 +1764,10 @@ body {
1646
  height: 100%;
1647
  display: flex;
1648
  flex-direction: column;
1649
- background: var(--bg-deep);
1650
  border-radius: var(--radius-md);
1651
  overflow: hidden;
 
1652
  }
1653
 
1654
  .preview-placeholder {
@@ -1685,13 +1804,13 @@ body {
1685
  justify-content: flex-end;
1686
  padding: 8px;
1687
  background: var(--bg-tertiary);
1688
- border-top: 1px solid var(--border-default);
1689
  }
1690
 
1691
  .btn-fullscreen {
1692
  padding: 6px 12px;
1693
- background: var(--glass-bg);
1694
- border: 1px solid var(--glass-border);
1695
  border-radius: var(--radius-sm);
1696
  color: var(--text-muted);
1697
  font-size: 11px;
@@ -1701,8 +1820,8 @@ body {
1701
  }
1702
 
1703
  .btn-fullscreen:hover {
1704
- border-color: var(--cyan-dim);
1705
- color: var(--cyan);
1706
  }
1707
 
1708
  /* Code Pane */
@@ -1718,14 +1837,14 @@ body {
1718
  justify-content: space-between;
1719
  padding: 8px 12px;
1720
  background: var(--bg-tertiary);
1721
- border: 1px solid var(--border-default);
1722
  border-radius: var(--radius-md) var(--radius-md) 0 0;
1723
  }
1724
 
1725
  .code-tab-btn {
1726
  padding: 5px 10px;
1727
- background: var(--glass-bg);
1728
- border: 1px solid var(--glass-border);
1729
  border-radius: var(--radius-sm);
1730
  color: var(--text-muted);
1731
  font-size: 10px;
@@ -1735,14 +1854,14 @@ body {
1735
  }
1736
 
1737
  .code-tab-btn:hover {
1738
- border-color: var(--cyan-dim);
1739
- color: var(--cyan);
1740
  }
1741
 
1742
  .code-content {
1743
  flex: 1;
1744
- background: var(--bg-deep);
1745
- border: 1px solid var(--border-default);
1746
  border-top: none;
1747
  border-radius: 0 0 var(--radius-md) var(--radius-md);
1748
  padding: 14px;
@@ -1750,7 +1869,7 @@ body {
1750
  font-family: var(--font-mono);
1751
  font-size: 12px;
1752
  line-height: 1.7;
1753
- color: var(--text-secondary);
1754
  white-space: pre-wrap;
1755
  word-break: break-all;
1756
  }
@@ -1782,34 +1901,34 @@ body {
1782
  gap: 6px;
1783
  }
1784
 
1785
- .console-label.stdout { color: var(--green); }
1786
- .console-label.stderr { color: var(--red); }
1787
 
1788
  .console-output {
1789
  flex: 1;
1790
- background: var(--bg-deep);
1791
- border: 1px solid var(--border-default);
1792
  border-radius: var(--radius-sm);
1793
  padding: 10px;
1794
  overflow: auto;
1795
  font-family: var(--font-mono);
1796
  font-size: 11px;
1797
  line-height: 1.6;
1798
- color: var(--text-secondary);
1799
  white-space: pre-wrap;
1800
  word-break: break-all;
1801
  }
1802
 
1803
  /* ═══ STATUS BAR ═══ */
1804
  .status-bar {
1805
- height: 28px;
1806
- min-height: 28px;
1807
  display: flex;
1808
  align-items: center;
1809
  justify-content: space-between;
1810
  padding: 0 16px;
1811
- background: var(--bg-primary);
1812
- border-top: 1px solid var(--glass-border);
1813
  font-size: 11px;
1814
  font-family: var(--font-mono);
1815
  }
@@ -1817,7 +1936,7 @@ body {
1817
  .status-left, .status-right {
1818
  display: flex;
1819
  align-items: center;
1820
- gap: 16px;
1821
  }
1822
 
1823
  .status-item {
@@ -1835,10 +1954,10 @@ body {
1835
  }
1836
 
1837
  .status-idle { color: var(--text-muted); }
1838
- .status-working { color: var(--amber); }
1839
- .status-success { color: var(--green); }
1840
- .status-error { color: var(--red); }
1841
- .status-info { color: var(--cyan); }
1842
 
1843
  .status-working .indicator {
1844
  animation: statusPulse 1s ease-in-out infinite;
@@ -1853,8 +1972,8 @@ body {
1853
  .fullscreen-overlay {
1854
  position: fixed;
1855
  inset: 0;
1856
- background: rgba(5, 8, 16, 0.95);
1857
- backdrop-filter: blur(10px);
1858
  z-index: var(--z-modal);
1859
  display: none;
1860
  align-items: center;
@@ -1881,8 +2000,8 @@ body {
1881
  display: flex;
1882
  align-items: center;
1883
  justify-content: center;
1884
- background: var(--glass-bg);
1885
- border: 1px solid var(--glass-border);
1886
  border-radius: var(--radius-md);
1887
  color: var(--text-secondary);
1888
  font-size: 20px;
@@ -1891,17 +2010,17 @@ body {
1891
  }
1892
 
1893
  .fullscreen-close:hover {
1894
- border-color: var(--red);
1895
- color: var(--red);
1896
  }
1897
 
1898
  .fullscreen-iframe {
1899
  width: 90vw;
1900
  height: 90vh;
1901
- border: 1px solid var(--glass-border);
1902
  border-radius: var(--radius-lg);
1903
  background: white;
1904
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
1905
  }
1906
 
1907
  /* ═══ RESPONSIVE ADJUSTMENTS ═══ */
@@ -1912,8 +2031,12 @@ body {
1912
  }
1913
 
1914
  .sidebar {
1915
- width: 220px;
1916
- min-width: 220px;
 
 
 
 
1917
  }
1918
  }
1919
 
@@ -1922,17 +2045,28 @@ body {
1922
  display: none;
1923
  }
1924
 
 
 
 
 
 
 
 
1925
  .output-panel {
1926
  width: 250px;
1927
  min-width: 250px;
1928
  }
1929
- }
1930
-
1931
- @media (max-width: 600px) {
1932
  .header-center {
1933
  display: none;
1934
  }
1935
 
 
 
 
 
 
 
1936
  .status-indicators {
1937
  display: none;
1938
  }
@@ -1945,7 +2079,7 @@ body {
1945
  position: fixed;
1946
  right: 0;
1947
  top: var(--header-height);
1948
- bottom: 28px;
1949
  width: 100%;
1950
  min-width: 100%;
1951
  transform: translateX(100%);
@@ -1956,22 +2090,27 @@ body {
1956
  .output-panel.show {
1957
  transform: translateX(0);
1958
  }
 
 
 
 
 
 
 
 
 
1959
  }
1960
 
1961
  /* ═══ LOADING/SPINNER ANIMATIONS ═══ */
1962
  .spinner {
1963
  width: 20px;
1964
  height: 20px;
1965
- border: 2px solid var(--glass-border);
1966
- border-top-color: var(--cyan);
1967
  border-radius: 50%;
1968
  animation: spin 0.8s linear infinite;
1969
  }
1970
 
1971
- @keyframes spin {
1972
- to { transform: rotate(360deg); }
1973
- }
1974
-
1975
  .typing-indicator {
1976
  display: flex;
1977
  align-items: center;
@@ -1982,7 +2121,7 @@ body {
1982
  .typing-indicator span {
1983
  width: 6px;
1984
  height: 6px;
1985
- background: var(--cyan);
1986
  border-radius: 50%;
1987
  animation: typingBounce 1.4s ease-in-out infinite;
1988
  }
@@ -2010,46 +2149,49 @@ body {
2010
  .hidden { display: none !important; }
2011
  .visible { display: block !important; }
2012
 
2013
- /* Glow effects on hover for interactive elements */
2014
- .glow-hover {
2015
- transition: box-shadow var(--transition-fast);
2016
  }
2017
 
2018
- .glow-hover:hover {
2019
- box-shadow: 0 0 20px var(--cyan-glow-subtle);
 
 
2020
  }
2021
  </style>
2022
  </head>
2023
  <body>
2024
 
2025
- <!-- Animated Background -->
2026
- <div class="bg-canvas">
2027
- <div class="bg-gradient-mesh"></div>
2028
- <div class="particles-container" id="particles"></div>
2029
- <div class="grid-overlay"></div>
2030
- <div class="scanline"></div>
2031
- </div>
2032
-
2033
  <!-- Main App Container -->
2034
  <div class="app-container">
2035
 
2036
  <!-- Header -->
2037
  <header class="header">
2038
  <div class="header-left">
 
2039
  <div class="logo" onclick="newChat()">
2040
  <div class="logo-icon">⚑</div>
2041
  <div class="logo-text">
2042
  <span class="logo-title">SoniCoder</span>
2043
- <span class="logo-version">v2.0 AI Agent</span>
2044
  </div>
2045
  </div>
2046
  </div>
2047
 
2048
  <div class="header-center">
 
 
 
 
 
2049
  <div class="model-selector" onclick="toggleModelMenu()">
2050
  <span class="model-dot" id="model-dot"></span>
2051
  <span class="model-text" id="model-pill-text">Loading...</span>
2052
  <span style="font-size: 10px; color: var(--text-muted);">β–Ό</span>
 
 
 
2053
  </div>
2054
 
2055
  <div class="status-pill">
@@ -2061,6 +2203,7 @@ body {
2061
  <div class="header-right">
2062
  <button class="btn-icon" onclick="refreshWorkspace()" title="Refresh Workspace">↻</button>
2063
  <button class="btn-icon" onclick="newChat()" title="New Chat">+</button>
 
2064
  </div>
2065
  </header>
2066
 
@@ -2068,31 +2211,142 @@ body {
2068
  <main class="main-content">
2069
 
2070
  <!-- Sidebar -->
2071
- <aside class="sidebar">
2072
  <div class="sidebar-header">
2073
- <span class="sidebar-title">Workspace</span>
2074
- <div class="sidebar-actions">
2075
- <button class="btn-sidebar-action" onclick="refreshWorkspace()" title="Refresh">↻</button>
 
 
 
 
 
 
 
 
 
2076
  </div>
2077
  </div>
2078
 
2079
- <div class="sidebar-content">
2080
- <div class="file-tree" id="files-tree"></div>
2081
- <div class="file-viewer" id="file-viewer"></div>
 
 
 
 
 
 
 
2082
  </div>
2083
 
 
2084
  <div class="sidebar-section">
2085
- <div class="sidebar-section-title">πŸ”Œ MCP Servers</div>
 
 
2086
  <div class="sidebar-content" style="padding: 0 12px;">
2087
  <div id="mcp-content"></div>
2088
  </div>
2089
  </div>
 
 
 
 
 
 
 
 
 
 
 
2090
  </aside>
2091
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2092
  <!-- Chat Area -->
2093
  <section class="chat-area">
2094
  <div class="chat-messages" id="chat-messages">
2095
- <!-- Messages will be inserted here -->
 
 
 
 
 
 
 
 
2096
  </div>
2097
 
2098
  <!-- Input Area -->
@@ -2161,7 +2415,7 @@ body {
2161
  </section>
2162
 
2163
  <!-- Output Panel -->
2164
- <aside class="output-panel">
2165
  <div class="output-tabs">
2166
  <button class="output-tab active" data-tab="preview" onclick="switchTab('preview')">Preview</button>
2167
  <button class="output-tab" data-tab="code" onclick="switchTab('code')">Code</button>
@@ -2219,7 +2473,7 @@ body {
2219
  <span class="status-item">
2220
  <span id="header-model-name"></span>
2221
  </span>
2222
- <span class="status-item">Local Mode</span>
2223
  <span class="status-item">SoniCoder v2</span>
2224
  </div>
2225
  </footer>
@@ -2249,35 +2503,45 @@ var state = {
2249
  consoleStdout: '',
2250
  consoleStderr: '',
2251
  attachedImage: null,
2252
- activeTab: 'preview'
 
 
 
 
2253
  };
2254
 
2255
  // ═══ INITIALIZATION ═══
2256
 
2257
  document.addEventListener('DOMContentLoaded', function() {
2258
- initParticles();
2259
  loadConfig();
2260
  pollModelStatus();
2261
  loadMcpStatus();
2262
  refreshWorkspace();
2263
-
2264
- // Add welcome message
2265
- addMessage('system', 'Welcome to **SoniCoder v2** β€” Your AI Code Agent. What would you like to build today?');
2266
  });
2267
 
2268
- function initParticles() {
2269
- var container = document.getElementById('particles');
2270
- var particleCount = 30;
2271
-
2272
- for (var i = 0; i < particleCount; i++) {
2273
- var particle = document.createElement('div');
2274
- particle.className = 'particle';
2275
- particle.style.left = Math.random() * 100 + '%';
2276
- particle.style.width = (Math.random() * 3 + 1) + 'px';
2277
- particle.style.height = particle.style.width;
2278
- particle.style.animationDuration = (Math.random() * 20 + 15) + 's';
2279
- particle.style.animationDelay = (Math.random() * 20) + 's';
2280
- container.appendChild(particle);
 
 
 
 
 
 
 
 
 
2281
  }
2282
  }
2283
 
@@ -2324,10 +2588,39 @@ async function loadConfig() {
2324
  agentSel.appendChild(opt);
2325
  });
2326
 
 
 
 
2327
  renderExamples(config);
2328
  } catch(e) { console.error('Config load failed:', e); }
2329
  }
2330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2331
  function updateFrameworkOptions() {
2332
  if (!state.config) return;
2333
  var langSel = document.getElementById('opt-language');
@@ -2429,6 +2722,11 @@ async function switchModel(key) {
2429
  document.getElementById('model-dot').className = 'model-dot loading';
2430
  document.getElementById('model-pill-text').textContent = 'Switching...';
2431
  setStatus('status-working', 'SWITCHING MODEL...');
 
 
 
 
 
2432
  await fetch('/api/switch_model', {
2433
  method: 'POST', headers: {'Content-Type': 'application/json'},
2434
  body: JSON.stringify({ model_key: key }),
@@ -2437,6 +2735,79 @@ async function switchModel(key) {
2437
  } catch(e) { console.error(e); }
2438
  }
2439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2440
  async function refreshWorkspace() {
2441
  try {
2442
  var resp = await fetch('/api/workspace_tree?max_depth=4');
@@ -2455,7 +2826,7 @@ async function refreshWorkspace() {
2455
  if (!node) return '';
2456
  var name = escHtml(node.name || '');
2457
  if (node.type === 'dir') {
2458
- var html = '<div class="ws-dir"><span class="ws-dir-name">' + name + '</span>';
2459
  if (node.children && node.children.length > 0) {
2460
  html += '<div class="ws-children">';
2461
  for (var i = 0; i < node.children.length; i++) {
@@ -2467,7 +2838,7 @@ async function refreshWorkspace() {
2467
  return html;
2468
  } else {
2469
  var size = node.size ? ' (' + formatSize(node.size) + ')' : '';
2470
- return '<div class="ws-file" data-path="' + name + '" onclick="openWorkspaceFile(\'' + name.replace(/'/g, "\\'") + '\')"><span>' + name + size + '</span></div>';
2471
  }
2472
  }
2473
 
@@ -2571,20 +2942,64 @@ function renderExamples(config) {
2571
  examples = examples.slice(0, 6);
2572
  var row = document.getElementById('examples-row');
2573
  if (!row) return;
2574
- row.innerHTML = '<span class="examples-label">Try:</span>';
2575
  examples.forEach(function(ex) {
2576
- var chip = document.createElement('span');
2577
- chip.className = 'example-chip';
2578
- chip.textContent = ex;
2579
- chip.onclick = function() {
2580
  document.getElementById('chat-input').value = ex;
2581
  document.getElementById('chat-input').dispatchEvent(new Event('input'));
2582
  handleSend();
2583
  };
2584
- row.appendChild(chip);
2585
  });
2586
  }
2587
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2588
  // ═══ TABS ═══
2589
 
2590
  function switchTab(tab) {
@@ -2610,7 +3025,10 @@ function closeFullscreen() {
2610
  document.getElementById('fullscreen-iframe').src = 'about:blank';
2611
  }
2612
  document.addEventListener('keydown', function(e) {
2613
- if (e.key === 'Escape') closeFullscreen();
 
 
 
2614
  });
2615
 
2616
  // ═══ INPUT HANDLING ═══
@@ -2633,6 +3051,11 @@ function escHtml(t) { var d = document.createElement('div'); d.textContent = t;
2633
 
2634
  function addMessage(role, content, extra) {
2635
  extra = extra || {};
 
 
 
 
 
2636
  var container = document.getElementById('chat-messages');
2637
  var div = document.createElement('div');
2638
  div.className = 'msg msg-' + role;
@@ -2642,12 +3065,12 @@ function addMessage(role, content, extra) {
2642
  wrapper.className = 'msg-content-wrapper';
2643
 
2644
  var prefix = '';
2645
- if (role === 'user') prefix = '<span class="msg-prefix">β–Έ </span>';
2646
- else if (role === 'assistant') prefix = '<span class="msg-prefix">β—ˆ </span>';
2647
- else if (role === 'system') prefix = '<span class="msg-prefix">β—‰ </span>';
2648
 
2649
  var iterationHtml = extra.iteration ? '<div class="iteration-badge">Iteration ' + extra.iteration + '/' + extra.max_iterations + '</div>' : '';
2650
- wrapper.innerHTML = iterationHtml + prefix + '<span class="msg-content">' + renderMd(content) + '</span>';
2651
 
2652
  div.appendChild(wrapper);
2653
  container.appendChild(div);
@@ -2910,6 +3333,11 @@ function newChat() {
2910
  state.consoleStdout = '';
2911
  state.consoleStderr = '';
2912
  document.getElementById('chat-messages').innerHTML = '';
 
 
 
 
 
2913
  addMessage('system', 'New session started. What would you like to build?');
2914
  updateConsole();
2915
  setStatus('status-idle', 'IDLE');
@@ -2940,13 +3368,6 @@ function setStatus(className, text) {
2940
  el.className = 'status-item ' + className;
2941
  document.getElementById('status-text').textContent = text;
2942
  }
2943
-
2944
- // ═══ MODEL MENU TOGGLE (placeholder) ═══
2945
-
2946
- function toggleModelMenu() {
2947
- // Could implement dropdown menu here
2948
- console.log('Model menu toggle clicked');
2949
- }
2950
  </script>
2951
  </body>
2952
  </html>
 
7
  <meta name="description" content="AI-powered code agent with MCP support, multiple 1B models, and Gemini CLI patterns">
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
11
  <style>
12
  /* ═══════════════════════════════════════════════════════
13
+ SONICODER V2 - DEEPSEEK-STYLE CLEAN UI
14
+ Professional AI Code Agent Interface
15
  ═══════════════════════════════════════════════════════ */
16
 
17
+ /* ═══ CSS VARIABLES - LIGHT THEME ═══ */
18
  :root {
19
  /* Core Colors */
20
+ --bg-primary: #ffffff;
21
+ --bg-secondary: #f7f8fa;
22
+ --bg-tertiary: #f0f1f3;
23
+ --bg-elevated: #ffffff;
24
+ --bg-hover: #eef0f3;
25
 
26
+ /* Text Colors */
27
+ --text-primary: #1a1a1a;
28
+ --text-secondary: #666666;
29
+ --text-muted: #999999;
30
+ --text-accent: #4d6bfe;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ /* Accent Color (DeepSeek-like blue) */
33
+ --accent: #4d6bfe;
34
+ --accent-hover: #3b5ae6;
35
+ --accent-light: rgba(77, 107, 254, 0.08);
36
+ --accent-border: rgba(77, 107, 254, 0.2);
37
 
38
+ /* Border Colors */
39
+ --border-light: #e5e5e5;
40
+ --border-default: #d9d9d9;
41
+ --border-focus: var(--accent);
42
 
43
+ /* Status Colors */
44
+ --success: #22c55e;
45
+ --success-bg: rgba(34, 197, 94, 0.1);
46
+ --error: #ef4444;
47
+ --error-bg: rgba(239, 68, 68, 0.1);
48
+ --warning: #f59e0b;
49
+ --warning-bg: rgba(245, 158, 11, 0.1);
50
+ --info: #4d6bfe;
51
+ --info-bg: rgba(77, 107, 254, 0.1);
52
 
53
+ /* Message Bubble Colors */
54
+ --user-bubble: #4d6bfe;
55
+ --user-bubble-text: #ffffff;
56
+ --ai-bubble: #f0f0f0;
57
+ --ai-bubble-text: #1a1a1a;
58
 
59
  /* Typography */
60
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
61
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
62
 
63
  /* Spacing & Sizing */
64
  --radius-sm: 6px;
 
66
  --radius-lg: 16px;
67
  --radius-xl: 24px;
68
  --header-height: 56px;
69
+ --sidebar-width: 280px;
70
 
71
  /* Transitions */
72
+ --transition-fast: 150ms ease;
73
+ --transition-base: 200ms ease;
74
+ --transition-slow: 300ms ease;
75
+
76
+ /* Shadows */
77
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
78
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
79
+ --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
80
 
81
  /* Z-Index Scale */
82
  --z-base: 1;
 
86
  --z-toast: 2000;
87
  }
88
 
89
+ /* Dark Theme Variables */
90
+ [data-theme="dark"] {
91
+ --bg-primary: #1a1a1a;
92
+ --bg-secondary: #202020;
93
+ --bg-tertiary: #2a2a2a;
94
+ --bg-elevated: #262626;
95
+ --bg-hover: #333333;
96
+
97
+ --text-primary: #f5f5f5;
98
+ --text-secondary: #a0a0a0;
99
+ --text-muted: #707070;
100
+
101
+ --user-bubble: #4d6bfe;
102
+ --ai-bubble: #2a2a2a;
103
+ --ai-bubble-text: #f5f5f5;
104
+
105
+ --border-light: #333333;
106
+ --border-default: #404040;
107
+
108
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
109
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
110
+ --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
111
+ }
112
+
113
  /* ═══ RESET & BASE ═══ */
114
  *, *::before, *::after {
115
  box-sizing: border-box;
 
124
 
125
  body {
126
  height: 100%;
127
+ background: var(--bg-primary);
128
  color: var(--text-primary);
129
  font-family: var(--font-sans);
130
  line-height: 1.6;
131
  overflow: hidden;
 
132
  }
133
 
134
  ::selection {
135
+ background: var(--accent);
136
  color: white;
137
  }
138
 
 
148
  ::-webkit-scrollbar-thumb {
149
  background: var(--border-default);
150
  border-radius: 3px;
 
151
  }
152
 
153
  ::-webkit-scrollbar-thumb:hover {
154
+ background: var(--text-muted);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
157
  /* ═══ MAIN LAYOUT ═══ */
 
170
  display: flex;
171
  align-items: center;
172
  justify-content: space-between;
173
+ padding: 0 20px;
174
+ background: var(--bg-secondary);
175
+ border-bottom: 1px solid var(--border-light);
 
 
176
  position: relative;
177
  z-index: var(--z-panel);
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
180
  .header-left {
181
  display: flex;
182
  align-items: center;
 
188
  align-items: center;
189
  gap: 10px;
190
  cursor: pointer;
191
+ transition: opacity var(--transition-fast);
192
  }
193
 
194
  .logo:hover {
195
+ opacity: 0.85;
196
  }
197
 
198
  .logo-icon {
199
+ width: 32px;
200
+ height: 32px;
201
+ background: linear-gradient(135deg, var(--accent), #6366f1);
202
  border-radius: var(--radius-md);
203
  display: flex;
204
  align-items: center;
205
  justify-content: center;
206
+ font-size: 16px;
207
  font-weight: 700;
208
  color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
210
 
211
  .logo-text {
 
215
  }
216
 
217
  .logo-title {
218
+ font-size: 15px;
219
  font-weight: 700;
220
+ color: var(--text-primary);
221
+ letter-spacing: -0.3px;
 
 
 
222
  }
223
 
224
  .logo-version {
225
  font-size: 10px;
226
  color: var(--text-muted);
227
  text-transform: uppercase;
228
+ letter-spacing: 0.5px;
229
  font-weight: 500;
230
  }
231
 
 
233
  display: flex;
234
  align-items: center;
235
  gap: 12px;
236
+ flex: 1;
237
+ justify-content: center;
238
+ max-width: 600px;
239
+ margin: 0 20px;
240
+ }
241
+
242
+ .search-bar {
243
+ display: flex;
244
+ align-items: center;
245
+ gap: 8px;
246
+ width: 100%;
247
+ max-width: 400px;
248
+ padding: 8px 14px;
249
+ background: var(--bg-primary);
250
+ border: 1px solid var(--border-light);
251
+ border-radius: var(--radius-xl);
252
+ transition: all var(--transition-fast);
253
+ }
254
+
255
+ .search-bar:focus-within {
256
+ border-color: var(--accent);
257
+ box-shadow: 0 0 0 3px var(--accent-light);
258
+ }
259
+
260
+ .search-bar input {
261
+ flex: 1;
262
+ border: none;
263
+ outline: none;
264
+ background: transparent;
265
+ font-size: 13px;
266
+ color: var(--text-primary);
267
+ font-family: var(--font-sans);
268
+ }
269
+
270
+ .search-bar input::placeholder {
271
+ color: var(--text-muted);
272
+ }
273
+
274
+ .search-bar .search-icon {
275
+ color: var(--text-muted);
276
+ font-size: 14px;
277
  }
278
 
279
  .model-selector {
280
  display: flex;
281
  align-items: center;
282
  gap: 8px;
283
+ padding: 7px 14px;
284
+ background: var(--bg-primary);
285
+ border: 1px solid var(--border-light);
286
  border-radius: var(--radius-xl);
287
  cursor: pointer;
288
  transition: all var(--transition-fast);
289
+ white-space: nowrap;
290
  position: relative;
 
291
  }
292
 
293
  .model-selector:hover {
294
+ border-color: var(--accent);
295
+ background: var(--accent-light);
296
  }
297
 
298
  .model-dot {
 
304
  }
305
 
306
  .model-dot.ready {
307
+ background: var(--success);
 
 
308
  }
309
 
310
  .model-dot.loading {
311
+ background: var(--warning);
312
+ animation: spin 1s linear infinite;
313
  }
314
 
315
  .model-dot.error {
316
+ background: var(--error);
 
 
 
 
 
 
317
  }
318
 
319
+ @keyframes spin {
320
+ to { transform: rotate(360deg); }
 
321
  }
322
 
323
  .model-text {
324
+ font-size: 13px;
325
  font-weight: 500;
326
  color: var(--text-secondary);
327
+ }
328
+
329
+ .model-dropdown {
330
+ position: absolute;
331
+ top: calc(100% + 4px);
332
+ left: 0;
333
+ right: 0;
334
+ background: var(--bg-elevated);
335
+ border: 1px solid var(--border-light);
336
+ border-radius: var(--radius-md);
337
+ box-shadow: var(--shadow-lg);
338
+ z-index: var(--z-modal);
339
+ display: none;
340
  overflow: hidden;
341
+ }
342
+
343
+ .model-dropdown.show {
344
+ display: block;
345
+ }
346
+
347
+ .model-option {
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 10px;
351
+ padding: 10px 14px;
352
+ cursor: pointer;
353
+ transition: background var(--transition-fast);
354
+ }
355
+
356
+ .model-option:hover {
357
+ background: var(--bg-hover);
358
+ }
359
+
360
+ .model-option.active {
361
+ background: var(--accent-light);
362
+ color: var(--accent);
363
+ }
364
+
365
+ .model-option .model-name {
366
+ font-weight: 500;
367
+ font-size: 13px;
368
+ }
369
+
370
+ .model-option .model-desc {
371
+ font-size: 11px;
372
+ color: var(--text-muted);
373
  }
374
 
375
  .header-right {
 
388
  display: flex;
389
  align-items: center;
390
  gap: 6px;
391
+ padding: 6px 12px;
392
+ background: var(--bg-primary);
393
+ border: 1px solid var(--border-light);
394
  border-radius: var(--radius-xl);
395
+ font-size: 12px;
396
  font-weight: 500;
397
+ color: var(--text-secondary);
398
  transition: all var(--transition-fast);
399
  }
400
 
401
  .status-pill:hover {
402
+ border-color: var(--border-default);
403
  }
404
 
405
  .status-pill .dot {
 
411
 
412
  .status-pill .dot.connected,
413
  .status-pill .dot.ready {
414
+ background: var(--success);
 
415
  }
416
 
417
+ .status-pill .dot.disconnected,
418
+ .status-pill .dot.error {
419
+ background: var(--error);
420
  }
421
 
422
  .status-pill .dot.loading {
423
+ background: var(--warning);
424
+ animation: spin 1s linear infinite;
425
  }
426
 
427
  .btn-icon {
428
+ width: 36px;
429
+ height: 36px;
430
  display: flex;
431
  align-items: center;
432
  justify-content: center;
433
+ background: var(--bg-primary);
434
+ border: 1px solid var(--border-light);
435
  border-radius: var(--radius-md);
436
  color: var(--text-secondary);
437
  cursor: pointer;
438
  transition: all var(--transition-fast);
439
+ font-size: 15px;
440
  }
441
 
442
  .btn-icon:hover {
443
+ background: var(--bg-hover);
444
+ border-color: var(--border-default);
445
+ color: var(--text-primary);
 
 
446
  }
447
 
448
+ .user-avatar {
449
+ width: 32px;
450
+ height: 32px;
451
+ border-radius: 50%;
452
+ background: linear-gradient(135deg, var(--accent), #8b5cf6);
453
+ display: flex;
454
+ align-items: center;
455
+ justify-content: center;
456
+ color: white;
457
+ font-size: 13px;
458
+ font-weight: 600;
459
+ cursor: pointer;
460
+ transition: transform var(--transition-fast);
461
+ }
462
+
463
+ .user-avatar:hover {
464
+ transform: scale(1.05);
465
  }
466
 
467
  /* ═══ MAIN CONTENT AREA ═══ */
 
476
  .sidebar {
477
  width: var(--sidebar-width);
478
  min-width: var(--sidebar-width);
479
+ background: var(--bg-secondary);
480
+ border-right: 1px solid var(--border-light);
 
 
481
  display: flex;
482
  flex-direction: column;
483
  overflow: hidden;
 
485
  z-index: var(--z-panel);
486
  }
487
 
 
 
 
 
 
 
 
 
 
 
 
488
  .sidebar-header {
489
  padding: 16px;
490
+ border-bottom: 1px solid var(--border-light);
491
+ }
492
+
493
+ .new-chat-btn {
494
+ width: 100%;
495
  display: flex;
496
  align-items: center;
497
+ justify-content: center;
498
+ gap: 8px;
499
+ padding: 12px 20px;
500
+ background: var(--accent);
501
+ color: white;
502
+ border: none;
503
+ border-radius: var(--radius-md);
504
+ font-size: 14px;
505
+ font-weight: 600;
506
+ font-family: var(--font-sans);
507
+ cursor: pointer;
508
+ transition: all var(--transition-fast);
509
+ }
510
+
511
+ .new-chat-btn:hover {
512
+ background: var(--accent-hover);
513
+ transform: translateY(-1px);
514
+ box-shadow: var(--shadow-md);
515
+ }
516
+
517
+ .new-chat-btn:active {
518
+ transform: translateY(0);
519
+ }
520
+
521
+ .sidebar-section {
522
+ padding: 16px;
523
+ border-bottom: 1px solid var(--border-light);
524
  }
525
 
526
+ .sidebar-section-title {
527
  font-size: 11px;
528
  font-weight: 600;
529
  text-transform: uppercase;
530
+ letter-spacing: 0.8px;
531
  color: var(--text-muted);
532
+ padding: 0 4px 10px;
533
+ display: flex;
534
+ align-items: center;
535
+ justify-content: space-between;
536
  }
537
 
538
+ .chat-history-list {
539
  display: flex;
540
+ flex-direction: column;
541
+ gap: 2px;
542
+ max-height: 200px;
543
+ overflow-y: auto;
544
  }
545
 
546
+ .chat-history-item {
 
 
547
  display: flex;
548
  align-items: center;
549
+ gap: 10px;
550
+ padding: 10px 12px;
 
551
  border-radius: var(--radius-sm);
 
552
  cursor: pointer;
553
  transition: all var(--transition-fast);
554
+ color: var(--text-secondary);
555
+ font-size: 13px;
556
+ }
557
+
558
+ .chat-history-item:hover {
559
+ background: var(--bg-hover);
560
+ color: var(--text-primary);
561
+ }
562
+
563
+ .chat-history-item.active {
564
+ background: var(--accent-light);
565
+ color: var(--accent);
566
+ }
567
+
568
+ .chat-history-item .chat-icon {
569
+ font-size: 14px;
570
+ opacity: 0.7;
571
+ }
572
+
573
+ .chat-history-item .chat-title {
574
+ flex: 1;
575
+ overflow: hidden;
576
+ text-overflow: ellipsis;
577
+ white-space: nowrap;
578
  }
579
 
580
+ .chat-history-empty {
581
+ padding: 20px 12px;
582
+ text-align: center;
583
+ color: var(--text-muted);
584
+ font-size: 12px;
585
  }
586
 
587
  .sidebar-content {
 
613
  }
614
 
615
  .ws-dir-name:hover {
616
+ background: var(--bg-hover);
617
+ color: var(--text-primary);
618
  }
619
 
620
+ .ws-dir-name .dir-icon {
621
+ font-size: 12px;
622
+ color: var(--text-muted);
 
623
  }
624
 
625
  .ws-children {
626
  margin-left: 16px;
627
  padding-left: 12px;
628
+ border-left: 1px solid var(--border-light);
629
  }
630
 
631
  .ws-file {
 
645
  }
646
 
647
  .ws-file > span:hover {
648
+ background: var(--bg-hover);
649
+ color: var(--accent);
650
  padding-left: 12px;
651
  }
652
 
653
+ .ws-file > span .file-icon {
 
654
  font-size: 11px;
655
+ color: var(--text-muted);
656
  }
657
 
658
  .ws-empty {
 
668
  align-items: center;
669
  gap: 12px;
670
  padding: 12px;
671
+ background: var(--bg-tertiary);
672
+ border-bottom: 1px solid var(--border-light);
673
  }
674
 
675
  .file-viewer-header button {
676
  padding: 6px 12px;
677
+ background: var(--bg-primary);
678
+ border: 1px solid var(--border-light);
679
  border-radius: var(--radius-sm);
680
  color: var(--text-secondary);
681
  cursor: pointer;
 
685
  }
686
 
687
  .file-viewer-header button:hover {
688
+ border-color: var(--accent);
689
+ color: var(--accent);
690
  }
691
 
692
  .file-viewer-header span {
 
708
  word-break: break-all;
709
  }
710
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
  /* MCP Section */
712
  .mcp-server {
713
  padding: 10px 12px;
714
+ background: var(--bg-primary);
715
+ border: 1px solid var(--border-light);
716
  border-radius: var(--radius-md);
717
  margin-bottom: 8px;
718
  transition: all var(--transition-fast);
719
  }
720
 
721
  .mcp-server:hover {
722
+ border-color: var(--border-default);
723
  }
724
 
725
  .mcp-server-header {
 
737
  }
738
 
739
  .mcp-server-dot.connected {
740
+ background: var(--success);
 
741
  }
742
 
743
  .mcp-server-dot.disconnected {
744
+ background: var(--error);
745
  }
746
 
747
  .mcp-server-name {
 
761
  }
762
 
763
  .tool-badge.success {
764
+ background: var(--success-bg);
765
+ color: var(--success);
766
  }
767
 
768
  .tool-badge.error {
769
+ background: var(--error-bg);
770
+ color: var(--error);
771
  }
772
 
773
  .tool-badge.running {
774
+ background: var(--warning-bg);
775
+ color: var(--warning);
 
 
 
 
 
 
776
  }
777
 
778
  .mcp-tools {
 
797
  line-height: 1.6;
798
  }
799
 
800
+ /* Sidebar Footer / Settings */
801
+ .sidebar-footer {
802
+ padding: 12px 16px;
803
+ border-top: 1px solid var(--border-light);
804
+ background: var(--bg-secondary);
805
+ }
806
+
807
+ .sidebar-footer-actions {
808
+ display: flex;
809
+ align-items: center;
810
+ justify-content: space-between;
811
+ }
812
+
813
+ .storage-mode {
814
+ display: flex;
815
+ align-items: center;
816
+ gap: 6px;
817
+ font-size: 11px;
818
+ color: var(--text-muted);
819
+ padding: 4px 8px;
820
+ background: var(--bg-primary);
821
+ border-radius: var(--radius-sm);
822
+ }
823
+
824
+ .storage-mode .storage-dot {
825
+ width: 6px;
826
+ height: 6px;
827
+ border-radius: 50%;
828
+ background: var(--success);
829
+ }
830
+
831
+ .storage-mode.hf-hub .storage-dot {
832
+ background: var(--accent);
833
+ }
834
+
835
+ .storage-mode.bucket .storage-dot {
836
+ background: var(--warning);
837
+ }
838
+
839
+ .settings-btn {
840
+ display: flex;
841
+ align-items: center;
842
+ justify-content: center;
843
+ width: 32px;
844
+ height: 32px;
845
+ background: var(--bg-primary);
846
+ border: 1px solid var(--border-light);
847
+ border-radius: var(--radius-sm);
848
+ color: var(--text-muted);
849
+ cursor: pointer;
850
+ transition: all var(--transition-fast);
851
+ font-size: 14px;
852
+ }
853
+
854
+ .settings-btn:hover {
855
+ border-color: var(--accent);
856
+ color: var(--accent);
857
+ }
858
+
859
+ /* Settings Panel */
860
+ .settings-panel {
861
+ position: fixed;
862
+ bottom: 60px;
863
+ left: 280px;
864
+ width: 320px;
865
+ background: var(--bg-elevated);
866
+ border: 1px solid var(--border-light);
867
+ border-radius: var(--radius-lg);
868
+ box-shadow: var(--shadow-lg);
869
+ z-index: var(--z-modal);
870
+ display: none;
871
+ overflow: hidden;
872
+ }
873
+
874
+ .settings-panel.show {
875
+ display: block;
876
+ animation: slideUp 0.2s ease-out;
877
+ }
878
+
879
+ @keyframes slideUp {
880
+ from {
881
+ opacity: 0;
882
+ transform: translateY(10px);
883
+ }
884
+ to {
885
+ opacity: 1;
886
+ transform: translateY(0);
887
+ }
888
+ }
889
+
890
+ .settings-panel-header {
891
+ display: flex;
892
+ align-items: center;
893
+ justify-content: space-between;
894
+ padding: 14px 16px;
895
+ border-bottom: 1px solid var(--border-light);
896
+ }
897
+
898
+ .settings-panel-title {
899
+ font-size: 14px;
900
+ font-weight: 600;
901
+ color: var(--text-primary);
902
+ }
903
+
904
+ .settings-close-btn {
905
+ width: 28px;
906
+ height: 28px;
907
+ display: flex;
908
+ align-items: center;
909
+ justify-content: center;
910
+ background: transparent;
911
+ border: none;
912
+ border-radius: var(--radius-sm);
913
+ color: var(--text-muted);
914
+ cursor: pointer;
915
+ font-size: 16px;
916
+ transition: all var(--transition-fast);
917
+ }
918
+
919
+ .settings-close-btn:hover {
920
+ background: var(--bg-hover);
921
+ color: var(--text-primary);
922
+ }
923
+
924
+ .settings-panel-body {
925
+ padding: 16px;
926
+ display: flex;
927
+ flex-direction: column;
928
+ gap: 16px;
929
+ max-height: 400px;
930
+ overflow-y: auto;
931
+ }
932
+
933
+ .setting-group {
934
+ display: flex;
935
+ flex-direction: column;
936
+ gap: 8px;
937
+ }
938
+
939
+ .setting-label {
940
+ font-size: 12px;
941
+ font-weight: 500;
942
+ color: var(--text-secondary);
943
+ display: flex;
944
+ align-items: center;
945
+ justify-content: space-between;
946
+ }
947
+
948
+ .setting-value {
949
+ font-size: 11px;
950
+ color: var(--text-muted);
951
+ font-family: var(--font-mono);
952
+ }
953
+
954
+ .setting-select {
955
+ width: 100%;
956
+ padding: 10px 12px;
957
+ background: var(--bg-primary);
958
+ border: 1px solid var(--border-light);
959
+ border-radius: var(--radius-sm);
960
+ color: var(--text-primary);
961
+ font-size: 13px;
962
+ font-family: var(--font-sans);
963
+ cursor: pointer;
964
+ transition: all var(--transition-fast);
965
+ appearance: none;
966
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
967
+ background-repeat: no-repeat;
968
+ background-position: right 12px center;
969
+ padding-right: 32px;
970
+ }
971
+
972
+ .setting-select:focus {
973
+ border-color: var(--accent);
974
+ box-shadow: 0 0 0 3px var(--accent-light);
975
+ outline: none;
976
+ }
977
+
978
+ .setting-slider {
979
+ width: 100%;
980
+ height: 6px;
981
+ border-radius: 3px;
982
+ background: var(--bg-tertiary);
983
+ appearance: none;
984
+ cursor: pointer;
985
+ }
986
+
987
+ .setting-slider::-webkit-slider-thumb {
988
+ appearance: none;
989
+ width: 18px;
990
+ height: 18px;
991
+ border-radius: 50%;
992
+ background: var(--accent);
993
+ cursor: pointer;
994
+ transition: transform var(--transition-fast);
995
+ }
996
+
997
+ .setting-slider::-webkit-slider-thumb:hover {
998
+ transform: scale(1.1);
999
+ }
1000
+
1001
+ .setting-row {
1002
+ display: flex;
1003
+ align-items: center;
1004
+ gap: 12px;
1005
+ }
1006
+
1007
+ .setting-toggle {
1008
+ position: relative;
1009
+ width: 44px;
1010
+ height: 24px;
1011
+ background: var(--bg-tertiary);
1012
+ border-radius: 12px;
1013
+ cursor: pointer;
1014
+ transition: background var(--transition-fast);
1015
+ }
1016
+
1017
+ .setting-toggle.active {
1018
+ background: var(--accent);
1019
+ }
1020
+
1021
+ .setting-toggle::after {
1022
+ content: '';
1023
+ position: absolute;
1024
+ top: 2px;
1025
+ left: 2px;
1026
+ width: 20px;
1027
+ height: 20px;
1028
+ background: white;
1029
+ border-radius: 50%;
1030
+ transition: transform var(--transition-fast);
1031
+ box-shadow: var(--shadow-sm);
1032
+ }
1033
+
1034
+ .setting-toggle.active::after {
1035
+ transform: translateX(20px);
1036
+ }
1037
+
1038
+ .export-buttons {
1039
+ display: flex;
1040
+ gap: 8px;
1041
+ }
1042
+
1043
+ .export-btn {
1044
+ flex: 1;
1045
+ padding: 10px 12px;
1046
+ background: var(--bg-primary);
1047
+ border: 1px solid var(--border-light);
1048
+ border-radius: var(--radius-sm);
1049
+ color: var(--text-secondary);
1050
+ font-size: 12px;
1051
+ font-weight: 500;
1052
+ cursor: pointer;
1053
+ transition: all var(--transition-fast);
1054
+ display: flex;
1055
+ align-items: center;
1056
+ justify-content: center;
1057
+ gap: 6px;
1058
+ }
1059
+
1060
+ .export-btn:hover {
1061
+ border-color: var(--accent);
1062
+ color: var(--accent);
1063
+ background: var(--accent-light);
1064
+ }
1065
+
1066
  /* ═══ CHAT AREA ═══ */
1067
  .chat-area {
1068
  flex: 1;
 
1070
  flex-direction: column;
1071
  overflow: hidden;
1072
  position: relative;
1073
+ background: var(--bg-primary);
1074
  }
1075
 
1076
  .chat-messages {
 
1086
 
1087
  /* Welcome Banner */
1088
  .welcome-banner {
1089
+ max-width: 680px;
1090
+ margin: 60px auto;
1091
  text-align: center;
1092
+ padding: 48px 40px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1093
  }
1094
 
1095
+ .welcome-icon {
1096
+ font-size: 56px;
1097
+ margin-bottom: 20px;
1098
+ display: block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1099
  }
1100
 
1101
+ .welcome-title {
1102
+ font-size: 28px;
1103
+ font-weight: 700;
1104
+ color: var(--text-primary);
1105
+ margin-bottom: 12px;
1106
+ letter-spacing: -0.5px;
1107
  }
1108
 
1109
+ .welcome-subtitle {
1110
+ font-size: 16px;
1111
  color: var(--text-secondary);
1112
+ margin-bottom: 32px;
1113
+ line-height: 1.6;
 
 
 
 
 
 
 
 
1114
  }
1115
 
1116
+ .examples-grid {
1117
+ display: grid;
1118
+ grid-template-columns: repeat(2, 1fr);
1119
+ gap: 10px;
1120
+ max-width: 520px;
1121
+ margin: 0 auto;
1122
  }
1123
 
1124
+ .example-card {
1125
+ padding: 14px 18px;
1126
+ background: var(--bg-secondary);
1127
+ border: 1px solid var(--border-light);
1128
+ border-radius: var(--radius-md);
1129
+ font-size: 13px;
1130
  color: var(--text-secondary);
1131
  cursor: pointer;
1132
  transition: all var(--transition-fast);
1133
+ text-align: left;
 
 
 
 
 
 
 
 
 
 
1134
  }
1135
 
1136
+ .example-card:hover {
1137
+ border-color: var(--accent);
1138
+ color: var(--accent);
1139
+ background: var(--accent-light);
1140
  transform: translateY(-2px);
1141
+ box-shadow: var(--shadow-md);
 
 
 
 
 
 
 
 
 
1142
  }
1143
 
1144
  /* Message Styles */
1145
  .msg {
1146
+ margin-bottom: 24px;
1147
+ animation: msgSlideIn 0.25s ease-out;
1148
  position: relative;
1149
  }
1150
 
1151
  @keyframes msgSlideIn {
1152
  from {
1153
  opacity: 0;
1154
+ transform: translateY(8px);
1155
  }
1156
  to {
1157
  opacity: 1;
 
1166
 
1167
  .msg-user .msg-content-wrapper {
1168
  max-width: 75%;
1169
+ background: var(--user-bubble);
1170
+ color: var(--user-bubble-text);
1171
  border-radius: var(--radius-lg) var(--radius-lg) 4px var(--radius-lg);
1172
  padding: 14px 18px;
1173
  position: relative;
1174
  }
1175
 
 
 
 
 
 
 
 
 
 
 
 
1176
  .msg-assistant {
1177
  display: flex;
1178
  justify-content: flex-start;
 
1180
 
1181
  .msg-assistant .msg-content-wrapper {
1182
  max-width: 85%;
1183
+ background: var(--ai-bubble);
1184
+ color: var(--ai-bubble-text);
 
 
1185
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) 4px;
1186
  padding: 14px 18px;
1187
  position: relative;
 
1194
 
1195
  .msg-system .msg-content-wrapper {
1196
  max-width: 80%;
1197
+ background: var(--bg-secondary);
1198
+ border: 1px dashed var(--border-default);
1199
  border-radius: var(--radius-md);
1200
  padding: 12px 20px;
1201
  text-align: center;
1202
+ color: var(--text-secondary);
1203
  }
1204
 
1205
  .msg-prefix {
 
1208
  }
1209
 
1210
  .msg-user .msg-prefix {
1211
+ color: rgba(255,255,255,0.8);
1212
  }
1213
 
1214
  .msg-assistant .msg-prefix {
1215
+ color: var(--accent);
1216
  }
1217
 
1218
  .msg-system .msg-prefix {
1219
+ color: var(--warning);
1220
  }
1221
 
1222
  .msg-content {
1223
+ color: inherit;
1224
  line-height: 1.7;
1225
  word-wrap: break-word;
1226
  }
 
1234
  align-items: center;
1235
  gap: 6px;
1236
  padding: 4px 10px;
1237
+ background: var(--info-bg);
1238
+ border: 1px solid var(--accent-border);
1239
  border-radius: var(--radius-sm);
1240
+ font-size: 11px;
1241
  font-weight: 600;
1242
+ color: var(--accent);
 
 
1243
  margin-bottom: 10px;
 
 
 
 
 
 
1244
  }
1245
 
1246
  /* Code Block Styles */
1247
  .code-block-wrap {
1248
  margin: 12px 0;
1249
+ background: #1e1e1e;
1250
  border: 1px solid var(--border-default);
1251
  border-radius: var(--radius-md);
1252
  overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
1253
  }
1254
 
1255
  .code-block-header {
1256
  display: flex;
1257
  align-items: center;
1258
  justify-content: space-between;
1259
+ padding: 8px 14px;
1260
+ background: #2d2d2d;
1261
+ border-bottom: 1px solid #3d3d3d;
1262
  }
1263
 
1264
  .code-lang {
1265
  font-size: 11px;
1266
  font-weight: 500;
1267
+ color: #9ca3af;
1268
  text-transform: uppercase;
1269
  letter-spacing: 0.5px;
1270
  font-family: var(--font-mono);
 
1272
 
1273
  .btn-copy {
1274
  padding: 4px 10px;
1275
+ background: transparent;
1276
+ border: 1px solid #4a4a4a;
1277
+ border-radius: 4px;
1278
+ color: #9ca3af;
1279
  font-size: 11px;
1280
  cursor: pointer;
1281
  font-family: var(--font-mono);
 
1283
  }
1284
 
1285
  .btn-copy:hover {
1286
+ border-color: var(--accent);
1287
+ color: var(--accent);
 
1288
  }
1289
 
1290
  .btn-copy.copied {
1291
+ background: var(--success-bg);
1292
+ border-color: var(--success);
1293
+ color: var(--success);
1294
  }
1295
 
1296
  .code-block-wrap pre {
 
1303
  font-family: var(--font-mono);
1304
  font-size: 12px;
1305
  line-height: 1.7;
1306
+ color: #e0e0e0;
 
1307
  }
1308
 
1309
  /* Inline code */
1310
  .msg-content code:not([id]) {
1311
  padding: 2px 6px;
1312
+ background: var(--bg-tertiary);
1313
+ border: 1px solid var(--border-light);
1314
  border-radius: 4px;
1315
  font-family: var(--font-mono);
1316
  font-size: 12px;
1317
+ color: var(--accent);
1318
  }
1319
 
1320
  /* Headings in messages */
 
1324
  color: var(--text-primary);
1325
  }
1326
 
1327
+ .msg-content h1 { font-size: 18px; }
1328
+ .msg-content h2 { font-size: 16px; }
1329
  .msg-content h3 { font-size: 14px; }
1330
 
1331
  .msg-content strong {
 
1334
  }
1335
 
1336
  .msg-content em {
1337
+ color: var(--accent);
1338
  font-style: normal;
1339
  }
1340
 
1341
  .msg-content li {
1342
  margin-left: 20px;
1343
  margin-bottom: 4px;
1344
+ list-style: disc;
 
1345
  }
1346
 
1347
+ .msg-content ul, .msg-content ol {
1348
+ margin: 8px 0;
1349
+ padding-left: 20px;
 
 
1350
  }
1351
 
1352
  /* Streaming Cursor */
1353
  .streaming-cursor {
1354
  display: inline-block;
1355
  width: 8px;
1356
+ height: 18px;
1357
+ background: var(--accent);
1358
  margin-left: 2px;
1359
  vertical-align: text-bottom;
1360
  animation: cursorBlink 1s step-end infinite;
 
1369
  /* Tool Call Block */
1370
  .tool-block {
1371
  margin: 12px 0;
1372
+ background: var(--bg-secondary);
1373
+ border: 1px solid var(--border-light);
1374
  border-radius: var(--radius-md);
1375
  overflow: hidden;
1376
+ animation: toolSlideIn 0.25s ease-out;
1377
  }
1378
 
1379
  @keyframes toolSlideIn {
1380
  from {
1381
  opacity: 0;
1382
+ transform: translateX(-8px);
1383
  }
1384
  to {
1385
  opacity: 1;
 
1393
  gap: 10px;
1394
  padding: 12px 14px;
1395
  background: var(--bg-tertiary);
1396
+ border-bottom: 1px solid var(--border-light);
1397
  cursor: pointer;
1398
  transition: background var(--transition-fast);
1399
  }
1400
 
1401
  .tool-header:hover {
1402
+ background: var(--bg-hover);
1403
  }
1404
 
1405
  .tool-icon {
1406
+ font-size: 14px;
1407
  }
1408
 
1409
  .tool-name {
 
1421
  color: var(--text-muted);
1422
  white-space: pre-wrap;
1423
  word-break: break-all;
1424
+ border-bottom: 1px solid var(--border-light);
1425
+ background: var(--bg-primary);
1426
  }
1427
 
1428
  .tool-result {
 
1437
  }
1438
 
1439
  .tool-result.error-output {
1440
+ color: var(--error);
1441
  }
1442
 
1443
  /* ═══ INPUT AREA ═══ */
1444
  .input-area {
1445
+ padding: 16px 24px 20px;
1446
+ background: var(--bg-primary);
1447
+ border-top: 1px solid var(--border-light);
 
 
 
 
 
 
 
 
 
 
 
 
 
1448
  }
1449
 
1450
  .options-bar {
1451
  display: flex;
1452
  flex-wrap: wrap;
1453
+ gap: 10px;
1454
  margin-bottom: 12px;
1455
  align-items: center;
1456
  }
 
1462
  }
1463
 
1464
  .option-group label {
1465
+ font-size: 11px;
1466
  font-weight: 500;
1467
  text-transform: uppercase;
1468
  letter-spacing: 0.5px;
 
1471
 
1472
  .option-select {
1473
  padding: 6px 10px;
1474
+ background: var(--bg-secondary);
1475
+ border: 1px solid var(--border-light);
1476
  border-radius: var(--radius-sm);
1477
  color: var(--text-secondary);
1478
  font-family: var(--font-mono);
 
1483
  }
1484
 
1485
  .option-select:hover, .option-select:focus {
1486
+ border-color: var(--accent);
 
1487
  }
1488
 
1489
  .option-checkbox {
 
1494
  font-size: 11px;
1495
  color: var(--text-muted);
1496
  padding: 6px 10px;
1497
+ background: var(--bg-secondary);
1498
+ border: 1px solid var(--border-light);
1499
  border-radius: var(--radius-sm);
1500
  transition: all var(--transition-fast);
1501
  }
1502
 
1503
  .option-checkbox:hover {
1504
+ border-color: var(--border-default);
1505
  }
1506
 
1507
  .option-checkbox input[type="checkbox"] {
 
1509
  -webkit-appearance: none;
1510
  width: 14px;
1511
  height: 14px;
1512
+ background: var(--bg-primary);
1513
  border: 1px solid var(--border-default);
1514
  border-radius: 3px;
1515
  cursor: pointer;
 
1518
  }
1519
 
1520
  .option-checkbox input[type="checkbox"]:checked {
1521
+ background: var(--accent);
1522
+ border-color: var(--accent);
 
1523
  }
1524
 
1525
  .option-checkbox input[type="checkbox"]:checked::after {
 
1529
  left: 50%;
1530
  transform: translate(-50%, -50%);
1531
  font-size: 10px;
1532
+ color: white;
1533
  font-weight: bold;
1534
  }
1535
 
1536
  .image-upload-btn {
1537
  padding: 6px 12px;
1538
+ background: var(--bg-secondary);
1539
+ border: 1px solid var(--border-light);
1540
  border-radius: var(--radius-sm);
1541
  color: var(--text-muted);
1542
  font-size: 11px;
 
1548
  }
1549
 
1550
  .image-upload-btn:hover {
1551
+ border-color: var(--accent);
1552
+ color: var(--accent);
1553
  }
1554
 
1555
  #opt-image-input {
 
1568
  align-items: center;
1569
  gap: 8px;
1570
  padding: 6px 10px;
1571
+ background: var(--bg-secondary);
1572
+ border: 1px solid var(--border-default);
1573
  border-radius: var(--radius-sm);
1574
+ animation: imgAppear 0.2s ease-out;
1575
  }
1576
 
1577
  @keyframes imgAppear {
 
1604
  }
1605
 
1606
  .img-preview .remove:hover {
1607
+ color: var(--error);
1608
  }
1609
 
1610
  .input-row {
 
1624
  max-height: 150px;
1625
  padding: 14px 18px;
1626
  padding-right: 50px;
1627
+ background: var(--bg-secondary);
1628
+ border: 1px solid var(--border-light);
1629
  border-radius: var(--radius-lg);
1630
  color: var(--text-primary);
1631
  font-family: var(--font-sans);
 
1641
  }
1642
 
1643
  .chat-input:focus {
1644
+ border-color: var(--accent);
1645
+ box-shadow: 0 0 0 3px var(--accent-light);
1646
  }
1647
 
1648
  .chat-input:not(:placeholder-shown) {
1649
+ border-color: var(--border-default);
1650
  }
1651
 
1652
  .input-hint {
 
1674
  cursor: pointer;
1675
  font-size: 18px;
1676
  transition: all var(--transition-base);
 
 
1677
  }
1678
 
1679
  .btn-send {
1680
+ background: var(--accent);
1681
+ color: white;
 
1682
  }
1683
 
1684
  .btn-send:hover {
1685
+ background: var(--accent-hover);
1686
+ transform: translateY(-1px);
1687
+ box-shadow: var(--shadow-md);
1688
  }
1689
 
1690
  .btn-send:active {
1691
  transform: translateY(0);
1692
  }
1693
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1694
  .btn-stop {
1695
+ background: var(--error);
1696
  color: white;
 
1697
  display: none;
1698
  }
1699
 
1700
  .btn-stop:hover {
1701
+ background: #dc2626;
 
1702
  }
1703
 
1704
  /* ═══ OUTPUT PANEL (Right Side) ═══ */
1705
  .output-panel {
1706
  width: 380px;
1707
  min-width: 380px;
1708
+ background: var(--bg-secondary);
1709
+ border-left: 1px solid var(--border-light);
 
 
1710
  display: flex;
1711
  flex-direction: column;
1712
  overflow: hidden;
 
1714
  z-index: var(--z-panel);
1715
  }
1716
 
 
 
 
 
 
 
 
 
 
 
 
1717
  .output-tabs {
1718
  display: flex;
1719
  padding: 8px;
1720
  gap: 4px;
1721
+ border-bottom: 1px solid var(--border-light);
1722
+ background: var(--bg-secondary);
1723
  }
1724
 
1725
  .output-tab {
 
1739
 
1740
  .output-tab:hover {
1741
  color: var(--text-secondary);
1742
+ background: var(--bg-hover);
1743
  }
1744
 
1745
  .output-tab.active {
1746
+ background: var(--bg-primary);
1747
+ color: var(--accent);
1748
+ box-shadow: var(--shadow-sm);
1749
  }
1750
 
1751
  .tab-pane {
 
1764
  height: 100%;
1765
  display: flex;
1766
  flex-direction: column;
1767
+ background: var(--bg-primary);
1768
  border-radius: var(--radius-md);
1769
  overflow: hidden;
1770
+ border: 1px solid var(--border-light);
1771
  }
1772
 
1773
  .preview-placeholder {
 
1804
  justify-content: flex-end;
1805
  padding: 8px;
1806
  background: var(--bg-tertiary);
1807
+ border-top: 1px solid var(--border-light);
1808
  }
1809
 
1810
  .btn-fullscreen {
1811
  padding: 6px 12px;
1812
+ background: var(--bg-primary);
1813
+ border: 1px solid var(--border-light);
1814
  border-radius: var(--radius-sm);
1815
  color: var(--text-muted);
1816
  font-size: 11px;
 
1820
  }
1821
 
1822
  .btn-fullscreen:hover {
1823
+ border-color: var(--accent);
1824
+ color: var(--accent);
1825
  }
1826
 
1827
  /* Code Pane */
 
1837
  justify-content: space-between;
1838
  padding: 8px 12px;
1839
  background: var(--bg-tertiary);
1840
+ border: 1px solid var(--border-light);
1841
  border-radius: var(--radius-md) var(--radius-md) 0 0;
1842
  }
1843
 
1844
  .code-tab-btn {
1845
  padding: 5px 10px;
1846
+ background: var(--bg-primary);
1847
+ border: 1px solid var(--border-light);
1848
  border-radius: var(--radius-sm);
1849
  color: var(--text-muted);
1850
  font-size: 10px;
 
1854
  }
1855
 
1856
  .code-tab-btn:hover {
1857
+ border-color: var(--accent);
1858
+ color: var(--accent);
1859
  }
1860
 
1861
  .code-content {
1862
  flex: 1;
1863
+ background: #1e1e1e;
1864
+ border: 1px solid var(--border-light);
1865
  border-top: none;
1866
  border-radius: 0 0 var(--radius-md) var(--radius-md);
1867
  padding: 14px;
 
1869
  font-family: var(--font-mono);
1870
  font-size: 12px;
1871
  line-height: 1.7;
1872
+ color: #e0e0e0;
1873
  white-space: pre-wrap;
1874
  word-break: break-all;
1875
  }
 
1901
  gap: 6px;
1902
  }
1903
 
1904
+ .console-label.stdout { color: var(--success); }
1905
+ .console-label.stderr { color: var(--error); }
1906
 
1907
  .console-output {
1908
  flex: 1;
1909
+ background: #1e1e1e;
1910
+ border: 1px solid var(--border-light);
1911
  border-radius: var(--radius-sm);
1912
  padding: 10px;
1913
  overflow: auto;
1914
  font-family: var(--font-mono);
1915
  font-size: 11px;
1916
  line-height: 1.6;
1917
+ color: #9ca3af;
1918
  white-space: pre-wrap;
1919
  word-break: break-all;
1920
  }
1921
 
1922
  /* ═══ STATUS BAR ═══ */
1923
  .status-bar {
1924
+ height: 32px;
1925
+ min-height: 32px;
1926
  display: flex;
1927
  align-items: center;
1928
  justify-content: space-between;
1929
  padding: 0 16px;
1930
+ background: var(--bg-secondary);
1931
+ border-top: 1px solid var(--border-light);
1932
  font-size: 11px;
1933
  font-family: var(--font-mono);
1934
  }
 
1936
  .status-left, .status-right {
1937
  display: flex;
1938
  align-items: center;
1939
+ gap: 20px;
1940
  }
1941
 
1942
  .status-item {
 
1954
  }
1955
 
1956
  .status-idle { color: var(--text-muted); }
1957
+ .status-working { color: var(--warning); }
1958
+ .status-success { color: var(--success); }
1959
+ .status-error { color: var(--error); }
1960
+ .status-info { color: var(--accent); }
1961
 
1962
  .status-working .indicator {
1963
  animation: statusPulse 1s ease-in-out infinite;
 
1972
  .fullscreen-overlay {
1973
  position: fixed;
1974
  inset: 0;
1975
+ background: rgba(0, 0, 0, 0.9);
1976
+ backdrop-filter: blur(8px);
1977
  z-index: var(--z-modal);
1978
  display: none;
1979
  align-items: center;
 
2000
  display: flex;
2001
  align-items: center;
2002
  justify-content: center;
2003
+ background: var(--bg-secondary);
2004
+ border: 1px solid var(--border-light);
2005
  border-radius: var(--radius-md);
2006
  color: var(--text-secondary);
2007
  font-size: 20px;
 
2010
  }
2011
 
2012
  .fullscreen-close:hover {
2013
+ border-color: var(--error);
2014
+ color: var(--error);
2015
  }
2016
 
2017
  .fullscreen-iframe {
2018
  width: 90vw;
2019
  height: 90vh;
2020
+ border: 1px solid var(--border-light);
2021
  border-radius: var(--radius-lg);
2022
  background: white;
2023
+ box-shadow: var(--shadow-lg);
2024
  }
2025
 
2026
  /* ═══ RESPONSIVE ADJUSTMENTS ═══ */
 
2031
  }
2032
 
2033
  .sidebar {
2034
+ width: 240px;
2035
+ min-width: 240px;
2036
+ }
2037
+
2038
+ .settings-panel {
2039
+ left: 240px;
2040
  }
2041
  }
2042
 
 
2045
  display: none;
2046
  }
2047
 
2048
+ .settings-panel {
2049
+ left: 16px;
2050
+ right: 16px;
2051
+ width: auto;
2052
+ bottom: 50px;
2053
+ }
2054
+
2055
  .output-panel {
2056
  width: 250px;
2057
  min-width: 250px;
2058
  }
2059
+
 
 
2060
  .header-center {
2061
  display: none;
2062
  }
2063
 
2064
+ .examples-grid {
2065
+ grid-template-columns: 1fr;
2066
+ }
2067
+ }
2068
+
2069
+ @media (max-width: 600px) {
2070
  .status-indicators {
2071
  display: none;
2072
  }
 
2079
  position: fixed;
2080
  right: 0;
2081
  top: var(--header-height);
2082
+ bottom: 32px;
2083
  width: 100%;
2084
  min-width: 100%;
2085
  transform: translateX(100%);
 
2090
  .output-panel.show {
2091
  transform: translateX(0);
2092
  }
2093
+
2094
+ .welcome-banner {
2095
+ padding: 30px 20px;
2096
+ margin: 30px auto;
2097
+ }
2098
+
2099
+ .welcome-title {
2100
+ font-size: 22px;
2101
+ }
2102
  }
2103
 
2104
  /* ═══ LOADING/SPINNER ANIMATIONS ═══ */
2105
  .spinner {
2106
  width: 20px;
2107
  height: 20px;
2108
+ border: 2px solid var(--border-light);
2109
+ border-top-color: var(--accent);
2110
  border-radius: 50%;
2111
  animation: spin 0.8s linear infinite;
2112
  }
2113
 
 
 
 
 
2114
  .typing-indicator {
2115
  display: flex;
2116
  align-items: center;
 
2121
  .typing-indicator span {
2122
  width: 6px;
2123
  height: 6px;
2124
+ background: var(--accent);
2125
  border-radius: 50%;
2126
  animation: typingBounce 1.4s ease-in-out infinite;
2127
  }
 
2149
  .hidden { display: none !important; }
2150
  .visible { display: block !important; }
2151
 
2152
+ /* Mobile sidebar toggle */
2153
+ .mobile-sidebar-toggle {
2154
+ display: none;
2155
  }
2156
 
2157
+ @media (max-width: 900px) {
2158
+ .mobile-sidebar-toggle {
2159
+ display: flex;
2160
+ }
2161
  }
2162
  </style>
2163
  </head>
2164
  <body>
2165
 
 
 
 
 
 
 
 
 
2166
  <!-- Main App Container -->
2167
  <div class="app-container">
2168
 
2169
  <!-- Header -->
2170
  <header class="header">
2171
  <div class="header-left">
2172
+ <button class="btn-icon mobile-sidebar-toggle" onclick="toggleSidebar()">☰</button>
2173
  <div class="logo" onclick="newChat()">
2174
  <div class="logo-icon">⚑</div>
2175
  <div class="logo-text">
2176
  <span class="logo-title">SoniCoder</span>
2177
+ <span class="logo-version">v2.0</span>
2178
  </div>
2179
  </div>
2180
  </div>
2181
 
2182
  <div class="header-center">
2183
+ <div class="search-bar">
2184
+ <span class="search-icon">πŸ”</span>
2185
+ <input type="text" placeholder="Search conversations..." id="search-input">
2186
+ </div>
2187
+
2188
  <div class="model-selector" onclick="toggleModelMenu()">
2189
  <span class="model-dot" id="model-dot"></span>
2190
  <span class="model-text" id="model-pill-text">Loading...</span>
2191
  <span style="font-size: 10px; color: var(--text-muted);">β–Ό</span>
2192
+ <div class="model-dropdown" id="model-dropdown">
2193
+ <!-- Model options populated by JS -->
2194
+ </div>
2195
  </div>
2196
 
2197
  <div class="status-pill">
 
2203
  <div class="header-right">
2204
  <button class="btn-icon" onclick="refreshWorkspace()" title="Refresh Workspace">↻</button>
2205
  <button class="btn-icon" onclick="newChat()" title="New Chat">+</button>
2206
+ <div class="user-avatar" onclick="toggleUserMenu()" title="User Menu">U</div>
2207
  </div>
2208
  </header>
2209
 
 
2211
  <main class="main-content">
2212
 
2213
  <!-- Sidebar -->
2214
+ <aside class="sidebar" id="sidebar">
2215
  <div class="sidebar-header">
2216
+ <button class="new-chat-btn" onclick="newChat()">
2217
+ <span>+ New Chat</span>
2218
+ </button>
2219
+ </div>
2220
+
2221
+ <!-- Chat History Section -->
2222
+ <div class="sidebar-section">
2223
+ <div class="sidebar-section-title">
2224
+ <span>Recent Chats</span>
2225
+ </div>
2226
+ <div class="chat-history-list" id="chat-history-list">
2227
+ <div class="chat-history-empty">No recent chats</div>
2228
  </div>
2229
  </div>
2230
 
2231
+ <!-- Workspace Section -->
2232
+ <div class="sidebar-section">
2233
+ <div class="sidebar-section-title">
2234
+ <span>πŸ“ Workspace</span>
2235
+ <button class="btn-sidebar-action" onclick="refreshWorkspace()" title="Refresh" style="background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:12px;">↻</button>
2236
+ </div>
2237
+ <div class="sidebar-content" style="padding: 0 12px;">
2238
+ <div class="file-tree" id="files-tree"></div>
2239
+ <div class="file-viewer" id="file-viewer"></div>
2240
+ </div>
2241
  </div>
2242
 
2243
+ <!-- MCP Section -->
2244
  <div class="sidebar-section">
2245
+ <div class="sidebar-section-title">
2246
+ <span>πŸ”Œ MCP Servers</span>
2247
+ </div>
2248
  <div class="sidebar-content" style="padding: 0 12px;">
2249
  <div id="mcp-content"></div>
2250
  </div>
2251
  </div>
2252
+
2253
+ <!-- Sidebar Footer with Storage Mode & Settings -->
2254
+ <div class="sidebar-footer">
2255
+ <div class="sidebar-footer-actions">
2256
+ <div class="storage-mode" id="storage-mode">
2257
+ <span class="storage-dot"></span>
2258
+ <span>Local</span>
2259
+ </div>
2260
+ <button class="settings-btn" onclick="toggleSettings()" title="Settings">βš™οΈ</button>
2261
+ </div>
2262
+ </div>
2263
  </aside>
2264
 
2265
+ <!-- Settings Panel -->
2266
+ <div class="settings-panel" id="settings-panel">
2267
+ <div class="settings-panel-header">
2268
+ <span class="settings-panel-title">Settings</span>
2269
+ <button class="settings-close-btn" onclick="toggleSettings()">βœ•</button>
2270
+ </div>
2271
+ <div class="settings-panel-body">
2272
+ <!-- Model Selection -->
2273
+ <div class="setting-group">
2274
+ <label class="setting-label">
2275
+ <span>Model</span>
2276
+ </label>
2277
+ <select class="setting-select" id="setting-model" onchange="onSettingModelChange(this.value)">
2278
+ <option value="qwen2.5-coder">Qwen2.5-Coder</option>
2279
+ <option value="minicpm5">MiniCPM5</option>
2280
+ <option value="deepseek">DeepSeek</option>
2281
+ <option value="codestral">Codestral</option>
2282
+ </select>
2283
+ </div>
2284
+
2285
+ <!-- Temperature -->
2286
+ <div class="setting-group">
2287
+ <label class="setting-label">
2288
+ <span>Temperature</span>
2289
+ <span class="setting-value" id="temp-value">0.7</span>
2290
+ </label>
2291
+ <input type="range" class="setting-slider" id="setting-temperature"
2292
+ min="0" max="2" step="0.1" value="0.7"
2293
+ oninput="document.getElementById('temp-value').textContent = this.value">
2294
+ </div>
2295
+
2296
+ <!-- Max Tokens -->
2297
+ <div class="setting-group">
2298
+ <label class="setting-label">
2299
+ <span>Max Tokens</span>
2300
+ <span class="setting-value" id="tokens-value">8192</span>
2301
+ </label>
2302
+ <input type="range" class="setting-slider" id="setting-maxtokens"
2303
+ min="1024" max="32768" step="1024" value="8192"
2304
+ oninput="document.getElementById('tokens-value').textContent = this.value">
2305
+ </div>
2306
+
2307
+ <!-- Storage Mode -->
2308
+ <div class="setting-group">
2309
+ <label class="setting-label">
2310
+ <span>Storage Mode</span>
2311
+ </label>
2312
+ <select class="setting-select" id="setting-storage" onchange="onStorageModeChange(this.value)">
2313
+ <option value="local">Local</option>
2314
+ <option value="hf-hub">HuggingFace Hub</option>
2315
+ <option value="bucket">Cloud Bucket</option>
2316
+ </select>
2317
+ </div>
2318
+
2319
+ <!-- Theme Toggle -->
2320
+ <div class="setting-group">
2321
+ <div class="setting-row">
2322
+ <label class="setting-label" style="margin:0;"><span>Dark Mode</span></label>
2323
+ <div class="setting-toggle" id="theme-toggle" onclick="toggleTheme()"></div>
2324
+ </div>
2325
+ </div>
2326
+
2327
+ <!-- Export Buttons -->
2328
+ <div class="setting-group">
2329
+ <label class="setting-label"><span>Export</span></label>
2330
+ <div class="export-buttons">
2331
+ <button class="export-btn" onclick="exportChat('json')">πŸ“„ JSON</button>
2332
+ <button class="export-btn" onclick="exportChat('markdown')">πŸ“ MD</button>
2333
+ </div>
2334
+ </div>
2335
+ </div>
2336
+ </div>
2337
+
2338
  <!-- Chat Area -->
2339
  <section class="chat-area">
2340
  <div class="chat-messages" id="chat-messages">
2341
+ <!-- Welcome message shown when no messages -->
2342
+ <div class="welcome-banner" id="welcome-banner">
2343
+ <span class="welcome-icon">πŸ‘‹</span>
2344
+ <h1 class="welcome-title">Hi, I'm SoniCoder</h1>
2345
+ <p class="welcome-subtitle">How can I help you code today? I can build apps, write scripts, debug code, and more.</p>
2346
+ <div class="examples-grid" id="examples-row">
2347
+ <!-- Examples populated by JS -->
2348
+ </div>
2349
+ </div>
2350
  </div>
2351
 
2352
  <!-- Input Area -->
 
2415
  </section>
2416
 
2417
  <!-- Output Panel -->
2418
+ <aside class="output-panel" id="output-panel">
2419
  <div class="output-tabs">
2420
  <button class="output-tab active" data-tab="preview" onclick="switchTab('preview')">Preview</button>
2421
  <button class="output-tab" data-tab="code" onclick="switchTab('code')">Code</button>
 
2473
  <span class="status-item">
2474
  <span id="header-model-name"></span>
2475
  </span>
2476
+ <span class="status-item" id="status-storage">Local Mode</span>
2477
  <span class="status-item">SoniCoder v2</span>
2478
  </div>
2479
  </footer>
 
2503
  consoleStdout: '',
2504
  consoleStderr: '',
2505
  attachedImage: null,
2506
+ activeTab: 'preview',
2507
+ chatHistory: [],
2508
+ settingsOpen: false,
2509
+ modelMenuOpen: false,
2510
+ theme: 'light'
2511
  };
2512
 
2513
  // ═══ INITIALIZATION ═══
2514
 
2515
  document.addEventListener('DOMContentLoaded', function() {
 
2516
  loadConfig();
2517
  pollModelStatus();
2518
  loadMcpStatus();
2519
  refreshWorkspace();
2520
+ initTheme();
 
 
2521
  });
2522
 
2523
+ function initTheme() {
2524
+ var savedTheme = localStorage.getItem('sonicoder-theme') || 'light';
2525
+ state.theme = savedTheme;
2526
+ document.documentElement.setAttribute('data-theme', savedTheme);
2527
+ var toggle = document.getElementById('theme-toggle');
2528
+ if (toggle && savedTheme === 'dark') {
2529
+ toggle.classList.add('active');
2530
+ }
2531
+ }
2532
+
2533
+ function toggleTheme() {
2534
+ var toggle = document.getElementById('theme-toggle');
2535
+ if (state.theme === 'light') {
2536
+ state.theme = 'dark';
2537
+ document.documentElement.setAttribute('data-theme', 'dark');
2538
+ localStorage.setItem('sonicoder-theme', 'dark');
2539
+ if (toggle) toggle.classList.add('active');
2540
+ } else {
2541
+ state.theme = 'light';
2542
+ document.documentElement.setAttribute('data-theme', '');
2543
+ localStorage.setItem('sonicoder-theme', 'light');
2544
+ if (toggle) toggle.classList.remove('active');
2545
  }
2546
  }
2547
 
 
2588
  agentSel.appendChild(opt);
2589
  });
2590
 
2591
+ // Populate model dropdown in header
2592
+ populateModelDropdown(config);
2593
+
2594
  renderExamples(config);
2595
  } catch(e) { console.error('Config load failed:', e); }
2596
  }
2597
 
2598
+ function populateModelDropdown(config) {
2599
+ var dropdown = document.getElementById('model-dropdown');
2600
+ if (!dropdown) return;
2601
+
2602
+ var models = config.models || [
2603
+ { key: 'qwen2.5-coder', name: 'Qwen2.5-Coder', desc: '1.5B β€’ Code focused' },
2604
+ { key: 'minicpm5', name: 'MiniCPM5', desc: '1B β€’ Versatile' },
2605
+ { key: 'deepseek', name: 'DeepSeek-Coder', desc: '1B β€’ DeepSeek quality' },
2606
+ { key: 'codestral', name: 'Codestral', desc: '1B β€’ Fast inference' }
2607
+ ];
2608
+
2609
+ dropdown.innerHTML = '';
2610
+ models.forEach(function(m) {
2611
+ var div = document.createElement('div');
2612
+ div.className = 'model-option';
2613
+ div.dataset.key = m.key;
2614
+ div.innerHTML = '<div><div class="model-name">' + m.name + '</div><div class="model-desc">' + (m.desc || '') + '</div></div>';
2615
+ div.onclick = function(e) {
2616
+ e.stopPropagation();
2617
+ switchModel(m.key);
2618
+ closeModelMenu();
2619
+ };
2620
+ dropdown.appendChild(div);
2621
+ });
2622
+ }
2623
+
2624
  function updateFrameworkOptions() {
2625
  if (!state.config) return;
2626
  var langSel = document.getElementById('opt-language');
 
2722
  document.getElementById('model-dot').className = 'model-dot loading';
2723
  document.getElementById('model-pill-text').textContent = 'Switching...';
2724
  setStatus('status-working', 'SWITCHING MODEL...');
2725
+
2726
+ // Update setting select too
2727
+ var settingSelect = document.getElementById('setting-model');
2728
+ if (settingSelect) settingSelect.value = key;
2729
+
2730
  await fetch('/api/switch_model', {
2731
  method: 'POST', headers: {'Content-Type': 'application/json'},
2732
  body: JSON.stringify({ model_key: key }),
 
2735
  } catch(e) { console.error(e); }
2736
  }
2737
 
2738
+ function onSettingModelChange(value) {
2739
+ switchModel(value);
2740
+ closeModelMenu();
2741
+ }
2742
+
2743
+ function onStorageModeChange(value) {
2744
+ var modeEl = document.getElementById('storage-mode');
2745
+ var statusEl = document.getElementById('status-storage');
2746
+
2747
+ modeEl.className = 'storage-mode ' + value;
2748
+
2749
+ var labels = {
2750
+ 'local': 'Local Mode',
2751
+ 'hf-hub': 'HF Hub Mode',
2752
+ 'bucket': 'Bucket Mode'
2753
+ };
2754
+
2755
+ var storageLabels = {
2756
+ 'local': 'Local',
2757
+ 'hf-hub': 'HF Hub',
2758
+ 'bucket': 'Bucket'
2759
+ };
2760
+
2761
+ if (modeEl) modeEl.querySelector('span:last-child').textContent = storageLabels[value] || value;
2762
+ if (statusEl) statusEl.textContent = labels[value] || value;
2763
+ }
2764
+
2765
+ function toggleModelMenu() {
2766
+ var dropdown = document.getElementById('model-dropdown');
2767
+ state.modelMenuOpen = !state.modelMenuOpen;
2768
+ if (dropdown) {
2769
+ dropdown.classList.toggle('show', state.modelMenuOpen);
2770
+ }
2771
+ }
2772
+
2773
+ function closeModelMenu() {
2774
+ state.modelMenuOpen = false;
2775
+ var dropdown = document.getElementById('model-dropdown');
2776
+ if (dropdown) dropdown.classList.remove('show');
2777
+ }
2778
+
2779
+ function toggleSettings() {
2780
+ var panel = document.getElementById('settings-panel');
2781
+ state.settingsOpen = !state.settingsOpen;
2782
+ if (panel) {
2783
+ panel.classList.toggle('show', state.settingsOpen);
2784
+ }
2785
+ }
2786
+
2787
+ function toggleSidebar() {
2788
+ var sidebar = document.getElementById('sidebar');
2789
+ if (sidebar) {
2790
+ sidebar.style.display = sidebar.style.display === 'none' ? 'flex' : 'none';
2791
+ }
2792
+ }
2793
+
2794
+ function toggleUserMenu() {
2795
+ // Could implement user menu here
2796
+ console.log('User menu clicked');
2797
+ }
2798
+
2799
+ // Close menus when clicking outside
2800
+ document.addEventListener('click', function(e) {
2801
+ if (state.modelMenuOpen && !e.target.closest('.model-selector')) {
2802
+ closeModelMenu();
2803
+ }
2804
+ if (state.settingsOpen && !e.target.closest('.settings-panel') && !e.target.closest('.settings-btn')) {
2805
+ var panel = document.getElementById('settings-panel');
2806
+ if (panel) panel.classList.remove('show');
2807
+ state.settingsOpen = false;
2808
+ }
2809
+ });
2810
+
2811
  async function refreshWorkspace() {
2812
  try {
2813
  var resp = await fetch('/api/workspace_tree?max_depth=4');
 
2826
  if (!node) return '';
2827
  var name = escHtml(node.name || '');
2828
  if (node.type === 'dir') {
2829
+ var html = '<div class="ws-dir"><span class="ws-dir-name"><span class="dir-icon">πŸ“</span>' + name + '</span>';
2830
  if (node.children && node.children.length > 0) {
2831
  html += '<div class="ws-children">';
2832
  for (var i = 0; i < node.children.length; i++) {
 
2838
  return html;
2839
  } else {
2840
  var size = node.size ? ' (' + formatSize(node.size) + ')' : '';
2841
+ return '<div class="ws-file" data-path="' + name + '" onclick="openWorkspaceFile(\'' + name.replace(/'/g, "\\'") + '\')"><span><span class="file-icon">πŸ“„</span>' + name + size + '</span></div>';
2842
  }
2843
  }
2844
 
 
2942
  examples = examples.slice(0, 6);
2943
  var row = document.getElementById('examples-row');
2944
  if (!row) return;
2945
+ row.innerHTML = '';
2946
  examples.forEach(function(ex) {
2947
+ var card = document.createElement('div');
2948
+ card.className = 'example-card';
2949
+ card.textContent = ex;
2950
+ card.onclick = function() {
2951
  document.getElementById('chat-input').value = ex;
2952
  document.getElementById('chat-input').dispatchEvent(new Event('input'));
2953
  handleSend();
2954
  };
2955
+ row.appendChild(card);
2956
  });
2957
  }
2958
 
2959
+ // ═══ EXPORT FUNCTIONS ═══
2960
+
2961
+ function exportChat(format) {
2962
+ var messages = document.querySelectorAll('.chat-messages .msg');
2963
+ if (!messages.length) {
2964
+ alert('No chat to export');
2965
+ return;
2966
+ }
2967
+
2968
+ var content = '';
2969
+ var filename = '';
2970
+ var mimeType = '';
2971
+
2972
+ if (format === 'json') {
2973
+ var chatData = [];
2974
+ messages.forEach(function(msg) {
2975
+ var role = msg.classList.contains('msg-user') ? 'user' :
2976
+ msg.classList.contains('msg-assistant') ? 'assistant' : 'system';
2977
+ var text = msg.querySelector('.msg-content')?.textContent || '';
2978
+ chatData.push({ role: role, content: text });
2979
+ });
2980
+ content = JSON.stringify(chatData, null, 2);
2981
+ filename = 'sonicoder-chat.json';
2982
+ mimeType = 'application/json';
2983
+ } else {
2984
+ messages.forEach(function(msg) {
2985
+ var prefix = msg.classList.contains('msg-user') ? '**You:** ' :
2986
+ msg.classList.contains('msg-assistant') ? '**SoniCoder:** ' :
2987
+ '> ';
2988
+ content += prefix + (msg.querySelector('.msg-content')?.textContent || '') + '\n\n';
2989
+ });
2990
+ filename = 'sonicoder-chat.md';
2991
+ mimeType = 'text/markdown';
2992
+ }
2993
+
2994
+ var blob = new Blob([content], { type: mimeType });
2995
+ var url = URL.createObjectURL(blob);
2996
+ var a = document.createElement('a');
2997
+ a.href = url;
2998
+ a.download = filename;
2999
+ a.click();
3000
+ URL.revokeObjectURL(url);
3001
+ }
3002
+
3003
  // ═══ TABS ═══
3004
 
3005
  function switchTab(tab) {
 
3025
  document.getElementById('fullscreen-iframe').src = 'about:blank';
3026
  }
3027
  document.addEventListener('keydown', function(e) {
3028
+ if (e.key === 'Escape') {
3029
+ closeFullscreen();
3030
+ closeModelMenu();
3031
+ }
3032
  });
3033
 
3034
  // ═══ INPUT HANDLING ═══
 
3051
 
3052
  function addMessage(role, content, extra) {
3053
  extra = extra || {};
3054
+
3055
+ // Hide welcome banner when first message is added
3056
+ var welcomeBanner = document.getElementById('welcome-banner');
3057
+ if (welcomeBanner) welcomeBanner.style.display = 'none';
3058
+
3059
  var container = document.getElementById('chat-messages');
3060
  var div = document.createElement('div');
3061
  div.className = 'msg msg-' + role;
 
3065
  wrapper.className = 'msg-content-wrapper';
3066
 
3067
  var prefix = '';
3068
+ if (role === 'user') prefix = '<span class="msg-prefix">You</span>';
3069
+ else if (role === 'assistant') prefix = '<span class="msg-prefix">SoniCoder</span>';
3070
+ else if (role === 'system') prefix = '<span class="msg-prefix">β—‰</span>';
3071
 
3072
  var iterationHtml = extra.iteration ? '<div class="iteration-badge">Iteration ' + extra.iteration + '/' + extra.max_iterations + '</div>' : '';
3073
+ wrapper.innerHTML = iterationHtml + prefix + '<div class="msg-content">' + renderMd(content) + '</div>';
3074
 
3075
  div.appendChild(wrapper);
3076
  container.appendChild(div);
 
3333
  state.consoleStdout = '';
3334
  state.consoleStderr = '';
3335
  document.getElementById('chat-messages').innerHTML = '';
3336
+
3337
+ // Show welcome banner again
3338
+ var welcomeBanner = document.getElementById('welcome-banner');
3339
+ if (welcomeBanner) welcomeBanner.style.display = '';
3340
+
3341
  addMessage('system', 'New session started. What would you like to build?');
3342
  updateConsole();
3343
  setStatus('status-idle', 'IDLE');
 
3368
  el.className = 'status-item ' + className;
3369
  document.getElementById('status-text').textContent = text;
3370
  }
 
 
 
 
 
 
 
3371
  </script>
3372
  </body>
3373
  </html>