Spaces:
Running on Zero
Running on Zero
CI deploy dd2d8bbc
Browse files- src/ui/components.py +14 -1
- src/ui/theme.py +2 -3
- tests/test_ui.py +14 -1
src/ui/components.py
CHANGED
|
@@ -15,6 +15,19 @@ import pandas as pd
|
|
| 15 |
from .. import config
|
| 16 |
from .format import EM, arrow, count, esc, money, num, pct, seg, sharpe_tone, tone
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
# --------------------------------------------------------------------------
|
| 19 |
# Primitives
|
| 20 |
# --------------------------------------------------------------------------
|
|
@@ -61,7 +74,7 @@ def top_bar(status_text: str = "NO RUN LOADED", status_kind: str = "",
|
|
| 61 |
el = f'<span class="bit-micro" style="margin:0 4px">{esc(elapsed)}</span>' if elapsed else ""
|
| 62 |
return f"""
|
| 63 |
<div class="bit-topbar">
|
| 64 |
-
|
| 65 |
<span class="bit-wordmark">BIT</span>
|
| 66 |
<span class="bit-slash">/</span>
|
| 67 |
<span class="bit-h1">Backtest Lab</span>
|
|
|
|
| 15 |
from .. import config
|
| 16 |
from .format import EM, arrow, count, esc, money, num, pct, seg, sharpe_tone, tone
|
| 17 |
|
| 18 |
+
# The actual mark shipped with the design (uploads/bit-trading-mark.svg),
|
| 19 |
+
# inlined so it can be recoloured through a token rather than loaded as a
|
| 20 |
+
# fixed-colour file. Previously this was a CSS box-shadow approximation --
|
| 21 |
+
# a guess at a logo that was sitting in the design folder the whole time.
|
| 22 |
+
MARK_SVG = (
|
| 23 |
+
'<svg class="bit-mark" viewBox="0 0 100 100" role="img" '
|
| 24 |
+
'aria-label="The Bit Trading Company">'
|
| 25 |
+
'<path fill="currentColor" fill-rule="evenodd" '
|
| 26 |
+
'd="M0 0H100V100H0Z M50 10H90V90H50Z M22 42H38V58H22Z M62 42H78V58H62Z">'
|
| 27 |
+
'</path></svg>'
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
# --------------------------------------------------------------------------
|
| 32 |
# Primitives
|
| 33 |
# --------------------------------------------------------------------------
|
|
|
|
| 74 |
el = f'<span class="bit-micro" style="margin:0 4px">{esc(elapsed)}</span>' if elapsed else ""
|
| 75 |
return f"""
|
| 76 |
<div class="bit-topbar">
|
| 77 |
+
{MARK_SVG}
|
| 78 |
<span class="bit-wordmark">BIT</span>
|
| 79 |
<span class="bit-slash">/</span>
|
| 80 |
<span class="bit-h1">Backtest Lab</span>
|
src/ui/theme.py
CHANGED
|
@@ -151,9 +151,8 @@ SHELL_CSS = """
|
|
| 151 |
padding:8px 12px; position:sticky; top:0; z-index:var(--z-header);
|
| 152 |
}
|
| 153 |
.bit-mark{
|
| 154 |
-
width:18px; height:18px;
|
| 155 |
-
|
| 156 |
-
box-shadow:inset 0 0 0 3px var(--bg-panel), inset 0 0 0 5px var(--accent-amber);
|
| 157 |
}
|
| 158 |
.bit-wordmark{
|
| 159 |
font-family:var(--font-heading); font-size:var(--text-md); font-weight:500;
|
|
|
|
| 151 |
padding:8px 12px; position:sticky; top:0; z-index:var(--z-header);
|
| 152 |
}
|
| 153 |
.bit-mark{
|
| 154 |
+
width:18px; height:18px; flex:0 0 18px; display:inline-block;
|
| 155 |
+
color:var(--accent-amber); /* the SVG paths use currentColor */
|
|
|
|
| 156 |
}
|
| 157 |
.bit-wordmark{
|
| 158 |
font-family:var(--font-heading); font-size:var(--text-md); font-weight:500;
|
tests/test_ui.py
CHANGED
|
@@ -404,7 +404,20 @@ def test_every_bit_class_used_in_markup_has_a_css_rule():
|
|
| 404 |
root = Path(__file__).resolve().parent.parent
|
| 405 |
used = set()
|
| 406 |
for rel in ("src/ui/components.py", "src/ui/compare_tab.py", "app.py"):
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
defined = set(re.findall(r"\.(bit-[a-z0-9-]+)", theme.full_css()))
|
| 409 |
missing = sorted(c for c in used if c not in defined and not c.endswith("-"))
|
| 410 |
assert not missing, f"classes used in markup but never styled: {missing}"
|
|
|
|
| 404 |
root = Path(__file__).resolve().parent.parent
|
| 405 |
used = set()
|
| 406 |
for rel in ("src/ui/components.py", "src/ui/compare_tab.py", "app.py"):
|
| 407 |
+
text = (root / rel).read_text()
|
| 408 |
+
# Only real class attributes -- a bare `bit-…` token can appear in a
|
| 409 |
+
# comment or an asset filename and is not a class the page uses.
|
| 410 |
+
for attr in (re.findall(r'class="([^"]*)"', text)
|
| 411 |
+
+ re.findall(r"elem_classes=[\"']([^\"']+)", text)):
|
| 412 |
+
for cls in attr.split():
|
| 413 |
+
if not cls.startswith("bit-"):
|
| 414 |
+
continue
|
| 415 |
+
# Class names are built in f-strings, e.g. `bit-chip{cls}` or
|
| 416 |
+
# `bit-podium-{rank}`. Keep the static prefix; a name that is
|
| 417 |
+
# only a prefix (ends in `-`) has variant rules instead.
|
| 418 |
+
static = cls.split("{", 1)[0]
|
| 419 |
+
if static and not static.endswith("-"):
|
| 420 |
+
used.add(static)
|
| 421 |
defined = set(re.findall(r"\.(bit-[a-z0-9-]+)", theme.full_css()))
|
| 422 |
missing = sorted(c for c in used if c not in defined and not c.endswith("-"))
|
| 423 |
assert not missing, f"classes used in markup but never styled: {missing}"
|