Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import base64 | |
| import os | |
| def _logo_b64(size: int) -> str: | |
| logo_path = os.path.join(os.path.dirname(__file__), "..", "logo.png") | |
| logo_path = os.path.normpath(logo_path) | |
| if not os.path.exists(logo_path): | |
| return "" | |
| with open(logo_path, "rb") as f: | |
| data = base64.b64encode(f.read()).decode() | |
| return f'<img src="data:image/png;base64,{data}" width="{size}" height="{size}" style="object-fit:contain;" />' | |
| def _logo_img_tag(size: int) -> str: | |
| tag = _logo_b64(size) | |
| return tag if tag else _logo_svg_fallback(size) | |
| def _logo_svg_fallback(size: int) -> str: | |
| grad_id = "swirl1" if size > 40 else "s1" | |
| grad_id2 = "swirl2" if size > 40 else "s2" | |
| return f"""<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="{size}" height="{size}"> | |
| <defs> | |
| <linearGradient id="{grad_id}" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" stop-color="#9B7FFF"/> | |
| <stop offset="100%" stop-color="#1E148C"/> | |
| </linearGradient> | |
| <linearGradient id="{grad_id2}" x1="100%" y1="0%" x2="0%" y2="100%"> | |
| <stop offset="0%" stop-color="#7C5CE8"/> | |
| <stop offset="100%" stop-color="#120E6B"/> | |
| </linearGradient> | |
| </defs> | |
| <path d="M 52 8 C 82 10 95 38 82 68 C 72 52 62 30 52 8 Z" fill="url(#{grad_id})" opacity="0.95"/> | |
| <path d="M 48 92 C 18 90 5 62 18 32 C 28 48 38 70 48 92 Z" fill="url(#{grad_id2})" opacity="0.90"/> | |
| <path d="M 10 38 C 22 12 52 6 78 22 C 60 28 36 32 10 38 Z" fill="url(#{grad_id})" opacity="0.80"/> | |
| <path d="M 90 62 C 78 88 48 94 22 78 C 40 72 64 68 90 62 Z" fill="url(#{grad_id2})" opacity="0.75"/> | |
| <circle cx="50" cy="50" r="20" fill="white" opacity="0.92"/> | |
| <circle cx="50" cy="50" r="12" fill="white" opacity="0.4"/> | |
| </svg>""" | |
| # Pre-compute at import time | |
| LOGO_SVG = _logo_img_tag(56) | |
| LOGO_SVG_SMALL = _logo_img_tag(36) | |
| def apply_theme(): | |
| st.sidebar.markdown( | |
| f'<div style="padding:16px 8px 12px;border-bottom:1px solid rgba(255,255,255,0.15);' | |
| f'margin-bottom:8px;display:flex;align-items:center;gap:10px;">' | |
| f'{LOGO_SVG_SMALL}' | |
| f'<div><div style="color:white;font-weight:800;font-size:15px;line-height:1.2;">Discovery Lens</div>' | |
| f'<div style="color:rgba(255,255,255,0.65);font-size:10px;">Discovery data is everywhere. <em>Insight isn\'t.</em></div></div>' | |
| f'</div>', | |
| unsafe_allow_html=True, | |
| ) | |
| st.markdown(""" | |
| <style> | |
| /* ββ Page background ββ */ | |
| [data-testid="stAppViewContainer"] > .main { | |
| background-color: #EEEDF6; | |
| } | |
| [data-testid="stHeader"] { | |
| background-color: #EEEDF6; | |
| } | |
| /* ββ Sidebar ββ */ | |
| [data-testid="stSidebar"] { | |
| background-color: #3D2F9E !important; | |
| } | |
| [data-testid="stSidebar"] * { | |
| color: rgba(255,255,255,0.85) !important; | |
| } | |
| [data-testid="stSidebar"] [data-testid="stSidebarNav"] a { | |
| color: rgba(255,255,255,0.75) !important; | |
| border-radius: 6px; | |
| padding: 5px 10px; | |
| } | |
| [data-testid="stSidebar"] [data-testid="stSidebarNav"] a:hover, | |
| [data-testid="stSidebar"] [data-testid="stSidebarNav"] a[aria-current="page"] { | |
| background: rgba(255,255,255,0.15) !important; | |
| color: white !important; | |
| } | |
| [data-testid="stSidebar"] hr { | |
| border-color: rgba(255,255,255,0.2) !important; | |
| } | |
| /* ββ Typography ββ */ | |
| h1, h2, h3, h4 { | |
| color: #26215C !important; | |
| } | |
| /* ββ Primary buttons ββ */ | |
| .stButton > button[kind="primary"] { | |
| background-color: #534AB7 !important; | |
| border-color: #534AB7 !important; | |
| color: white !important; | |
| border-radius: 8px !important; | |
| font-weight: 600 !important; | |
| } | |
| .stButton > button[kind="primary"]:hover { | |
| background-color: #3D2F9E !important; | |
| border-color: #3D2F9E !important; | |
| } | |
| .stButton > button[kind="secondary"] { | |
| border-color: #534AB7 !important; | |
| color: #534AB7 !important; | |
| border-radius: 8px !important; | |
| } | |
| /* ββ Inputs ββ */ | |
| [data-testid="stTextInput"] input, | |
| [data-testid="stTextArea"] textarea { | |
| border-color: #D0CCF0 !important; | |
| border-radius: 8px !important; | |
| background: white !important; | |
| } | |
| [data-testid="stTextInput"] input:focus, | |
| [data-testid="stTextArea"] textarea:focus { | |
| border-color: #534AB7 !important; | |
| box-shadow: 0 0 0 2px rgba(83,74,183,0.15) !important; | |
| } | |
| /* ββ Selectbox ββ */ | |
| [data-testid="stSelectbox"] > div > div { | |
| border-color: #D0CCF0 !important; | |
| border-radius: 8px !important; | |
| background: white !important; | |
| } | |
| /* ββ Expander ββ */ | |
| [data-testid="stExpander"] { | |
| border: 1.5px solid #D0CCF0 !important; | |
| border-radius: 10px !important; | |
| background: white !important; | |
| } | |
| /* ββ Tabs ββ */ | |
| [data-testid="stTabs"] [data-baseweb="tab"] { | |
| color: #534AB7 !important; | |
| font-weight: 600 !important; | |
| } | |
| [data-testid="stTabs"] [data-baseweb="tab"][aria-selected="true"] { | |
| border-bottom-color: #534AB7 !important; | |
| } | |
| /* ββ Download buttons ββ */ | |
| [data-testid="stDownloadButton"] > button { | |
| border-color: #534AB7 !important; | |
| color: #534AB7 !important; | |
| border-radius: 8px !important; | |
| background: white !important; | |
| } | |
| /* ββ Alerts ββ */ | |
| [data-testid="stAlert"][data-type="error"] { | |
| background-color: #FEF0F0 !important; | |
| border-color: #E24B4A !important; | |
| } | |
| [data-testid="stAlert"][data-type="warning"] { | |
| background-color: #FEF8EC !important; | |
| border-color: #EF9F27 !important; | |
| } | |
| [data-testid="stAlert"][data-type="info"] { | |
| background-color: #EEEDFE !important; | |
| border-color: #534AB7 !important; | |
| } | |
| [data-testid="stAlert"][data-type="success"] { | |
| background-color: #F0F7E8 !important; | |
| border-color: #639922 !important; | |
| } | |
| /* ββ Block container ββ */ | |
| .block-container { | |
| padding-top: 3rem !important; | |
| } | |
| /* ββ Sidebar inputs β keep text dark so it's readable on white background ββ */ | |
| [data-testid="stSidebar"] [data-testid="stTextInput"] input, | |
| [data-testid="stSidebar"] [data-testid="stTextArea"] textarea { | |
| color: #26215C !important; | |
| background: white !important; | |
| } | |
| [data-testid="stSidebar"] [data-testid="stSelectbox"] span, | |
| [data-testid="stSidebar"] [data-testid="stSelectbox"] div[data-baseweb="select"] * { | |
| color: #26215C !important; | |
| } | |
| /* ββ Divider ββ */ | |
| hr { | |
| border-color: #D0CCF0 !important; | |
| } | |
| /* ββ Status widget ββ */ | |
| [data-testid="stStatus"] { | |
| border-color: #534AB7 !important; | |
| border-radius: 10px !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |