Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions docs/frontend_architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,8 @@ The application uses a **single-page template** (`index.html`) with tab-based na
┌─────────────────────────────────────────────────────────┐
│ Header (site-header) │
│ ├── Brand (icon + title + subtitle) │
│ └── Ticker Badge (when analysis active) │
├─────────────────────────────────────────────────────────┤
│ Parameters bar [ticker] [Run] (collapse ▸/▾) │ ← sticky, not a tab
│ ├── Parameters bar [ticker] [Run] │ ← not a tab, always visible
│ └── Theme toggle │
├─────────────────────────────────────────────────────────┤
│ Sidebar │ Main Panel │
│ (tab-nav) │ (tab-content) │
Expand All @@ -144,17 +143,17 @@ The application uses a **single-page template** (`index.html`) with tab-based na
└───────────────┴─────────────────────────────────────────┘
```

The **Parameters bar** (`templates/partials/parameters_bar.html`, batch B6) renders
between the header and `.app-body`, is `position: sticky` under the header, and owns
exactly one visible input — `ticker` — plus the Run button and the ticker-validation
badges. Every other parameter lives in its module's toolbar (batch B7); the bar
also carries two hidden `start_time`/`end_time` inputs that `POST /` validates and
uses to size the readiness prefetch, kept in sync by `state/marketParamsState.js`.
It is **not** a tab: it survives tab switches. Collapsing it (the chevron toggle;
state persisted per viewer under `localStorage['parametersBarCollapsed']`, guarded
`try/catch`) hides the `#parameters-bar-body` fields group and the validation line,
leaving the toggle, a one-line `▸ ^SPX` summary, and Run. The chevron is an inline
SVG (Font Awesome is not loaded on this page) rotated by `[data-collapsed]`.
The **Parameters bar** (`templates/partials/parameters_bar.html`, batch B6; folded into
the header post-B10) renders inside `.site-header`, between the brand and the theme
toggle, and owns exactly one visible input — `ticker` — plus the Run button and the
ticker-validation badges. Every other parameter lives in its module's toolbar (batch
B7); the bar also carries two hidden `start_time`/`end_time` inputs that `POST /`
validates and uses to size the readiness prefetch, kept in sync by
`state/marketParamsState.js`. It is **not** a tab: it survives tab switches, and it is
always visible — there is no collapse toggle. Because `.site-header` stays dark in both
themes, the bar's own controls (label, input) use light-on-dark styling rather than the
page's light-theme tokens; the ticker-validation badges and the error alert keep their
own self-contained colors, so they read the same as before.

### Peek Sidebar

Expand Down
85 changes: 0 additions & 85 deletions static/parametersBar.js

This file was deleted.

