From 775762d75bf2b6b49893f84db1f4910ef1aa1e4b Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 16 May 2026 00:51:08 -0700 Subject: Harden script embedding, timezone parsing, and layout buffers - overview: use json_for_script for inline payload/meta to prevent break-out from yfinance-sourced strings; raise iframe height to cover responsive single-column collapse under 1100px - news: treat naive ISO/strptime datetimes as UTC before converting to local-naive, matching the int-timestamp branch from 75dbe29 - news: bump per-row iframe height to fit summary + metadata under scrolling=False - top_movers: drop name column in compact (sidebar) mode and tighten grid so symbol/price/change fit a default-width Streamlit sidebar Co-Authored-By: Claude Opus 4.7 --- components/news.py | 10 ++++++---- components/overview.py | 9 ++++----- components/top_movers.py | 7 +++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/components/news.py b/components/news.py index 2a22b25..c2263c9 100644 --- a/components/news.py +++ b/components/news.py @@ -64,7 +64,7 @@ def _normalize_dt(raw): dt = _dt.fromisoformat(norm) if dt.tzinfo is not None: return dt.astimezone().replace(tzinfo=None) - return dt + return dt.replace(tzinfo=_tz.utc).astimezone().replace(tzinfo=None) except Exception: pass @@ -77,13 +77,15 @@ def _normalize_dt(raw): "%m/%d/%Y", ): try: - return _dt.strptime(text[: len(fmt)], fmt) + naive = _dt.strptime(text[: len(fmt)], fmt) + return naive.replace(tzinfo=_tz.utc).astimezone().replace(tzinfo=None) except Exception: pass if len(text) >= 10: try: - return _dt.strptime(text[:10], "%Y-%m-%d") + naive = _dt.strptime(text[:10], "%Y-%m-%d") + return naive.replace(tzinfo=_tz.utc).astimezone().replace(tzinfo=None) except Exception: pass @@ -167,7 +169,7 @@ def render_news(ticker: str): rows_js = "const NEWS_ROWS=" + _json.dumps(rows).replace("*,*::before,*::after{box-sizing:border-box}" diff --git a/components/overview.py b/components/overview.py index 27c4166..53358f0 100644 --- a/components/overview.py +++ b/components/overview.py @@ -7,6 +7,7 @@ import streamlit as st import streamlit.components.v1 as components from services.data_service import get_company_info, get_latest_price, get_price_history +from utils.security import json_for_script PERIODS = {"1mo": "1M", "3mo": "3M", "6mo": "6M", "1y": "1Y", "5y": "5Y"} SECTOR_ETF_MAP = { @@ -190,8 +191,6 @@ def _comparison_list(ticker: str, info: dict) -> list[dict]: def render_overview(ticker: str): - import json as _json - info = get_company_info(ticker) or {} if not info: st.error("Could not load data for this ticker.") @@ -271,8 +270,8 @@ def render_overview(ticker: str): "default_comparisons": ["^GSPC"], } - payload_js = "const OVERVIEW_DATA=" + _json.dumps(payload) + ";" - meta_js = "const OVERVIEW_META=" + _json.dumps(meta) + ";" + payload_js = "const OVERVIEW_DATA=" + json_for_script(payload) + ";" + meta_js = "const OVERVIEW_META=" + json_for_script(meta) + ";" if price is not None and prev_close is not None and prev_close > 0: chg_pct = (price - prev_close) / prev_close * 100.0 @@ -497,7 +496,7 @@ def render_overview(ticker: str): + "" ) - height = 1480 + height = 1950 # extra ~470px buffer for responsive single-column collapse at <1100px doc = ( "" diff --git a/components/top_movers.py b/components/top_movers.py index fcf64d4..3de53af 100644 --- a/components/top_movers.py +++ b/components/top_movers.py @@ -14,11 +14,12 @@ def _toggle_mover_tab(state_key: str): def _inject_styles(compact: bool = False): row_template = ( - "minmax(60px, 0.95fr) minmax(0, 2.0fr) minmax(74px, 1fr) minmax(86px, 1fr)" + "minmax(48px, 0.9fr) minmax(56px, 1fr) minmax(60px, 1fr)" if compact else "minmax(72px, 0.8fr) minmax(0, 2.6fr) minmax(90px, 1fr) minmax(110px, 1.1fr)" ) - row_gap = "0.45rem" if compact else "0.85rem" + row_gap = "0.3rem" if compact else "0.85rem" + name_display = "none" if compact else "block" row_padding = "0.12rem 0" if compact else "0.18rem 0" symbol_size = "0.75rem" if compact else "0.875rem" name_size = "0.75rem" if compact else "0.8125rem" @@ -48,6 +49,7 @@ def _inject_styles(compact: bool = False): line-height: 1.1; }} .prism-mover-name {{ + display: {name_display}; font-family: 'IBM Plex Sans', sans-serif; color: #8E8676; font-size: {name_size}; @@ -89,6 +91,7 @@ def _inject_styles(compact: bool = False): row_padding=row_padding, symbol_size=symbol_size, name_size=name_size, + name_display=name_display, price_size=price_size, change_size=change_size, change_meta_size=change_meta_size, -- cgit v1.3-2-g0d8e