Spaces:
Running on Zero
Running on Zero
CI deploy 02273b10
Browse files- src/ui/shell.py +1 -55
- src/ui/theme.py +2 -6
- tests/test_ui.py +3 -2
src/ui/shell.py
CHANGED
|
@@ -5,8 +5,7 @@ with the design's exact padding and type -- not a Gradio component restyled from
|
|
| 5 |
outside. Gradio still owns the plots and the transport; it no longer owns the
|
| 6 |
chrome.
|
| 7 |
|
| 8 |
-
Values are lifted verbatim from `Backtest Lab.dc.html`: 286px left aside,
|
| 9 |
-
right tray, `8px 12px` header padding, `3px 7px` chips, `4px 6px` segments,
|
| 10 |
`9px 12px` panel headers, `0 12px 12px` section bodies with a 10px gap. The DS
|
| 11 |
utility classes (`mono-data`, `pixel-text`, `styrene-text`) come from base.css
|
| 12 |
and are used rather than reinvented.
|
|
@@ -19,7 +18,6 @@ from .format import EM, count, esc, money, num, pct, sharpe_tone
|
|
| 19 |
|
| 20 |
# Zone widths, straight from the design.
|
| 21 |
LEFT_W = "286px"
|
| 22 |
-
RIGHT_W = "306px"
|
| 23 |
|
| 24 |
# The mark shipped with the design (uploads/bit-trading-mark.svg).
|
| 25 |
MARK = (
|
|
@@ -501,55 +499,3 @@ def frame_to_rows(df, limit=200):
|
|
| 501 |
rows = [[esc("" if v is None else v) for v in rec]
|
| 502 |
for rec in sub.itertuples(index=False, name=None)]
|
| 503 |
return headers, rows
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
# --------------------------------------------------------------------------
|
| 507 |
-
# Right tray -- Run Manager
|
| 508 |
-
# --------------------------------------------------------------------------
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
def run_card(label, meta, sharpe, ret):
|
| 512 |
-
color = sharpe_tone(sharpe)
|
| 513 |
-
return (
|
| 514 |
-
f'<div style="border:1px solid var(--border-subtle);padding:6px 8px;'
|
| 515 |
-
f'margin-bottom:4px;background:var(--bg-panel)">'
|
| 516 |
-
f'<div style="font-size:var(--text-xs);color:var(--text-primary);'
|
| 517 |
-
f'overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{esc(label)}</div>'
|
| 518 |
-
f'<div class="pixel-text" style="color:var(--text-tertiary)">{esc(meta)}</div>'
|
| 519 |
-
f'<div class="mono-data" style="font-size:var(--text-xs);display:flex;'
|
| 520 |
-
f'gap:6px;color:{color}">SHARPE {num(sharpe)}'
|
| 521 |
-
f'<span style="margin-left:auto;color:var(--text-tertiary)">{pct(ret)}</span>'
|
| 522 |
-
f"</div></div>"
|
| 523 |
-
)
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
def right_panel(runs, glossary_items, *, signed_in=False):
|
| 527 |
-
"""The design's 306px tray."""
|
| 528 |
-
if runs:
|
| 529 |
-
history = "".join(run_card(*r) for r in runs[:14])
|
| 530 |
-
else:
|
| 531 |
-
history = micro("no runs yet in this session")
|
| 532 |
-
|
| 533 |
-
gloss = "".join(
|
| 534 |
-
f'<div style="margin-bottom:6px">'
|
| 535 |
-
f'<div class="pixel-text" style="color:var(--text-tertiary)">{esc(t)}</div>'
|
| 536 |
-
f'<div style="font-size:var(--text-2xs);color:var(--text-secondary);'
|
| 537 |
-
f'line-height:1.6">{esc(d)}</div></div>'
|
| 538 |
-
for t, d in glossary_items)
|
| 539 |
-
|
| 540 |
-
def block(title, body):
|
| 541 |
-
return (
|
| 542 |
-
f'<div style="border-bottom:1px solid var(--border-default)">'
|
| 543 |
-
f'<div style="padding:9px 12px;font-family:var(--font-styrene);'
|
| 544 |
-
f"font-size:var(--text-sm);text-transform:uppercase;"
|
| 545 |
-
f'letter-spacing:var(--tracking-wide)">{esc(title)}</div>'
|
| 546 |
-
f'<div style="padding:0 12px 12px">{body}</div></div>')
|
| 547 |
-
|
| 548 |
-
return (
|
| 549 |
-
f'<aside style="width:{RIGHT_W};flex:0 0 {RIGHT_W};'
|
| 550 |
-
f"border-left:1px solid var(--border-default);background:var(--bg-panel);"
|
| 551 |
-
f'display:flex;flex-direction:column">'
|
| 552 |
-
+ block("Run Manager", history)
|
| 553 |
-
+ block("Metrics glossary", gloss)
|
| 554 |
-
+ "</aside>"
|
| 555 |
-
)
|
|
|
|
| 5 |
outside. Gradio still owns the plots and the transport; it no longer owns the
|
| 6 |
chrome.
|
| 7 |
|
| 8 |
+
Values are lifted verbatim from `Backtest Lab.dc.html`: 286px left aside, `8px 12px` header padding, `3px 7px` chips, `4px 6px` segments,
|
|
|
|
| 9 |
`9px 12px` panel headers, `0 12px 12px` section bodies with a 10px gap. The DS
|
| 10 |
utility classes (`mono-data`, `pixel-text`, `styrene-text`) come from base.css
|
| 11 |
and are used rather than reinvented.
|
|
|
|
| 18 |
|
| 19 |
# Zone widths, straight from the design.
|
| 20 |
LEFT_W = "286px"
|
|
|
|
| 21 |
|
| 22 |
# The mark shipped with the design (uploads/bit-trading-mark.svg).
|
| 23 |
MARK = (
|
|
|
|
| 499 |
rows = [[esc("" if v is None else v) for v in rec]
|
| 500 |
for rec in sub.itertuples(index=False, name=None)]
|
| 501 |
return headers, rows
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/ui/theme.py
CHANGED
|
@@ -493,14 +493,10 @@ input:focus, select:focus, textarea:focus{
|
|
| 493 |
flex:0 0 286px !important; width:286px !important; min-width:286px !important;
|
| 494 |
max-width:286px !important; padding:0 !important; gap:0 !important;
|
| 495 |
}
|
| 496 |
-
.bit-zone-right{
|
| 497 |
-
flex:0 0 306px !important; width:306px !important; min-width:306px !important;
|
| 498 |
-
max-width:306px !important; padding:0 !important; gap:0 !important;
|
| 499 |
-
}
|
| 500 |
.bit-zone-center{
|
| 501 |
flex:1 1 auto !important; min-width:0 !important; padding:0 12px !important;
|
| 502 |
}
|
| 503 |
-
.bit-zone-left > *
|
| 504 |
/* The bridge target and trigger must stay in the DOM to receive events, but
|
| 505 |
never show. `visible=False` would remove them from the DOM entirely. */
|
| 506 |
#bit-action, #bit-trigger{
|
|
@@ -510,7 +506,7 @@ input:focus, select:focus, textarea:focus{
|
|
| 510 |
}
|
| 511 |
@media (max-width: 1100px){
|
| 512 |
.bit-zones{ flex-wrap:wrap !important; }
|
| 513 |
-
.bit-zone-left
|
| 514 |
flex:1 1 100% !important; width:100% !important; max-width:100% !important;
|
| 515 |
}
|
| 516 |
}
|
|
|
|
| 493 |
flex:0 0 286px !important; width:286px !important; min-width:286px !important;
|
| 494 |
max-width:286px !important; padding:0 !important; gap:0 !important;
|
| 495 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
.bit-zone-center{
|
| 497 |
flex:1 1 auto !important; min-width:0 !important; padding:0 12px !important;
|
| 498 |
}
|
| 499 |
+
.bit-zone-left > *{ height:100%; }
|
| 500 |
/* The bridge target and trigger must stay in the DOM to receive events, but
|
| 501 |
never show. `visible=False` would remove them from the DOM entirely. */
|
| 502 |
#bit-action, #bit-trigger{
|
|
|
|
| 506 |
}
|
| 507 |
@media (max-width: 1100px){
|
| 508 |
.bit-zones{ flex-wrap:wrap !important; }
|
| 509 |
+
.bit-zone-left{
|
| 510 |
flex:1 1 100% !important; width:100% !important; max-width:100% !important;
|
| 511 |
}
|
| 512 |
}
|
tests/test_ui.py
CHANGED
|
@@ -589,8 +589,9 @@ def test_zone_widths_are_pinned_in_css():
|
|
| 589 |
from src.ui import theme
|
| 590 |
|
| 591 |
css = theme.full_css()
|
| 592 |
-
assert "flex:0 0 286px" in css
|
| 593 |
-
|
|
|
|
| 594 |
|
| 595 |
|
| 596 |
def test_bridge_target_is_hidden_but_present():
|
|
|
|
| 589 |
from src.ui import theme
|
| 590 |
|
| 591 |
css = theme.full_css()
|
| 592 |
+
assert "flex:0 0 286px" in css, "left aside is not pinned to the design width"
|
| 593 |
+
# The right tray was removed; its rules should not linger.
|
| 594 |
+
assert "bit-zone-right" not in css
|
| 595 |
|
| 596 |
|
| 597 |
def test_bridge_target_is_hidden_but_present():
|