StockRecommander / theme_config.py
zhengyi
feat: 實現深色模式功能
ba681c7
"""
主題配置模組 - 定義亮色和深色主題的顏色方案
支援 Gradio UI 和 Plotly 圖表的主題切換
"""
# 亮色主題配置
LIGHT_THEME = {
"colors": {
"primary": "#1f77b4", # 主要顏色
"secondary": "#ff7f0e", # 次要顏色
"accent": "#2ca02c", # 強調色
"background": "#ffffff", # 背景色
"surface": "#f8f9fa", # 表面色
"text": "#212529", # 文字色
"text_secondary": "#6c757d", # 次要文字色
"border": "#dee2e6", # 邊框色
"hover": "#e9ecef", # 懸停色
"success": "#28a745", # 成功色
"warning": "#ffc107", # 警告色
"error": "#dc3545", # 錯誤色
},
"name": "light"
}
# 深色主題配置
DARK_THEME = {
"colors": {
"primary": "#4a9eff", # 主要顏色(調整以增加對比度)
"secondary": "#ffb366", # 次要顏色
"accent": "#66dd88", # 強調色
"background": "#1a1a1a", # 背景色
"surface": "#2d2d2d", # 表面色
"text": "#e8e8e8", # 文字色
"text_secondary": "#a0a0a0", # 次要文字色
"border": "#404040", # 邊框色
"hover": "#383838", # 懸停色
"success": "#4ade80", # 成功色
"warning": "#facc15", # 警告色
"error": "#ef4444", # 錯誤色
},
"name": "dark"
}
# 預設主題
DEFAULT_THEME = LIGHT_THEME
def get_theme(theme_name="light"):
"""
根據主題名稱取得主題配置
Args:
theme_name (str): 'light' 或 'dark'
Returns:
dict: 主題配置字典
"""
if theme_name.lower() == "dark":
return DARK_THEME
return LIGHT_THEME
def get_theme_colors(theme_name="light"):
"""
取得指定主題的顏色字典
Args:
theme_name (str): 'light' 或 'dark'
Returns:
dict: 顏色變數字典
"""
theme = get_theme(theme_name)
return theme.get("colors", {})
def create_gradio_theme(theme_name="light"):
"""
建立 Gradio 主題配置物件
Args:
theme_name (str): 'light' 或 'dark'
Returns:
gr.themes.Base: Gradio 主題物件
"""
import gradio as gr
colors = get_theme_colors(theme_name)
if theme_name.lower() == "dark":
return gr.themes.Base(
primary_hue="blue",
secondary_hue="orange",
).set(
body_background_fill=colors["background"],
body_background_fill_secondary=colors["surface"],
border_color_accent=colors["accent"],
border_color_primary=colors["border"],
link_text_color=colors["primary"],
link_text_color_hover=colors["accent"],
link_text_color_visited=colors["secondary"],
)
else:
return gr.themes.Base(
primary_hue="blue",
secondary_hue="orange",
).set(
body_background_fill=colors["background"],
body_background_fill_secondary=colors["surface"],
border_color_accent=colors["accent"],
border_color_primary=colors["border"],
link_text_color=colors["primary"],
link_text_color_hover=colors["accent"],
link_text_color_visited=colors["secondary"],
)
def get_plotly_theme(theme_name="light"):
"""
取得 Plotly 圖表的主題配置
Args:
theme_name (str): 'light' 或 'dark'
Returns:
dict: Plotly 主題參數
"""
colors = get_theme_colors(theme_name)
if theme_name.lower() == "dark":
return {
"template": "plotly_dark",
"paper_bgcolor": colors["background"],
"plot_bgcolor": colors["surface"],
"font": {
"color": colors["text"],
"family": "Arial, sans-serif",
"size": 12
},
"colorway": [
colors["primary"],
colors["secondary"],
colors["accent"],
colors["warning"],
colors["error"],
colors["success"]
]
}
else:
return {
"template": "plotly",
"paper_bgcolor": colors["background"],
"plot_bgcolor": colors["surface"],
"font": {
"color": colors["text"],
"family": "Arial, sans-serif",
"size": 12
},
"colorway": [
colors["primary"],
colors["secondary"],
colors["accent"],
colors["warning"],
colors["error"],
colors["success"]
]
}
def get_default_theme():
"""
取得預設主題(伺服器端預設值)
當 localStorage 不可用時作為備選方案
Returns:
str: 預設主題名稱 ('light')
"""
return "light"
def apply_theme_fallback(theme_name=None):
"""
當 localStorage 或其他機制失敗時的備選方案
Args:
theme_name (str): 試圖套用的主題名稱,為 None 時使用預設
Returns:
str: 實際套用的主題名稱
"""
if theme_name is None or theme_name not in ["light", "dark"]:
return get_default_theme()
return theme_name