umanggarg Claude Sonnet 4.6 commited on
Commit
fb8d4ff
·
1 Parent(s): bd3100b

OLED glow polish + ⌘K keyboard shortcut from design system

Browse files

CSS — Dark Mode (OLED) checklist items (ui-ux-pro-max-skill):
- color-scheme: dark on :root (browser chrome adapts: scrollbars, inputs)
- Streaming cursor: green + box-shadow glow (0 0 6px rgba(34,197,94,0.7))
- User bubble: dark-green→green gradient + shadow (replaces flat accent)
- Btn primary: glow on rest (0.25 alpha), stronger on hover (0.35 alpha)
- Active repo item: inset + outer glow rings
- Input focus: green glow ring (rgba(34,197,94,0.12))
- Agent trace live: glow border
- Onboarding active step: ambient glow

UX — Productivity Tool must_have: keyboard-shortcuts:
- ⌘K / Ctrl+K global shortcut focuses chat input from anywhere
- Switches from Graph view to Chat if needed before focusing
- ⌘K hint badge shown in input bar when idle (hides during streaming/typing)

Send button: shortened "Run Agent" → "Run" to match button width

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. ui/src/App.jsx +21 -1
  2. ui/src/index.css +47 -7
ui/src/App.jsx CHANGED
@@ -24,6 +24,21 @@ export default function App() {
24
  const textareaRef = useRef(null);
25
  const stopStream = useRef(null); // cleanup fn for active SSE
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  // Auto-grow textarea as user types
28
  useEffect(() => {
29
  const el = textareaRef.current;
@@ -421,10 +436,15 @@ export default function App() {
421
  className="btn"
422
  onClick={handleSubmit}
423
  disabled={!input.trim() || streaming}
 
424
  >
425
- {streaming ? <span className="spinner" /> : agentMode ? "Run Agent" : "Ask"}
426
  </button>
427
  </div>
 
 
 
 
428
  </div>
429
  </>
430
  )}
 
24
  const textareaRef = useRef(null);
25
  const stopStream = useRef(null); // cleanup fn for active SSE
26
 
27
+ // ⌘K / Ctrl+K — focus the input from anywhere in the app.
28
+ // Productivity Tool must_have: keyboard-shortcuts (ui-ux-pro-max-skill #16).
29
+ useEffect(() => {
30
+ function onGlobalKey(e) {
31
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
32
+ e.preventDefault();
33
+ if (view === "graph") setView("chat");
34
+ // Small delay if we just switched views (textarea may not be mounted yet)
35
+ setTimeout(() => textareaRef.current?.focus(), 20);
36
+ }
37
+ }
38
+ window.addEventListener("keydown", onGlobalKey);
39
+ return () => window.removeEventListener("keydown", onGlobalKey);
40
+ }, [view]);
41
+
42
  // Auto-grow textarea as user types
43
  useEffect(() => {
44
  const el = textareaRef.current;
 
436
  className="btn"
437
  onClick={handleSubmit}
438
  disabled={!input.trim() || streaming}
439
+ aria-label={streaming ? "Generating…" : agentMode ? "Run Agent" : "Ask"}
440
  >
441
+ {streaming ? <span className="spinner" aria-hidden="true" /> : agentMode ? "Run" : "Ask"}
442
  </button>
443
  </div>
444
+ {/* ⌘K hint — shown when idle, guides users to the keyboard shortcut */}
445
+ {!streaming && !input && (
446
+ <div className="input-hint" aria-hidden="true">⌘K</div>
447
+ )}
448
  </div>
449
  </>
450
  )}
ui/src/index.css CHANGED
@@ -68,6 +68,10 @@
68
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.6);
69
  }
70
 
 
 
 
 
71
  body {
72
  font-family: var(--sans);
73
  background: var(--bg);
@@ -196,11 +200,16 @@ textarea:focus-visible {
196
  font-size: 13px;
197
  font-weight: 600;
198
  padding: 8px 12px;
199
- transition: opacity var(--transition), transform var(--transition);
 
 
200
  }
201
 
202
- .btn:hover { opacity: 0.85; }
203
- .btn:active { transform: scale(0.97); }
 
 
 
204
  .btn:disabled { opacity: 0.4; cursor: not-allowed; }
205
  .btn.secondary {
206
  background: var(--pill-bg);
@@ -232,6 +241,8 @@ textarea:focus-visible {
232
  .repo-item.active {
233
  background: var(--accent-dim);
234
  border-color: var(--accent);
 
 
235
  }
236
 
237
  .repo-slug {
@@ -397,9 +408,12 @@ textarea:focus-visible {
397
  }
398
 
399
  .message.user .bubble {
400
- background: var(--accent);
 
 
401
  color: #000;
402
  border-bottom-right-radius: 3px;
 
403
  }
404
 
405
  .message.assistant .bubble {
@@ -596,7 +610,10 @@ textarea:focus-visible {
596
  transition: border-color var(--transition);
597
  }
598
 
599
- .input-bar textarea:focus { border-color: var(--accent); }
 
 
 
600
  .input-bar textarea::placeholder { color: var(--muted); }
601
 
602
  /* ── Empty state ─────────────────────────────────────────────── */
@@ -636,7 +653,7 @@ textarea:focus-visible {
636
 
637
  .onboarding-step.active {
638
  border-color: var(--accent);
639
- box-shadow: 0 0 0 1px var(--accent-dim), var(--shadow-sm);
640
  }
641
 
642
  .step-num {
@@ -758,10 +775,12 @@ textarea:focus-visible {
758
  .cursor {
759
  display: inline-block;
760
  width: 2px; height: 14px;
761
- background: var(--text);
762
  margin-left: 2px;
763
  vertical-align: text-bottom;
764
  animation: blink 1s step-end infinite;
 
 
765
  }
766
  @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
767
 
@@ -940,6 +959,7 @@ textarea:focus-visible {
940
  border-radius: var(--radius-md);
941
  padding: 8px 12px;
942
  background: var(--accent-dim);
 
943
  }
944
 
945
  .agent-trace-label {
@@ -1096,6 +1116,26 @@ textarea:focus-visible {
1096
  50% { opacity: 0.3; }
1097
  }
1098
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1099
  /* ── Scrollbar ───────────────────────────────────────────────── */
1100
  ::-webkit-scrollbar { width: 6px; }
1101
  ::-webkit-scrollbar-track { background: transparent; }
 
68
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.6);
69
  }
70
 
71
+ /* color-scheme: dark — browser chrome (scrollbars, inputs, select) adapts.
72
+ Required by Dark Mode (OLED) checklist in ui-ux-pro-max-skill. */
73
+ :root { color-scheme: dark; }
74
+
75
  body {
76
  font-family: var(--sans);
77
  background: var(--bg);
 
200
  font-size: 13px;
201
  font-weight: 600;
202
  padding: 8px 12px;
203
+ transition: opacity var(--transition), transform var(--transition), box-shadow var(--transition);
204
+ /* Minimal OLED glow on primary CTA */
205
+ box-shadow: 0 2px 8px rgba(34,197,94,0.25);
206
  }
207
 
208
+ .btn:hover {
209
+ opacity: 0.9;
210
+ box-shadow: 0 4px 16px rgba(34,197,94,0.35);
211
+ }
212
+ .btn:active { transform: scale(0.97); box-shadow: none; }
213
  .btn:disabled { opacity: 0.4; cursor: not-allowed; }
214
  .btn.secondary {
215
  background: var(--pill-bg);
 
241
  .repo-item.active {
242
  background: var(--accent-dim);
243
  border-color: var(--accent);
244
+ /* Minimal glow — OLED dark mode accent highlight (ui-ux-pro-max-skill) */
245
+ box-shadow: 0 0 0 1px rgba(34,197,94,0.12), inset 0 0 8px rgba(34,197,94,0.05);
246
  }
247
 
248
  .repo-slug {
 
408
  }
409
 
410
  .message.user .bubble {
411
+ /* Gradient instead of flat green — premium OLED look.
412
+ Dark-green → bright-green matches the "run" semantic. */
413
+ background: linear-gradient(135deg, #166534 0%, #22C55E 100%);
414
  color: #000;
415
  border-bottom-right-radius: 3px;
416
+ box-shadow: 0 2px 12px rgba(34,197,94,0.2);
417
  }
418
 
419
  .message.assistant .bubble {
 
610
  transition: border-color var(--transition);
611
  }
612
 
613
+ .input-bar textarea:focus {
614
+ border-color: var(--accent);
615
+ box-shadow: 0 0 0 3px rgba(34,197,94,0.12);
616
+ }
617
  .input-bar textarea::placeholder { color: var(--muted); }
618
 
619
  /* ── Empty state ─────────────────────────────────────────────── */
 
653
 
654
  .onboarding-step.active {
655
  border-color: var(--accent);
656
+ box-shadow: 0 0 0 1px rgba(34,197,94,0.15), 0 0 12px rgba(34,197,94,0.08), var(--shadow-sm);
657
  }
658
 
659
  .step-num {
 
775
  .cursor {
776
  display: inline-block;
777
  width: 2px; height: 14px;
778
+ background: var(--accent);
779
  margin-left: 2px;
780
  vertical-align: text-bottom;
781
  animation: blink 1s step-end infinite;
782
+ /* Accent glow on cursor — visible "thinking" indicator */
783
+ box-shadow: 0 0 6px rgba(34,197,94,0.7);
784
  }
785
  @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
786
 
 
959
  border-radius: var(--radius-md);
960
  padding: 8px 12px;
961
  background: var(--accent-dim);
962
+ box-shadow: 0 0 0 1px rgba(34,197,94,0.1);
963
  }
964
 
965
  .agent-trace-label {
 
1116
  50% { opacity: 0.3; }
1117
  }
1118
 
1119
+ /* ── Keyboard shortcut hint ──────────────────────────────────── */
1120
+ /* Shown inside the input bar when textarea is empty and not streaming.
1121
+ Follows the Productivity Tool must_have: keyboard-shortcuts from
1122
+ ui-ux-pro-max-skill. Inspired by Linear/Raycast/Vercel AI patterns. */
1123
+ .input-hint {
1124
+ position: absolute;
1125
+ right: 72px;
1126
+ bottom: 19px;
1127
+ font-size: 11px;
1128
+ color: var(--faint);
1129
+ font-family: var(--mono);
1130
+ pointer-events: none;
1131
+ background: var(--surface);
1132
+ border: 1px solid var(--border-subtle);
1133
+ padding: 1px 6px;
1134
+ border-radius: var(--radius-sm);
1135
+ letter-spacing: 0.02em;
1136
+ user-select: none;
1137
+ }
1138
+
1139
  /* ── Scrollbar ───────────────────────────────────────────────── */
1140
  ::-webkit-scrollbar { width: 6px; }
1141
  ::-webkit-scrollbar-track { background: transparent; }