File size: 5,310 Bytes
f2c0e49
 
 
 
 
 
d70d84b
f2c0e49
d70d84b
 
 
f2c0e49
 
 
 
d70d84b
f2c0e49
 
 
 
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
d70d84b
f2c0e49
 
 
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
d70d84b
f2c0e49
 
 
 
 
 
d70d84b
f2c0e49
 
 
 
 
d70d84b
f2c0e49
 
 
 
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
 
 
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
 
d70d84b
f2c0e49
 
 
 
d70d84b
f2c0e49
d70d84b
 
 
 
 
 
 
 
f2c0e49
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
 
d70d84b
f2c0e49
 
d70d84b
f2c0e49
 
 
 
d70d84b
f2c0e49
 
 
 
 
 
 
d70d84b
f2c0e49
d70d84b
f2c0e49
 
 
 
 
 
 
 
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
d70d84b
f2c0e49
 
 
d70d84b
f2c0e49
 
 
 
 
 
 
d70d84b
f2c0e49
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import streamlit as st
import toml
from pathlib import Path
import os
import time


class ThemeSelector:
    def __init__(
        self, themes_dir=".streamlit/themes", config_path=".streamlit/config.toml"
    ):
        self.themes_dir = Path(themes_dir)
        self.config_path = Path(config_path)
        self.themes = {}
        self.load_themes()

    def load_themes(self):
        """加载所有主题文件"""
        self.themes = {}
        if not self.themes_dir.exists():
            return

        for theme_file in self.themes_dir.glob("*.toml"):
            try:
                theme_data = toml.load(theme_file)

                # 从根级别获取theme_name和theme_poem
                theme_name = theme_data.get("theme_name", theme_file.stem)
                theme_poem = theme_data.get("theme_poem", "")
                theme_config = theme_data.get("theme", {})

                self.themes[theme_name] = {
                    "file": theme_file,
                    "name": theme_name,
                    "poem": theme_poem,
                    "config": theme_config,
                }
            except Exception as e:
                st.warning(f"读取主题文件 {theme_file} 失败: {e}")

    def get_current_theme(self):
        """获取当前主题名称"""
        if not self.config_path.exists():
            return None

        try:
            # config = toml.load(self.config_path)
            # # 从根级别读取theme_name
            # current_theme_name = config.get("theme") or {}
            # current_theme_name = current_theme_name.get("theme_name")
            # return current_theme_name
            theme_toml = self.config_path.parent / "theme.toml"
            theme = toml.load(theme_toml)
            return theme.get("theme_name")

        except Exception:
            return None

    def apply_theme(self, theme_name):
        """应用选定的主题"""
        if theme_name not in self.themes:
            st.error(f"主题 '{theme_name}' 不存在")
            return False

        try:
            # 确保配置目录存在
            self.config_path.parent.mkdir(parents=True, exist_ok=True)

            # 读取现有配置或创建新配置
            config = {}
            if self.config_path.exists():
                try:
                    config = toml.load(self.config_path)
                except Exception:
                    config = {}

            # 添加根级别的theme_name和theme_poem
            # config["theme_name"] = self.themes[theme_name]["name"]
            # config["theme_poem"] = self.themes[theme_name]["poem"]

            # 更新主题配置
            theme_config = self.themes[theme_name]["config"].copy()
            # theme_config["theme_name"] = self.themes[theme_name]["name"]
            # theme_config["theme_poem"] = self.themes[theme_name]["poem"]
            config["theme"] |= theme_config

            # 写入配置文件
            with open(self.config_path, "w", encoding="utf-8") as f:
                toml.dump(config, f)

            theme_toml = self.config_path.parent / "theme.toml"
            with open(theme_toml, "w", encoding="utf-8") as f:
                toml.dump(
                    dict(
                        theme_name=self.themes[theme_name]["name"],
                        theme_poem=self.themes[theme_name]["poem"],
                    ),
                    f,
                )

            return True

        except Exception as e:
            st.error(f"应用主题失败: {e}")
            return False

    def render_theme_selector(self):
        """渲染主题选择器UI"""
        if not self.themes:
            st.warning("未找到可用主题")
            return

        theme_names = list(self.themes.keys())
        current_theme = self.get_current_theme()

        # 确定当前选中的索引
        current_index = 0
        if current_theme and current_theme in theme_names:
            current_index = theme_names.index(current_theme)

        # 主题选择下拉菜单
        selected_theme = st.selectbox(
            "选择主题",
            options=theme_names,
            index=current_index,
            format_func=lambda x: self.themes[x]["name"],
            key="theme_selector_widget",
            label_visibility="collapsed",
        )

        # 如果选择了新主题
        if selected_theme != current_theme:
            if self.apply_theme(selected_theme):
                # 显示主题诗句
                theme_poem = self.themes[selected_theme]["poem"]
                if theme_poem:
                    st.toast(f"✨ {theme_poem}", icon="🎨")
                else:
                    st.toast(f"已切换到主题: {selected_theme}", icon="🎨")

                time.sleep(3)
                # 延迟重新运行以应用主题
                st.rerun()

        return selected_theme


# 全局主题选择器实例
_theme_selector = None


def get_theme_selector():
    """获取全局主题选择器实例"""
    global _theme_selector
    if _theme_selector is None:
        _theme_selector = ThemeSelector()
    return _theme_selector


def render_theme_selector():
    """便捷函数:渲染主题选择器"""
    return get_theme_selector().render_theme_selector()