diff --git a/frontends/desktop/static/app.js b/frontends/desktop/static/app.js
index d5a83a00..897c925e 100644
--- a/frontends/desktop/static/app.js
+++ b/frontends/desktop/static/app.js
@@ -24,7 +24,8 @@ const I18N = {
'ctx.pin': '置顶', 'ctx.unpin': '取消置顶', 'ctx.del': '删除',
'common.close': '关闭', 'common.more': '更多', 'common.optional': '选填',
'modal.preset': '预设功能', 'modal.addModel': '添加模型', 'modal.editModel': '编辑模型', 'modal.settings': '配置',
- 'set.theme': '主题色', 'set.lang': '语言', 'set.model': '模型', 'set.addModel': '添加模型',
+ 'set.appearance': '外观', 'set.plainUi': '素色', 'set.theme': '颜色', 'set.lang': '语言', 'set.model': '模型', 'set.addModel': '添加模型',
+ 'appearance.light': '浅色', 'appearance.dark': '深色',
'set.noModels': '暂无模型,点击下方添加',
'lang.zh': '简体中文', 'lang.en': 'English',
'model.name': '备注', 'model.namePh': '会显示在模型列表',
@@ -35,7 +36,8 @@ const I18N = {
'model.retries': '重试 (次)', 'model.connTimeout': '连接超时 (s)', 'model.readTimeout': '读取超时 (s)',
'model.save': '保存', 'common.cancel': '取消', 'common.edit': '编辑', 'common.delete': '删除',
'err.modelSave': '保存失败', 'err.modelRequired': '请填写模型、API Key 和 API 地址',
- 'err.modelDelete': '删除失败', 'confirm.modelDelete': '确定删除该模型配置?',
+ 'err.modelDelete': '删除失败', 'err.modelDeleteLast': '至少保留一个模型',
+ 'confirm.modelDelete': '确定删除该模型配置?',
'page.channels.title': '消息通道', 'page.channels.sub': '把 hub.pyw 管理的各 imbot 接入搬进来:每行一个渠道',
'page.status.title': '状态面板', 'page.status.sub': 'hub.pyw 管理的后台进程/服务,集中查看与启停',
'page.collab.title': '协作动态', 'page.collab.sub': 'subagent / Hive worker 的实时状态与产出',
@@ -83,7 +85,8 @@ const I18N = {
'ctx.pin': 'Pin', 'ctx.unpin': 'Unpin', 'ctx.del': 'Delete',
'common.close': 'Close', 'common.more': 'More', 'common.optional': 'Optional',
'modal.preset': 'Presets', 'modal.addModel': 'Add model', 'modal.editModel': 'Edit model', 'modal.settings': 'Settings',
- 'set.theme': 'Theme color', 'set.lang': 'Language', 'set.model': 'Model', 'set.addModel': 'Add model',
+ 'set.appearance': 'Appearance', 'set.plainUi': 'Plain', 'set.theme': 'Color', 'set.lang': 'Language', 'set.model': 'Model', 'set.addModel': 'Add model',
+ 'appearance.light': 'Light', 'appearance.dark': 'Dark',
'set.noModels': 'No models yet — add one below',
'lang.zh': '简体中文', 'lang.en': 'English',
'model.name': 'Note', 'model.namePh': 'Shown in the model list',
@@ -94,7 +97,8 @@ const I18N = {
'model.retries': 'Retries (×)', 'model.connTimeout': 'Connect (s)', 'model.readTimeout': 'Read (s)',
'model.save': 'Save', 'common.cancel': 'Cancel', 'common.edit': 'Edit', 'common.delete': 'Delete',
'err.modelSave': 'Save failed', 'err.modelRequired': 'Model, API Key and base URL are required',
- 'err.modelDelete': 'Delete failed', 'confirm.modelDelete': 'Delete this model profile?',
+ 'err.modelDelete': 'Delete failed', 'err.modelDeleteLast': 'At least one model is required',
+ 'confirm.modelDelete': 'Delete this model profile?',
'page.channels.title': 'Channels', 'page.channels.sub': 'imbot channels managed by hub.pyw — one row per channel',
'page.status.title': 'Status', 'page.status.sub': 'Background processes/services managed by hub.pyw',
'page.collab.title': 'Collaboration', 'page.collab.sub': 'Live state & output of subagents / Hive workers',
@@ -125,9 +129,28 @@ const I18N = {
'presetPrompt.mine': 'Collect this week\'s git commits and write a weekly report.',
},
};
-let lang = (localStorage.getItem('ga_lang') === 'en') ? 'en' : 'zh';
+const LANGS = ['zh', 'en'];
+let lang = LANGS.includes(localStorage.getItem('ga_lang')) ? localStorage.getItem('ga_lang') : 'zh';
let theme = localStorage.getItem('ga_theme') || '1';
-const STORE = { lang: 'ga_lang', theme: 'ga_theme', llmNo: 'ga_llm_no' };
+const STORE = { lang: 'ga_lang', theme: 'ga_theme', appearance: 'ga_appearance', plain: 'ga_plain', llmNo: 'ga_llm_no' };
+const APPEARANCE_IDS = ['light', 'dark'];
+const LEGACY_STYLE = { classic: ['light', true], tinted: ['light', false], dark: ['dark', false] };
+
+function migrateAppearance() {
+ let app = localStorage.getItem(STORE.appearance);
+ let plain = localStorage.getItem(STORE.plain) === '1';
+ const legacy = localStorage.getItem('ga_style');
+ if (!app && legacy && LEGACY_STYLE[legacy]) {
+ [app, plain] = LEGACY_STYLE[legacy];
+ localStorage.setItem(STORE.appearance, app);
+ if (plain) localStorage.setItem(STORE.plain, '1');
+ else localStorage.removeItem(STORE.plain);
+ localStorage.removeItem('ga_style');
+ }
+ if (!APPEARANCE_IDS.includes(app)) app = 'light';
+ return { appearance: app, plain: plain && app === 'light' };
+}
+let { appearance, plain: plainUi } = migrateAppearance();
const bridgeHost = () => `${location.protocol}//${location.hostname}:14168`;
async function bridgeFetch(path, opts = {}) {
const headers = { ...(opts.headers || {}) };
@@ -156,26 +179,67 @@ function applyI18n() {
el.setAttribute('placeholder', el.hasAttribute('data-optional-ph') ? optionalPh(phKey) : t(phKey));
});
document.querySelectorAll('[data-i18n-title]').forEach(el => { el.setAttribute('title', t(el.dataset.i18nTitle)); });
- populateLangSelect();
+ renderLangList();
}
-function populateLangSelect() {
- if (!langSel) return;
- langSel.innerHTML = '';
- ['zh', 'en'].forEach(code => {
- const opt = document.createElement('option');
- opt.value = code; opt.textContent = t('lang.' + code);
- langSel.appendChild(opt);
+function renderLangList() {
+ const box = document.getElementById('lang-list');
+ if (!box) return;
+ box.innerHTML = '';
+ LANGS.forEach(code => {
+ const row = document.createElement('label');
+ row.className = 'model-row' + (lang === code ? ' sel' : '');
+ row.innerHTML = `${escapeHtml(t('lang.' + code))}`;
+ row.addEventListener('click', (e) => { e.preventDefault(); selectLang(code); });
+ box.appendChild(row);
});
- langSel.value = lang;
+}
+function selectLang(code) {
+ if (!LANGS.includes(code) || lang === code) return;
+ lang = code;
+ localStorage.setItem(STORE.lang, lang);
+ applyI18n();
+ renderSessionList();
+ refreshStatusLabel();
+ updateModelChip();
+ renderSettingsModels();
}
function applyTheme(id) {
- theme = String(id || '1');
+ const n = parseInt(id, 10);
+ theme = (n >= 1 && n <= 8) ? String(n) : '1';
document.documentElement.dataset.theme = theme;
localStorage.setItem(STORE.theme, theme);
document.querySelectorAll('#theme-swatches .swatch').forEach(el => {
el.classList.toggle('sel', el.dataset.theme === theme);
});
}
+function syncPlainSwitch() {
+ const row = document.getElementById('plain-ui-row');
+ const sw = document.getElementById('plain-ui-switch');
+ if (!row || !sw) return;
+ const show = appearance === 'light';
+ row.hidden = !show;
+ sw.setAttribute('aria-checked', plainUi ? 'true' : 'false');
+}
+function applyAppearance(nextApp, nextPlain) {
+ appearance = APPEARANCE_IDS.includes(nextApp) ? nextApp : 'light';
+ if (appearance === 'light') {
+ plainUi = !!nextPlain;
+ if (plainUi) localStorage.setItem(STORE.plain, '1');
+ else localStorage.removeItem(STORE.plain);
+ } else {
+ plainUi = false;
+ }
+ localStorage.setItem(STORE.appearance, appearance);
+ document.documentElement.dataset.appearance = appearance;
+ if (plainUi) document.documentElement.dataset.plain = '1';
+ else delete document.documentElement.dataset.plain;
+ document.querySelectorAll('#appearance-seg .appear-card').forEach(el => {
+ const on = el.dataset.appearance === appearance;
+ el.classList.toggle('sel', on);
+ el.setAttribute('aria-checked', on ? 'true' : 'false');
+ });
+ syncPlainSwitch();
+}
/* ═══════════════ 侧边栏导航 ═══════════════ */
const nav = document.getElementById('nav');
@@ -324,7 +388,6 @@ bindResize(rpResize, rpPanel, -1, 160, 400); // 右栏:cursor 左移 → 增宽
bindResize(sbResize, sbPanel, +1, 180, 360); // 左栏:cursor 右移 → 增宽
const modelChip = document.getElementById('model-chip');
const modelNameEl= modelChip ? modelChip.querySelector('.model-name') : null;
-const langSel = document.getElementById('lang-select');
let msgsEl = null;
function ensureMsgs() {
@@ -735,7 +798,8 @@ async function deleteModel(id, name) {
}
renderSettingsModels();
} catch (ex) {
- alert(ex.message || t('err.modelDelete'));
+ const msg = ex.message || '';
+ alert(msg.includes('last profile') ? t('err.modelDeleteLast') : (msg || t('err.modelDelete')));
}
}
function renderSettingsModels() {
@@ -767,8 +831,9 @@ function renderSettingsModels() {
function openSettings() {
openModal('settings-modal');
renderSettingsModels();
- populateLangSelect();
+ renderLangList();
applyTheme(theme);
+ applyAppearance(appearance, plainUi);
}
async function loadModelProfiles() {
try {
@@ -801,14 +866,16 @@ if (themeSwatches) themeSwatches.addEventListener('click', (e) => {
const sw = e.target.closest('.swatch[data-theme]');
if (sw) applyTheme(sw.dataset.theme);
});
-if (langSel) langSel.addEventListener('change', () => {
- lang = (langSel.value === 'en') ? 'en' : 'zh';
- localStorage.setItem(STORE.lang, lang);
- applyI18n();
- renderSessionList();
- refreshStatusLabel();
- updateModelChip();
- renderSettingsModels();
+const appearanceSeg = document.getElementById('appearance-seg');
+if (appearanceSeg) appearanceSeg.addEventListener('click', (e) => {
+ const btn = e.target.closest('.appear-card[data-appearance]');
+ if (!btn) return;
+ const isLight = btn.dataset.appearance === 'light';
+ applyAppearance(btn.dataset.appearance, isLight && localStorage.getItem(STORE.plain) === '1');
+});
+const plainUiSwitch = document.getElementById('plain-ui-switch');
+if (plainUiSwitch) plainUiSwitch.addEventListener('click', () => {
+ if (appearance === 'light') applyAppearance('light', !plainUi);
});
async function loadBridgeConfig() {
try {
@@ -1005,6 +1072,7 @@ if(tokResetBtn)tokResetBtn.addEventListener('click',()=>{if(tokSince)tokSince.va
nav.addEventListener('click',(e)=>{const item=e.target.closest('.nav-item');if(item&&item.dataset.page==='token')loadTokenPage();});
/* ═══════════════ 启动 ═══════════════ */
+applyAppearance(appearance, plainUi);
applyTheme(theme);
applyI18n();
updateModelChip();
diff --git a/frontends/desktop/static/index.html b/frontends/desktop/static/index.html
index 7cbff8fe..0f747379 100644
--- a/frontends/desktop/static/index.html
+++ b/frontends/desktop/static/index.html
@@ -6,6 +6,22 @@
+
@@ -337,19 +353,41 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/frontends/desktop/static/styles.css b/frontends/desktop/static/styles.css
index 5b6403d9..5c843687 100644
--- a/frontends/desktop/static/styles.css
+++ b/frontends/desktop/static/styles.css
@@ -5,12 +5,15 @@
:root{
/* —— 基础面 —— */
- --bg:#f4f5f7;
- --panel:#ffffff; /* 三大卡片底 */
- --card:#ffffff; /* 卡片内的小块:pill/列表行/输入/菜单/按钮 */
- --field-bg:#fafbfc; /* 表单输入底 */
- --line:#e9eaee;
- --line-soft:#f0f1f4; /* 浅分隔 / hover 底 */
+ --bg-base:#f4f5f7;
+ --bg:var(--bg-base);
+ --panel:#ffffff;
+ --card:#ffffff;
+ --field-bg:#fafbfc;
+ --line-base:#e9eaee;
+ --line:var(--line-base);
+ --line-soft-base:#f0f1f4;
+ --line-soft:var(--line-soft-base);
--line-strong:#d4d8e0; /* hover 描边 */
--hover-2:#eceef2; /* 次级 hover 底 */
--hover-dim:#0000000f;
@@ -35,12 +38,15 @@
--brand1:#ffb35c;
--brand2:#ff7a59;
- /* —— 配置弹窗:可选主题色板(骨架占位)—— */
+ /* —— 配置弹窗:主题色板(mac 8 色)—— */
--swatch-1:#1f6f53;
--swatch-2:#7c5cff;
- --swatch-3:#2f9e54;
+ --swatch-3:#007aff;
--swatch-4:#ff7a59;
- --swatch-5:#1f2430;
+ --swatch-5:#ff2d55;
+ --swatch-6:#ff3b30;
+ --swatch-7:#ffcc00;
+ --swatch-8:#8e8e93;
/* —— 状态:成功 / 危险 / 关闭 —— */
--ok:#39a85a;
@@ -66,12 +72,78 @@
font-family:-apple-system,"Segoe UI","Microsoft YaHei",system-ui,sans-serif;
}
-/* —— 主题色板(切主题只改 accent 组)—— */
-html[data-theme="1"]{ --blue:var(--swatch-1); --blue-bg:#e7f2ed; --blue-soft:#f1f8f4; }
-html[data-theme="2"]{ --blue:var(--swatch-2); --blue-bg:#f0ecff; --blue-soft:#f7f5ff; }
-html[data-theme="3"]{ --blue:var(--swatch-3); --blue-bg:#e9f7ee; --blue-soft:#f1fbf4; }
-html[data-theme="4"]{ --blue:var(--swatch-4); --blue-bg:#fff0eb; --blue-soft:#fff6f2; }
-html[data-theme="5"]{ --blue:var(--swatch-5); --blue-bg:#eceef2; --blue-soft:#f4f5f7; }
+/* —— 主题色板(素色:仅 accent 浅底)—— */
+html[data-theme="1"]{ --blue:var(--swatch-1); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="2"]{ --blue:var(--swatch-2); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="3"]{ --blue:var(--swatch-3); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="4"]{ --blue:var(--swatch-4); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="5"]{ --blue:var(--swatch-5); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="6"]{ --blue:var(--swatch-6); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); }
+html[data-theme="7"]{ --blue:var(--swatch-7); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); --on-accent:#1f2430; }
+html[data-theme="8"]{ --blue:var(--swatch-8); --blue-bg:color-mix(in srgb, var(--blue) 14%, var(--panel)); --blue-soft:color-mix(in srgb, var(--blue) 7%, var(--panel)); --on-accent:#ffffff; }
+
+/* logo 渐变随主题色 */
+html[data-theme]{
+ --brand1:color-mix(in srgb, var(--blue) 40%, #ffc978);
+ --brand2:var(--blue);
+}
+
+/* —— 外观:浅色(accent 轻 tint 页面/边框)—— */
+html[data-appearance="light"]:not([data-plain="1"])[data-theme]{
+ --blue-bg:color-mix(in srgb, var(--blue) 20%, var(--panel));
+ --blue-soft:color-mix(in srgb, var(--blue) 11%, var(--panel));
+ --bg:color-mix(in srgb, var(--blue) 7%, var(--bg-base));
+ --line:color-mix(in srgb, var(--blue) 16%, var(--line-base));
+ --line-soft:color-mix(in srgb, var(--blue) 10%, var(--line-soft-base));
+}
+
+/* —— 外观:深色 —— */
+html[data-appearance="dark"]{
+ --swatch-7:#ffd60a;
+ --swatch-8:#e6edf3;
+ --bg-base:#0d1117;
+ --bg:#0d1117;
+ --panel:#161b22;
+ --card:#161b22;
+ --field-bg:#0d1117;
+ --line-base:#30363d;
+ --line:#30363d;
+ --line-soft-base:#21262d;
+ --line-soft:#21262d;
+ --line-strong:#484f58;
+ --hover-2:#21262d;
+ --hover-dim:#ffffff0f;
+ --txt:#e6edf3;
+ --txt-strong:#ffffff;
+ --txt-2:#c9d1d9;
+ --txt-3:#afb8c1;
+ --muted:#7d8590;
+ --muted2:#656d76;
+ --placeholder:#484f58;
+ --icon:#7d8590;
+ --off-bg:#21262d;
+ --switch-off:#484f58;
+ --dot-idle:#484f58;
+ --ok:#3fb950;
+ --ok-strong:#46c35a;
+ --ok-bg:#12261e;
+ --ok-ring:#3fb95033;
+ --danger:#f85149;
+ --danger-dot:#f85149;
+ --danger-text:#ff7b72;
+ --danger-bg:#2d1515;
+ --danger-ring:#f8514938;
+ --overlay:#010409a6;
+ --shadow:0 1px 2px #01040966, 0 8px 24px #01040966;
+ --shadow-pop:0 8px 24px #01040999;
+ --shadow-modal:0 18px 50px #010409cc;
+}
+html[data-appearance="dark"][data-theme]{
+ --blue-bg:color-mix(in srgb, var(--blue) 22%, var(--panel));
+ --blue-soft:color-mix(in srgb, var(--blue) 12%, var(--panel));
+}
+html[data-appearance="dark"][data-theme="7"],
+html[data-appearance="dark"][data-theme="8"]{ --on-accent:#0d1117; }
html,body{ height:100%; }
body{ background:var(--bg); color:var(--txt); font-size:13px; overflow:hidden; }
@@ -116,27 +188,103 @@ body{ background:var(--bg); color:var(--txt); font-size:13px; overflow:hidden; }
.modal-body{ flex:1; min-height:340px; overflow:auto; }
/* 配置弹窗内的骨架控件(未实现逻辑)*/
-.set-body{ min-height:0; padding:18px; display:flex; flex-direction:column; gap:20px; }
+.set-body{ min-height:0; padding:18px; display:flex; flex-direction:column; gap:22px; }
+.set-block{ display:flex; flex-direction:column; gap:0; }
.preset-pop{ min-height:0; padding:18px; display:flex; flex-direction:column; gap:14px; }
.set-sec-t{ font-size:12px; font-weight:700; color:var(--txt-2); margin-bottom:10px; }
-.swatches{ display:flex; gap:10px; flex-wrap:wrap; }
+
+/* 外观:mac 式预览卡片 */
+.appear-cards{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
+.appear-card{
+ display:flex; flex-direction:column; align-items:center; gap:8px;
+ padding:10px 8px 9px; border:2px solid var(--line); border-radius:10px;
+ background:var(--field-bg); cursor:pointer; font-family:inherit; transition:.15s;
+}
+.appear-card:hover{ border-color:var(--line-strong); background:var(--line-soft); }
+.appear-card.sel{
+ border-color:var(--blue); background:var(--blue-bg);
+ box-shadow:0 0 0 1px color-mix(in srgb, var(--blue) 25%, transparent);
+}
+.appear-preview{
+ width:100%; height:44px; border-radius:7px; border:1px solid var(--line);
+ position:relative; overflow:hidden;
+}
+.appear-preview-light{
+ background:linear-gradient(180deg, #f4f5f7 0%, #f4f5f7 42%, #ffffff 42%, #ffffff 100%);
+}
+.appear-preview-light::after{
+ content:''; position:absolute; left:10%; top:52%; width:55%; height:7px;
+ border-radius:4px; background:#e9eaee;
+}
+.appear-preview-dark{
+ background:linear-gradient(180deg, #0d1117 0%, #0d1117 42%, #161b22 42%, #161b22 100%);
+ border-color:#30363d;
+}
+.appear-preview-dark::after{
+ content:''; position:absolute; left:10%; top:52%; width:55%; height:7px;
+ border-radius:4px; background:#30363d;
+}
+.appear-name{ font-size:12px; font-weight:600; color:var(--txt-2); }
+.appear-card.sel .appear-name{ color:var(--blue); }
+
+/* 素色:mac/iOS 设置行 + Toggle Switch */
+.set-toggle-row{
+ display:flex; align-items:center; justify-content:space-between; gap:12px;
+ margin-top:10px; padding:10px 12px;
+ border:1px solid var(--line); border-radius:10px; background:var(--field-bg);
+}
+.set-toggle-row[hidden]{ display:none; }
+.set-toggle-label{ font-size:13px; font-weight:600; color:var(--txt-2); }
+.set-switch{
+ position:relative; flex:0 0 auto; width:44px; height:26px;
+ border:none; border-radius:999px; background:var(--switch-off);
+ cursor:pointer; transition:background .2s; padding:0;
+}
+.set-switch[aria-checked="true"]{ background:var(--blue); }
+.set-switch-knob{
+ position:absolute; top:2px; left:2px; width:22px; height:22px;
+ border-radius:50%; background:var(--card);
+ box-shadow:0 1px 3px var(--hover-dim); transition:transform .2s;
+}
+.set-switch[aria-checked="true"] .set-switch-knob{ transform:translateX(18px); }
+.set-switch:focus-visible{ outline:2px solid var(--blue); outline-offset:2px; }
+
+.lang-list{ margin-bottom:0; }
+
+/* 颜色:mac 式 4×2 色盘 */
+.color-grid{
+ display:grid; grid-template-columns:repeat(4, 1fr); gap:12px 10px;
+ justify-items:center; max-width:220px;
+}
.swatch{
- width:26px; height:26px; border-radius:50%; cursor:pointer;
- border:2px solid var(--card); box-shadow:0 0 0 1px var(--line);
+ position:relative; width:32px; height:32px; border-radius:50%; cursor:pointer;
background:var(--swatch-color, var(--swatch-1));
+ border:2px solid color-mix(in srgb, var(--panel) 70%, transparent);
+ box-shadow:0 1px 2px var(--hover-dim);
+ transition:transform .12s, box-shadow .12s;
+}
+.swatch:hover{ transform:scale(1.08); }
+.swatch:focus-visible{ outline:2px solid var(--blue); outline-offset:2px; }
+.swatch.sel{
+ box-shadow:0 0 0 2px var(--panel), 0 0 0 4px var(--blue);
+ transform:scale(1.04);
+}
+.swatch.sel::after{
+ content:''; position:absolute; inset:0; border-radius:50%;
+ background:center/14px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
+}
+html[data-theme="7"] .swatch[data-theme="7"].sel::after,
+html[data-appearance="dark"] .swatch[data-theme="8"].sel::after{
+ background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f2430' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}
-.swatch.sel{ box-shadow:0 0 0 2px var(--blue); }
.swatch[data-theme="1"]{ --swatch-color:var(--swatch-1); }
.swatch[data-theme="2"]{ --swatch-color:var(--swatch-2); }
.swatch[data-theme="3"]{ --swatch-color:var(--swatch-3); }
.swatch[data-theme="4"]{ --swatch-color:var(--swatch-4); }
.swatch[data-theme="5"]{ --swatch-color:var(--swatch-5); }
-.set-select{
- width:100%; border:1px solid var(--line); border-radius:8px; padding:8px 10px;
- font-size:13px; font-family:inherit; background:var(--field-bg); color:var(--txt-2);
- cursor:pointer;
-}
-.set-select:focus{ outline:none; border-color:var(--blue); }
+.swatch[data-theme="6"]{ --swatch-color:var(--swatch-6); }
+.swatch[data-theme="7"]{ --swatch-color:var(--swatch-7); }
+.swatch[data-theme="8"]{ --swatch-color:var(--swatch-8); }
.model-list{ display:flex; flex-direction:column; gap:4px; margin-bottom:10px; max-height:160px; overflow:auto; }
.model-row{
display:flex; align-items:center; gap:10px; padding:8px 10px;
@@ -147,15 +295,19 @@ body{ background:var(--bg); color:var(--txt); font-size:13px; overflow:hidden; }
.model-row.sel{ background:var(--blue-bg); border-color:var(--blue); color:var(--blue); font-weight:600; }
.model-row input{ accent-color:var(--blue); flex:0 0 auto; pointer-events:none; }
.model-row-name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
-.model-row-actions{ display:flex; gap:2px; flex:0 0 auto; opacity:0; transition:opacity .12s; }
-.model-row:hover .model-row-actions, .model-row.sel .model-row-actions{ opacity:1; }
-.model-act{
- width:26px; height:26px; border:none; background:transparent; cursor:pointer;
- color:var(--muted); border-radius:6px; display:flex; align-items:center; justify-content:center; padding:0;
+.model-row-actions{
+ display:flex; gap:2px; flex:0 0 auto; opacity:0; transition:opacity .12s;
}
-.model-act:hover{ background:var(--line-soft); color:var(--txt-2); }
+.model-row:hover .model-row-actions,
+.model-row.sel .model-row-actions{ opacity:1; }
+.model-act{
+ width:28px; height:28px; border:none; background:transparent; cursor:pointer;
+ color:var(--muted); border-radius:6px; display:flex; align-items:center; justify-content:center;
+ padding:0; flex:0 0 auto;
+}
+.model-act:hover{ background:var(--hover-dim); color:var(--txt-2); }
.model-act-del:hover{ color:var(--danger-text); }
-.model-act svg{ width:13px; height:13px; pointer-events:none; }
+.model-act svg{ width:14px; height:14px; pointer-events:none; }
.set-empty{ font-size:12px; color:var(--muted); padding:6px 0; }
.set-btn{
width:100%; display:flex; align-items:center; gap:8px;