125 lines
7.7 KiB
Python
125 lines
7.7 KiB
Python
"""Shared, intentionally small Streamlit presentation primitives."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from html import escape
|
|
from typing import Any
|
|
|
|
from .profile import AppProfile
|
|
|
|
|
|
def apply_console_theme(st: Any, profile: AppProfile) -> None:
|
|
"""Apply one predictable light theme from the product profile."""
|
|
|
|
st.markdown(
|
|
f"""
|
|
<style>
|
|
:root {{ color-scheme: light !important; --console-primary: {escape(profile.primary_color)};
|
|
--console-text: {escape(profile.text_color)}; --console-muted: {escape(profile.muted_color)};
|
|
--console-border: {escape(profile.border_color)}; }}
|
|
html, body, [data-testid="stAppViewContainer"], .stApp {{ background:#fff !important;
|
|
color:var(--console-text) !important; color-scheme:light !important;
|
|
font-family:"Noto Sans KR","Malgun Gothic",sans-serif; }}
|
|
header[data-testid="stHeader"] {{ display:none !important; }}
|
|
.block-container {{ max-width:1180px; padding:2rem 3rem 4rem; }}
|
|
section[data-testid="stSidebar"], section[data-testid="stSidebar"] > div {{ background:#fff !important; }}
|
|
section[data-testid="stSidebar"] {{ border-right:1px solid var(--console-border); }}
|
|
[data-testid="stAppViewContainer"] p, [data-testid="stAppViewContainer"] span,
|
|
[data-testid="stAppViewContainer"] label, [data-testid="stAppViewContainer"] h1,
|
|
[data-testid="stAppViewContainer"] h2, [data-testid="stAppViewContainer"] h3,
|
|
[data-testid="stAppViewContainer"] li, [data-testid="stAppViewContainer"] dt,
|
|
[data-testid="stAppViewContainer"] dd, [data-testid="stAppViewContainer"] blockquote,
|
|
[data-testid="stAppViewContainer"] input, [data-testid="stAppViewContainer"] textarea,
|
|
section[data-testid="stSidebar"] * {{ color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important; }}
|
|
input, textarea, [data-baseweb="select"] > div, [data-testid="stSidebar"] button {{
|
|
background:#fff !important; border:1px solid var(--console-border) !important;
|
|
border-radius:4px !important; box-shadow:none !important; }}
|
|
div[data-testid="stButton"] > button, div[data-testid="stFormSubmitButton"] > button {{
|
|
background:#fff !important; color:var(--console-text) !important;
|
|
border:1px solid var(--console-border) !important;
|
|
border-radius:4px !important; box-shadow:none !important; }}
|
|
div[data-testid="stButton"] > button *,
|
|
div[data-testid="stFormSubmitButton"] > button * {{
|
|
color:var(--console-text) !important; -webkit-text-fill-color:var(--console-text) !important; }}
|
|
div[data-testid="stButton"] > button[kind="primary"],
|
|
div[data-testid="stFormSubmitButton"] > button[data-testid="stBaseButton-primaryFormSubmit"] {{
|
|
background:var(--console-primary) !important; border-color:var(--console-primary) !important; color:#fff !important; }}
|
|
div[data-testid="stButton"] > button[kind="primary"] *,
|
|
div[data-testid="stFormSubmitButton"] > button[data-testid="stBaseButton-primaryFormSubmit"] * {{
|
|
color:#fff !important; -webkit-text-fill-color:#fff !important; }}
|
|
/* Streamlit JSON/code components otherwise retain a dark-surface theme while
|
|
the console text is forced dark, making MCP details unreadable. */
|
|
[data-testid="stJson"], [data-testid="stJson"] > div,
|
|
[data-testid="stCodeBlock"], [data-testid="stCodeBlock"] > div,
|
|
[data-testid="stCode"], [data-testid="stCode"] > div {{
|
|
background:#f6f8fa !important; color:var(--console-text) !important;
|
|
border-color:var(--console-border) !important; }}
|
|
[data-testid="stJson"] *, [data-testid="stCodeBlock"] *, [data-testid="stCode"] *,
|
|
[data-testid="stJson"] pre, [data-testid="stCodeBlock"] pre, [data-testid="stCode"] pre {{
|
|
color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important; }}
|
|
[data-testid="stJson"] button, [data-testid="stCodeBlock"] button, [data-testid="stCode"] button {{
|
|
background:#fff !important; border-color:var(--console-border) !important; }}
|
|
[data-testid="stExpander"] summary {{
|
|
background:#f6f8fa !important; color:var(--console-text) !important;
|
|
border-color:var(--console-border) !important; }}
|
|
[data-testid="stExpander"] summary * {{
|
|
color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important; }}
|
|
[data-baseweb="tab-list"], [data-testid="stTabs"] [role="tablist"] {{
|
|
border-bottom:1px solid var(--console-border) !important; }}
|
|
[data-baseweb="tab-list"] [role="tab"], [data-testid="stTab"] {{
|
|
background:#fff !important; color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important;
|
|
border-radius:4px 4px 0 0 !important; }}
|
|
[data-baseweb="tab-list"] [role="tab"] *, [data-testid="stTab"] * {{
|
|
color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important; }}
|
|
[data-baseweb="tab-list"] [role="tab"]:hover, [data-testid="stTab"]:hover {{
|
|
background:#f6f8fa !important; }}
|
|
[data-baseweb="tab-list"] [role="tab"][aria-selected="true"],
|
|
[data-testid="stTab"][aria-selected="true"] {{
|
|
color:var(--console-primary) !important;
|
|
-webkit-text-fill-color:var(--console-primary) !important;
|
|
border-bottom:3px solid var(--console-primary) !important; }}
|
|
[data-baseweb="tab-list"] [role="tab"][aria-selected="true"] *,
|
|
[data-testid="stTab"][aria-selected="true"] * {{
|
|
color:var(--console-primary) !important;
|
|
-webkit-text-fill-color:var(--console-primary) !important; }}
|
|
.console-header {{ margin:0 0 28px; padding:0 0 22px; border-bottom:1px solid var(--console-border); }}
|
|
.console-wordmark {{ color:var(--console-primary); font-size:1.35rem; font-weight:800; letter-spacing:.08em; }}
|
|
.console-header h1 {{ margin:10px 0 8px; font-size:1.7rem; }}
|
|
.console-muted {{ color:var(--console-muted) !important; }}
|
|
.st-key-console_login_container {{ max-width:440px; margin:12vh auto 0; }}
|
|
.console-login {{ text-align:left; }}
|
|
.console-login h1 {{ margin:12px 0 8px; font-size:1.7rem; }}
|
|
a.console-logout-button {{ display:block; width:100%; padding:.55rem .8rem;
|
|
margin:.25rem 0 .75rem; background:#fff; color:var(--console-text) !important;
|
|
-webkit-text-fill-color:var(--console-text) !important;
|
|
border:1px solid var(--console-border); border-radius:4px;
|
|
text-align:center; text-decoration:none; font-weight:700; }}
|
|
a.console-logout-button:hover {{ background:#f6f8fa; }}
|
|
@media (max-width:760px) {{ .block-container {{ padding:1.25rem 1.25rem 3rem; }} .st-key-console_login_container {{ margin-top:8vh; }} }}
|
|
</style>
|
|
""",
|
|
unsafe_allow_html=True,
|
|
)
|
|
|
|
|
|
def render_console_header(st: Any, profile: AppProfile) -> None:
|
|
st.markdown(
|
|
f"""<section class="console-header"><div class="console-wordmark">{escape(profile.short_name)}</div>
|
|
<h1>{escape(profile.header_title)}</h1><p class="console-muted">{escape(profile.header_description)}</p></section>""",
|
|
unsafe_allow_html=True,
|
|
)
|
|
|
|
|
|
def render_login_brand(st: Any, profile: AppProfile) -> None:
|
|
st.markdown(
|
|
f"""<section class="console-login"><div class="console-wordmark">{escape(profile.short_name)}</div>
|
|
<p class="console-muted">{escape(profile.login_kicker)}</p><h1>{escape(profile.login_title)}</h1>
|
|
<p class="console-muted">{escape(profile.login_description)}</p></section>""",
|
|
unsafe_allow_html=True,
|
|
)
|