aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler <tyler@tylerhoang.xyz>2026-05-17 02:35:16 -0700
committerTyler <tyler@tylerhoang.xyz>2026-05-17 02:35:16 -0700
commit119eaf8afe9924ce0e5eef62f4a1546caf0c4bab (patch)
treeeb20074326e517f07d065ac7832726213990ebd4
parent811fb970ac87c6f9e78e24889011623f097041a5 (diff)
Move ticker search to top bar
-rw-r--r--app.py206
1 files changed, 163 insertions, 43 deletions
diff --git a/app.py b/app.py
index 87a6716..c17dbcb 100644
--- a/app.py
+++ b/app.py
@@ -220,11 +220,96 @@ button[kind="secondary"]:hover {
padding-bottom: 3rem !important;
}
-/* ── Sticky market bar ──────────────────────────────────────────────────── */
-.st-key-market_bar_sticky {
+/* ── Sticky top bar / market bar ────────────────────────────────────────── */
+.st-key-prism_topbar_sticky {
position: sticky !important;
top: 0 !important;
- z-index: 200 !important;
+ z-index: 260 !important;
+ background: var(--ink-0) !important;
+ border-bottom: 1px solid var(--line-1) !important;
+ margin-top: -0.5rem !important;
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+}
+
+.st-key-prism_topbar_sticky [data-testid="stHorizontalBlock"] {
+ align-items: end;
+ gap: var(--sp-3);
+}
+
+.st-key-prism_topbar_sticky .stTextInput,
+.st-key-prism_topbar_sticky [data-testid="stSelectbox"],
+.st-key-prism_topbar_sticky [data-testid="stButton"] {
+ margin-bottom: 0 !important;
+}
+
+.st-key-prism_topbar_sticky .stTextInput label,
+.st-key-prism_topbar_sticky [data-testid="stSelectbox"] label {
+ display: none !important;
+}
+
+.st-key-prism_topbar_sticky .stTextInput input {
+ min-height: 36px !important;
+ background: var(--ink-2) !important;
+ border: 1px solid var(--line-2) !important;
+ border-radius: var(--r-2) !important;
+ color: var(--fg-1) !important;
+ font-family: var(--font-mono) !important;
+ font-size: var(--fs-13) !important;
+ padding-left: 34px !important;
+ padding-right: 60px !important;
+}
+
+.st-key-prism_topbar_sticky .stTextInput input::placeholder {
+ color: var(--fg-3) !important;
+}
+
+.st-key-prism_topbar_sticky .stTextInput input:focus {
+ border-color: var(--brass) !important;
+ box-shadow: none !important;
+}
+
+.st-key-prism_topbar_sticky .stTextInput:has(input[aria-label="Global ticker search"]) {
+ position: relative;
+}
+
+.st-key-prism_topbar_sticky .stTextInput:has(input[aria-label="Global ticker search"])::before {
+ content: "⌕";
+ position: absolute;
+ left: 12px;
+ bottom: 8px;
+ z-index: 5;
+ pointer-events: none;
+ font-family: var(--font-mono);
+ font-size: 18px;
+ color: var(--fg-3);
+ line-height: 1;
+}
+
+.st-key-prism_topbar_sticky .stTextInput:has(input[aria-label="Global ticker search"])::after {
+ content: "⌘ K";
+ position: absolute;
+ right: 10px;
+ bottom: 8px;
+ z-index: 5;
+ pointer-events: none;
+ font-family: var(--font-mono);
+ font-size: var(--fs-12);
+ color: var(--fg-3);
+ border: 1px solid var(--line-2);
+ padding: 1px 6px;
+ border-radius: var(--r-1);
+ background: var(--ink-1);
+}
+
+.psm-top-spacer {
+ min-height: 36px;
+}
+
+.st-key-market_bar_sticky {
+ position: sticky !important;
+ top: 52px !important;
+ z-index: 240 !important;
background: var(--ink-0) !important;
padding-bottom: 0.5rem !important;
margin-bottom: -0.5rem !important;
@@ -630,6 +715,21 @@ if "active_tab" not in st.session_state:
render_persistence_bridge()
+
+def open_topbar_search():
+ query = st.session_state.get("topbar_search_query", "").strip()
+ if not query:
+ return
+
+ results = search_tickers(query)
+ if results:
+ st.session_state["ticker"] = results[0]["symbol"]
+ else:
+ st.session_state["ticker"] = query.upper()
+
+
+ticker = st.session_state["ticker"]
+
# ── Sidebar ───────────────────────────────────────────────────────────────────
with st.sidebar:
@@ -706,34 +806,6 @@ with st.sidebar:
)
components.html(_clock_html, height=32, scrolling=False)
- with st.form("ticker_search_form", clear_on_submit=False):
- query = st.text_input(
- "Ticker or company",
- placeholder="AAPL, Apple, MSFT…",
- key="search_query",
- ).strip()
-
- results = search_tickers(query) if query else []
- selected_symbol = None
-
- if results:
- options = {f"{r['symbol']} — {r['name']} ({r['exchange']})": r["symbol"] for r in results}
- choice = st.selectbox(
- "Matches",
- options=list(options.keys()),
- label_visibility="collapsed",
- )
- selected_symbol = options[choice]
- elif query:
- selected_symbol = query.upper()
-
- submitted = st.form_submit_button("Open", width="stretch", type="primary")
-
- if submitted and selected_symbol:
- st.session_state["ticker"] = selected_symbol
-
- ticker = st.session_state["ticker"]
-
# ── Exit to landing page ──────────────────────────────────────────────
if st.session_state.get("ticker"):
if st.button("← Watchlist", key="exit_ticker", use_container_width=True):
@@ -784,29 +856,77 @@ with st.sidebar:
render_top_movers(True)
-# ── Market Bar ────────────────────────────────────────────────────────────────
+# ── Sticky Top Bar + Market Bar ───────────────────────────────────────────────
+
+with st.container(key="prism_topbar_sticky"):
+ _search_col, _match_col, _open_col = st.columns([3.2, 2.3, 0.7], vertical_alignment="bottom")
+ with _search_col:
+ _topbar_query = st.text_input(
+ "Global ticker search",
+ placeholder="Search ticker, company, or filing…",
+ key="topbar_search_query",
+ on_change=open_topbar_search,
+ ).strip()
+
+ _topbar_results = search_tickers(_topbar_query) if _topbar_query else []
+ _topbar_selected_symbol = _topbar_query.upper() if _topbar_query else None
+
+ with _match_col:
+ if _topbar_results:
+ _topbar_options = {
+ r["symbol"] + " — " + r["name"] + " (" + r["exchange"] + ")": r["symbol"]
+ for r in _topbar_results
+ }
+ _topbar_choice = st.selectbox(
+ "Matches",
+ options=list(_topbar_options.keys()),
+ key="topbar_search_match",
+ label_visibility="collapsed",
+ )
+ _topbar_selected_symbol = _topbar_options[_topbar_choice]
+ else:
+ st.markdown("<div class='psm-top-spacer'></div>", unsafe_allow_html=True)
+
+ with _open_col:
+ if st.button("Open", key="topbar_search_open", use_container_width=True, type="primary"):
+ if _topbar_selected_symbol:
+ st.session_state["ticker"] = _topbar_selected_symbol
+ st.rerun()
+
+ticker = st.session_state["ticker"]
with st.container(key="market_bar_sticky"):
render_market_bar()
st.divider()
-# ── ⌘K / Ctrl+K shortcut — focuses sidebar ticker search ─────────────────────
+# ── ⌘K / Ctrl+K shortcut — focuses top-bar ticker search ─────────────────────
components.html(
"<script>"
- "document.addEventListener('keydown', function(e) {"
- " if (e.key === '/' && !e.metaKey && !e.ctrlKey && !e.altKey"
- " && document.activeElement.tagName !== 'INPUT'"
- " && document.activeElement.tagName !== 'TEXTAREA') {"
- " var inputs = window.parent.document.querySelectorAll('input');"
+ "(function() {"
+ " var placeholder = 'Search ticker, company, or filing…';"
+ " var doc = window.parent && window.parent.document ? window.parent.document : document;"
+ " if (doc.__prismTopbarFocusVersion === 1) { return; }"
+ " doc.__prismTopbarFocusVersion = 1;"
+ " function findSearchInput() {"
+ " var inputs = doc.querySelectorAll('input');"
" for (var i = 0; i < inputs.length; i++) {"
- " if (inputs[i].placeholder && inputs[i].placeholder.indexOf('AAPL') > -1) {"
+ " if (inputs[i].placeholder === placeholder) { return inputs[i]; }"
+ " }"
+ " return null;"
+ " }"
+ " doc.addEventListener('keydown', function(e) {"
+ " var key = e.key ? e.key.toLowerCase() : '';"
+ " if (key === 'k' && (e.metaKey || e.ctrlKey)) {"
+ " var input = findSearchInput();"
+ " if (input) {"
" e.preventDefault();"
- " inputs[i].focus(); inputs[i].select(); break;"
+ " input.focus();"
+ " input.select();"
" }"
" }"
- " }"
- "});"
+ " }, true);"
+ "}());"
"</script>",
height=0,
scrolling=False,
@@ -839,7 +959,7 @@ if not ticker:
font-family:'IBM Plex Sans',sans-serif;
font-size:0.875rem;color:#5E5849;
letter-spacing:0.01em;
- ">Enter a company name or symbol in the sidebar.</div>
+ ">Enter a company name or symbol in the top search bar.</div>
</div>
""", unsafe_allow_html=True)
st.stop()