123 changes: 38 additions & 85 deletions static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ body {
top: 0;
z-index: 200;
background: var(--slate-900);
height: var(--header-h);
min-height: var(--header-h);
display: flex;
align-items: center;
box-shadow: 0 1px 0 rgba(255, 255, 255, .06), var(--shadow-md);
Expand All @@ -159,11 +159,12 @@ body {
width: 100%;
max-width: 1600px;
margin: 0 auto;
padding: 0 1.5rem;
padding: .6rem 1.5rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1rem;
gap: .6rem 1rem;
}

.header-brand {
Expand Down Expand Up @@ -200,29 +201,12 @@ body {
font-weight: 400;
}

.header-badge {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 2px;
}

.badge-ticker {
background: var(--blue);
color: #fff;
padding: 2px 10px;
border-radius: 999px;
font-size: .8rem;
font-weight: 700;
letter-spacing: .04em;
}

.badge-meta {
font-size: .7rem;
color: var(--slate-300);
}

/* ── Header actions (ticker badge + theme toggle) ── */
/* ── Header actions (theme toggle) ── */
.header-actions {
display: flex;
align-items: center;
Expand Down Expand Up @@ -1131,6 +1115,13 @@ body {
.badge-meta {
display: none;
}

/* Brand + theme toggle share the first line; the ticker form (flex-basis
100%) is forced onto its own line below, same as the old separate bar. */
.parameters-bar {
order: 3;
flex-basis: 100%;
}
}

@media (max-width: 480px) {
Expand Down Expand Up @@ -3174,100 +3165,67 @@ textarea:focus-visible,


/* ============================================================
Parameters bar (batch B6) — persistent `ticker` bar above the panes.
Not a tab: it stays put across tab switches (sticky under the header)
and collapses to a one-line summary (`▸ ^SPX`). Tokens only, so the
Onyx override layer below themes it for free.
Parameters bar — the `ticker` input, lives inside the header
(.site-header is dark in both themes, see the Onyx override layer),
so its controls use light-on-dark styling rather than the page's
light-theme tokens. Not a tab: it stays put across tab switches, and
it is always visible — no collapse toggle.
============================================================ */
.parameters-bar {
position: sticky;
top: var(--header-h);
z-index: 100;
display: flex;
flex-direction: column;
gap: 6px;
max-width: 1600px;
margin: 0 auto;
padding: 10px 1.5rem;
background: var(--slate-50);
border-bottom: 1px solid var(--slate-200);
gap: 4px;
flex: 1 1 320px;
min-width: 0;
font-family: var(--font);
}

.parameters-bar-main {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}

.parameters-bar-toggle {
display: inline-flex;
align-items: center;
background: transparent;
border: 1px solid var(--slate-200);
border-radius: var(--radius-sm);
color: var(--slate-700);
cursor: pointer;
padding: 5px 9px;
line-height: 1;
}

.parameters-bar-chevron {
display: block;
transition: transform .15s ease;
}

.parameters-bar[data-collapsed="true"] .parameters-bar-chevron {
transform: rotate(-90deg);
}

/* The collapsible region: label + ticker input + validation badges. */
.parameters-bar-fields {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}

.parameters-bar-label {
color: var(--slate-700);
color: var(--slate-300);
font-size: 12px;
font-weight: 600;
letter-spacing: .02em;
text-transform: uppercase;
}

.parameters-bar-ticker {
flex: 0 1 320px;
min-width: 180px;
flex: 1 1 220px;
min-width: 140px;
max-width: 320px;
padding: 6px 10px;
border: 1px solid var(--slate-200);
border: 1px solid rgb(255 255 255 / .25);
border-radius: var(--radius-sm);
background: rgb(255 255 255 / .08);
color: #fff;
font-family: inherit;
font-size: 14px;
}

.parameters-bar-summary {
color: var(--slate-500);
font-size: 13px;
font-variant-numeric: tabular-nums;
}

/* Collapsed → only the toggle, the one-line summary and Run remain. Expanded →
the input already shows the ticker, so the summary is redundant. */
.parameters-bar[data-collapsed="true"] .parameters-bar-fields,
.parameters-bar[data-collapsed="true"] .ticker-validation {
display: none;
.parameters-bar-ticker::placeholder {
color: var(--slate-400);
}

.parameters-bar[data-collapsed="false"] .parameters-bar-summary {
display: none;
.parameters-bar-ticker:focus {
outline: 2px solid var(--blue);
outline-offset: 1px;
background: rgb(255 255 255 / .12);
}

.parameters-bar-alert {
margin: 0;
}

.parameters-bar .ticker-validation {
color: var(--slate-300);
}

.parameters-bar .btn-primary {
margin-left: auto;
}
Expand Down Expand Up @@ -3417,11 +3375,6 @@ textarea:focus-visible,
border: 1px solid var(--blue-muted);
}

:root:not([data-theme="light"]) .badge-ticker {
background: var(--blue);
color: #0a0a0a;
}

/* All surfaces that were hardcoded #fff → onyx surface-1 */
:root:not([data-theme="light"]) .tab-nav,
:root:not([data-theme="light"]) .form-card,
Expand Down
27 changes: 10 additions & 17 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,18 @@ <h1>Market Dashboard</h1>
<p class="subtitle">Options Strategy &amp; Market Analysis</p>
</div>
</div>

{# The `ticker` input lives in the header now: it is the one input
every data module shares, plus Run and validation feedback. Not
a tab, so it survives tab switches; always visible — no collapse
toggle. Module params moved to the tab toolbars in B7. #}
{% include 'partials/parameters_bar.html' %}

<div class="header-actions">
{% if ticker %}
{# Analysis parameters are per-module now (batch B7): frequency /
horizon / side-bias differ per tab, so there is no single
value to show here. The badge is just the active ticker. #}
<div class="header-badge">
<span class="badge-ticker">{{ ticker }}</span>
</div>
{% endif %}
<!-- Theme toggle: persistent in the top-right on desktop and
mobile (outside the conditional header-badge). Icons show
the CURRENT theme (dark → moon, light → sun; CSS swaps
them per theme), while the aria-label describes the
action. -->
mobile. Icons show the CURRENT theme (dark → moon, light →
sun; CSS swaps them per theme), while the aria-label
describes the action. -->
<button type="button" id="theme-toggle" class="theme-toggle"
aria-label="Switch to light mode" title="Switch to light mode">
<svg class="theme-toggle__sun" viewBox="0 0 24 24" fill="none" stroke="currentColor"
Expand All @@ -135,10 +133,6 @@ <h1>Market Dashboard</h1>
</div>
</header>

{# Persistent Parameters bar (batch B6): above the panes so it survives tab
switches. Owns `ticker` + Run; module params move to the tab toolbars in B7. #}
{% include 'partials/parameters_bar.html' %}

<div class="app-body">
<!-- Sidebar Tab Nav -->
<aside class="sidebar" id="sidebar">
Expand Down Expand Up @@ -266,7 +260,6 @@ <h1>Market Dashboard</h1>
<script src="{{ url_for('static', filename='state/optionFilterState.js') }}"></script>
<script src="{{ url_for('static', filename='moduleParams.js') }}"></script>
<script src="{{ url_for('static', filename='utils.js') }}"></script>
<script src="{{ url_for('static', filename='parametersBar.js') }}"></script>
<script src="{{ url_for('static', filename='theme.js') }}"></script>
<script src="{{ url_for('static', filename='position.js') }}"></script>
<script src="{{ url_for('static', filename='option-chain.js') }}"></script>
Expand Down
Loading
Loading