""" Portfolio sidebar widgets — earnings calendar, dividends, news. Split from tab9_portfolio.py to stay under 300-line limit. """ import streamlit as st from data.portfolio import ( get_earnings_calendar, get_dividend_schedule, get_portfolio_news, ) def render_earnings(tickers: tuple): """Earnings calendar widget.""" st.markdown("#### Earnings Calendar") events = get_earnings_calendar(tickers) if not events: st.caption("No upcoming earnings found.") return for ev in events[:8]: d = ev["days_until"] color = "#F87171" if d <= 3 else "#FBBF24" if d <= 7 else "#6B7280" st.markdown( f'
' f'D-{d}' f'
{ev["name"]}' f'
{ev["ticker"]} · {ev["date"]}
' f'
', unsafe_allow_html=True ) def render_dividends(tickers: tuple): """Dividend schedule widget.""" st.markdown("#### Dividend Schedule") divs = get_dividend_schedule(tickers) if not divs: st.caption("No dividend data found.") return for d in divs[:8]: st.markdown( f'
' f'{d["name"]}' f' {d["ticker"]}
' f'Yield: {d["yield_pct"]}' f' · Ex-Date: {d["ex_date"]}' f' · Annual: {d["amount"]}' f'
', unsafe_allow_html=True ) def render_news(tickers: tuple): """Recent news for portfolio stocks.""" st.markdown("#### Portfolio News") news = get_portfolio_news(tickers, max_per_ticker=2) if not news: st.caption("No recent news.") return from datetime import datetime for n in news[:10]: ts = n.get("published", 0) date_str = datetime.fromtimestamp(ts).strftime("%m/%d") if ts else "" link = n.get("link", "#") st.markdown( f'
' f'{n["ticker"]}' f' {n.get("publisher","")} · {date_str}
' f'' f'{n["title"]}
', unsafe_allow_html=True )