feat: 编辑器亮色/暗色主题切换 + 保存到MySQL

- 标题栏🌙/☀️按钮切换 Monaco 主题
- 'vs'(亮色) / 'vs-dark'(暗色)
- 切换后立即应用到所有打开的标签页
- 通过 PUT /api/settings/editor_theme 保存到MySQL
- 页面加载时自动读取保存的主题偏好
- settings.py MUTABLE_KEYS 白名单加 editor_theme
This commit is contained in:
Your Name
2026-05-31 02:39:21 +08:00
parent ae47eb42de
commit e65c9993a2
2 changed files with 26 additions and 1 deletions
+1
View File
@@ -45,6 +45,7 @@ MUTABLE_KEYS: set[str] = {
"notify_alert_cpu", "notify_alert_mem", "notify_alert_disk", "notify_alert_cpu", "notify_alert_mem", "notify_alert_disk",
"notify_recovery", "notify_time_drift", "notify_recovery", "notify_time_drift",
"notify_system_redis", "notify_system_mysql", "notify_restart", "notify_system_redis", "notify_system_mysql", "notify_restart",
"editor_theme", # Monaco editor theme preference
} }
# S-02: Per-key validation rules: (type, min, max) for int settings # S-02: Per-key validation rules: (type, min, max) for int settings
+25 -1
View File
@@ -71,6 +71,7 @@
<div id="editorTabBar" class="flex flex-1 overflow-x-auto min-w-0"></div> <div id="editorTabBar" class="flex flex-1 overflow-x-auto min-w-0"></div>
<!-- Right buttons --> <!-- Right buttons -->
<div class="flex items-center shrink-0"> <div class="flex items-center shrink-0">
<button onclick="toggleEditorTheme()" id="themeBtn" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="切换亮色/暗色主题">🌙</button>
<button onclick="toggleEditorSize()" id="sizeBtn" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="最大化/还原"></button> <button onclick="toggleEditorSize()" id="sizeBtn" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="最大化/还原"></button>
<button onclick="toggleEditorFullscreen()" id="fsBtn" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="全屏"></button> <button onclick="toggleEditorFullscreen()" id="fsBtn" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="全屏"></button>
<button onclick="minimizeEditor()" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="最小化"></button> <button onclick="minimizeEditor()" class="text-slate-500 hover:text-white px-2 py-2 text-sm hover:bg-slate-700" title="最小化"></button>
@@ -636,6 +637,29 @@
let _activeTab=-1; let _activeTab=-1;
let _editorVisible=false; let _editorVisible=false;
let _editorMinimized=false; let _editorMinimized=false;
let _editorTheme='vs'; // 'vs' (light) or 'vs-dark' (dark)
// Load editor theme from settings
async function loadEditorTheme(){
try{
const r=await apiFetch(API+'/settings/editor_theme');
if(r&&r.ok){const d=await r.json();if(d.value&&d.value!=='null')_editorTheme=d.value}
}catch(e){}
updateThemeBtn();
}
loadEditorTheme();
function updateThemeBtn(){
const btn=document.getElementById('themeBtn');
if(btn)btn.textContent=_editorTheme==='vs-dark'?'🌙':'☀️';
}
function toggleEditorTheme(){
_editorTheme=_editorTheme==='vs'?'vs-dark':'vs';
_openTabs.forEach(t=>{if(t.editor)t.editor.updateOptions({theme:_editorTheme})});
updateThemeBtn();
apiFetch(API+'/settings/editor_theme',{method:'PUT',headers:apiHeadersJSON(),body:JSON.stringify({value:_editorTheme})});
}
function openFileInEditor(path,name,content){ function openFileInEditor(path,name,content){
// Check if already open // Check if already open
@@ -654,7 +678,7 @@
if(window._monacoReady){ if(window._monacoReady){
tab.editor=monaco.editor.create(container,{ tab.editor=monaco.editor.create(container,{
value:content,language:lang, value:content,language:lang,
// 官方默认配置 — 不匹配项目主题 theme:_editorTheme,
automaticLayout:true, automaticLayout:true,
lineNumbers:'on',folding:true, lineNumbers:'on',folding:true,
bracketPairColorization:{enabled:true},matchBrackets:'always', bracketPairColorization:{enabled:true},matchBrackets:'always',