Spaces:
Running
Running
Styles: mobile viewport height, keybar, single-scroll window, send button
Browse files.app height follows --vvh (visual viewport) on mobile so the terminal
and its control bar stay above the on-screen keyboard. Adds the
control-key bar, the conversation-window single-scroll layout (body
scrolls, output and input don't), and the reply send button.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- web/src/styles.css +24 -7
web/src/styles.css
CHANGED
|
@@ -243,6 +243,7 @@ body {
|
|
| 243 |
|
| 244 |
/* card content */
|
| 245 |
.ov-card { padding: 11px 14px 10px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
|
|
|
|
| 246 |
.ov-id { display: flex; align-items: center; gap: 8px; cursor: pointer; min-width: 0; }
|
| 247 |
.ov-id .spacer { flex: 1; }
|
| 248 |
.ov-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -250,8 +251,8 @@ body {
|
|
| 250 |
.ov-go { color: var(--muted); font-size: 12px; opacity: 0; transition: opacity 0.12s ease-out; flex: none; }
|
| 251 |
.ov-card:hover .ov-go, .ov-id:focus-visible .ov-go { opacity: 1; }
|
| 252 |
|
| 253 |
-
/* full prompt, wrapped
|
| 254 |
-
.ov-prompt { font-size: 13px; font-weight: 550; color: var(--text); white-space: pre-wrap; overflow-wrap: break-word;
|
| 255 |
/* nothing between prompt and reply → one hairline, not two */
|
| 256 |
.ov-prompt + .ov-live { border-top: none; }
|
| 257 |
.ov-prompt::before { content: '❯ '; font-family: var(--font-mono); color: var(--accent); font-weight: 700; }
|
|
@@ -271,8 +272,9 @@ body {
|
|
| 271 |
.ov-answer { font-size: 13px; line-height: 1.55; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
| 272 |
/* live progress while running: present but clearly not the final word */
|
| 273 |
.ov-answer-dim { color: var(--muted); margin-bottom: 5px; -webkit-line-clamp: 2; }
|
| 274 |
-
/* answer flows in the card
|
| 275 |
-
|
|
|
|
| 276 |
.ov-md pre { font-size: 11px; }
|
| 277 |
|
| 278 |
/* braille spinner: unmistakably a process, never an input line */
|
|
@@ -315,8 +317,12 @@ body {
|
|
| 315 |
.ovt-gn { color: var(--border-strong); }
|
| 316 |
/* conversation window: the full card, centered over the grid */
|
| 317 |
.ovw-backdrop { position: fixed; inset: 0; z-index: 120; display: flex; align-items: flex-start; justify-content: center; padding: 7vh 20px 20px; background: color-mix(in srgb, #000 52%, transparent); backdrop-filter: blur(3px); animation: rise-in 0.15s ease-out; }
|
| 318 |
-
|
| 319 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
.ov-x { background: none; border: none; color: var(--muted); font-size: 13px; cursor: pointer; padding: 0 2px 0 8px; flex: none; }
|
| 321 |
.ov-x:hover { color: var(--text); }
|
| 322 |
|
|
@@ -326,6 +332,9 @@ body {
|
|
| 326 |
.ov-live textarea { flex: 1; min-width: 0; border: none; background: none; font: inherit; font-size: 13px; line-height: 1.45; color: var(--text); outline: none; padding: 2px 0; resize: none; overflow: hidden; max-height: 140px; }
|
| 327 |
.ov-live textarea::placeholder { color: var(--muted); opacity: 0.7; }
|
| 328 |
.ov-hint { font-size: 10.5px; color: var(--muted); flex: none; }
|
|
|
|
|
|
|
|
|
|
| 329 |
.ov-note { font-size: 11px; color: var(--danger); }
|
| 330 |
|
| 331 |
/* tree */
|
|
@@ -553,6 +562,11 @@ body {
|
|
| 553 |
.slot.focused .pane-head { background: color-mix(in srgb, var(--accent) 8%, var(--panel)); }
|
| 554 |
|
| 555 |
.term-host { flex: 1; min-height: 0; padding: 10px 8px 8px 12px; background: var(--term-bg); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
.term-host .xterm { height: 100%; }
|
| 557 |
.xterm .xterm-viewport { scrollbar-width: none; }
|
| 558 |
.xterm .xterm-viewport::-webkit-scrollbar { width: 0; height: 0; display: none; }
|
|
@@ -802,7 +816,10 @@ a.btn-ghost { text-decoration: none; }
|
|
| 802 |
|
| 803 |
/* phones: two full-screen views — the sidebar list, or the selected pane */
|
| 804 |
@media (max-width: 720px) {
|
| 805 |
-
|
|
|
|
|
|
|
|
|
|
| 806 |
.app.m-home .main { display: none; }
|
| 807 |
.app.m-home .sidebar { width: 100%; border-right: none; }
|
| 808 |
.app.m-stage .sidebar { display: none; }
|
|
|
|
| 243 |
|
| 244 |
/* card content */
|
| 245 |
.ov-card { padding: 11px 14px 10px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
|
| 246 |
+
.ov-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
|
| 247 |
.ov-id { display: flex; align-items: center; gap: 8px; cursor: pointer; min-width: 0; }
|
| 248 |
.ov-id .spacer { flex: 1; }
|
| 249 |
.ov-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
| 251 |
.ov-go { color: var(--muted); font-size: 12px; opacity: 0; transition: opacity 0.12s ease-out; flex: none; }
|
| 252 |
.ov-card:hover .ov-go, .ov-id:focus-visible .ov-go { opacity: 1; }
|
| 253 |
|
| 254 |
+
/* full prompt, wrapped — the card body scrolls, so no inner scroll here */
|
| 255 |
+
.ov-prompt { font-size: 13px; font-weight: 550; color: var(--text); white-space: pre-wrap; overflow-wrap: break-word; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
|
| 256 |
/* nothing between prompt and reply → one hairline, not two */
|
| 257 |
.ov-prompt + .ov-live { border-top: none; }
|
| 258 |
.ov-prompt::before { content: '❯ '; font-family: var(--font-mono); color: var(--accent); font-weight: 700; }
|
|
|
|
| 272 |
.ov-answer { font-size: 13px; line-height: 1.55; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
| 273 |
/* live progress while running: present but clearly not the final word */
|
| 274 |
.ov-answer-dim { color: var(--muted); margin-bottom: 5px; -webkit-line-clamp: 2; }
|
| 275 |
+
/* answer flows in the card at natural height — the window body is the single
|
| 276 |
+
scroll region, so no inner scrollbar here */
|
| 277 |
+
.markdown.ov-md { border: none; background: none; padding: 0; font-size: 12.5px; }
|
| 278 |
.ov-md pre { font-size: 11px; }
|
| 279 |
|
| 280 |
/* braille spinner: unmistakably a process, never an input line */
|
|
|
|
| 317 |
.ovt-gn { color: var(--border-strong); }
|
| 318 |
/* conversation window: the full card, centered over the grid */
|
| 319 |
.ovw-backdrop { position: fixed; inset: 0; z-index: 120; display: flex; align-items: flex-start; justify-content: center; padding: 7vh 20px 20px; background: color-mix(in srgb, #000 52%, transparent); backdrop-filter: blur(3px); animation: rise-in 0.15s ease-out; }
|
| 320 |
+
/* window is a flex column: header + scrolling body + fixed input. Only the
|
| 321 |
+
body scrolls (one scrollbar), the reply input stays put at the bottom. */
|
| 322 |
+
.ovw-win { width: 100%; max-width: 640px; max-height: 85vh; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--border); border-radius: 13px; box-shadow: 0 24px 60px rgb(0 0 0 / 0.4); overflow: hidden; }
|
| 323 |
+
.ovw-win .ov-card { flex: 1; min-height: 0; padding: 14px 17px 12px; }
|
| 324 |
+
.ovw-win .ov-body { flex: 1; min-height: 0; overflow-y: auto; }
|
| 325 |
+
.ovw-win .ov-live { flex: none; }
|
| 326 |
.ov-x { background: none; border: none; color: var(--muted); font-size: 13px; cursor: pointer; padding: 0 2px 0 8px; flex: none; }
|
| 327 |
.ov-x:hover { color: var(--text); }
|
| 328 |
|
|
|
|
| 332 |
.ov-live textarea { flex: 1; min-width: 0; border: none; background: none; font: inherit; font-size: 13px; line-height: 1.45; color: var(--text); outline: none; padding: 2px 0; resize: none; overflow: hidden; max-height: 140px; }
|
| 333 |
.ov-live textarea::placeholder { color: var(--muted); opacity: 0.7; }
|
| 334 |
.ov-hint { font-size: 10.5px; color: var(--muted); flex: none; }
|
| 335 |
+
/* send button — essential on mobile (no Shift+Enter), handy on desktop */
|
| 336 |
+
.ov-send { flex: none; width: 26px; height: 26px; border: none; border-radius: 999px; background: var(--accent); color: var(--accent-fg); font-size: 14px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
|
| 337 |
+
.ov-send:disabled { opacity: 0.5; cursor: default; }
|
| 338 |
.ov-note { font-size: 11px; color: var(--danger); }
|
| 339 |
|
| 340 |
/* tree */
|
|
|
|
| 562 |
.slot.focused .pane-head { background: color-mix(in srgb, var(--accent) 8%, var(--panel)); }
|
| 563 |
|
| 564 |
.term-host { flex: 1; min-height: 0; padding: 10px 8px 8px 12px; background: var(--term-bg); }
|
| 565 |
+
/* mobile control-key bar: the keys a phone keyboard lacks, pinned below the
|
| 566 |
+
terminal so it rides just above the on-screen keyboard */
|
| 567 |
+
.term-keybar { flex: none; display: flex; gap: 5px; padding: 5px 6px; background: var(--panel); border-top: 1px solid var(--border); overflow-x: auto; }
|
| 568 |
+
.tk-btn { flex: 1 0 auto; min-width: 34px; height: 30px; border: 1px solid var(--border-strong); border-radius: var(--r-md); background: var(--panel-2); color: var(--text); font-size: 13px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; user-select: none; -webkit-user-select: none; touch-action: manipulation; }
|
| 569 |
+
.tk-btn:active { background: color-mix(in srgb, var(--accent) 22%, var(--panel-2)); border-color: var(--accent); }
|
| 570 |
.term-host .xterm { height: 100%; }
|
| 571 |
.xterm .xterm-viewport { scrollbar-width: none; }
|
| 572 |
.xterm .xterm-viewport::-webkit-scrollbar { width: 0; height: 0; display: none; }
|
|
|
|
| 816 |
|
| 817 |
/* phones: two full-screen views — the sidebar list, or the selected pane */
|
| 818 |
@media (max-width: 720px) {
|
| 819 |
+
/* Height follows the VISUAL viewport (set by App from window.visualViewport):
|
| 820 |
+
when the on-screen keyboard opens it shrinks the app so the terminal +
|
| 821 |
+
control bar stay above the keyboard instead of hiding behind it. */
|
| 822 |
+
.app { height: var(--vvh, 100dvh); overflow: hidden; }
|
| 823 |
.app.m-home .main { display: none; }
|
| 824 |
.app.m-home .sidebar { width: 100%; border-right: none; }
|
| 825 |
.app.m-stage .sidebar { display: none; }
|