auto-save 2026-05-11 17:04 (~4)
This commit is contained in:
@@ -1,12 +1,5 @@
|
|||||||
{
|
{
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
|
||||||
"files_changed": 1,
|
|
||||||
"hash": "3b0d2b2",
|
|
||||||
"message": "auto-save 2026-05-10 08:27 (~1)",
|
|
||||||
"ts": "2026-05-10T08:27:21+08:00",
|
|
||||||
"type": "commit"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"files_changed": 1,
|
"files_changed": 1,
|
||||||
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-10 08:27 (~1)",
|
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-10 08:27 (~1)",
|
||||||
@@ -3263,6 +3256,13 @@
|
|||||||
"type": "session-heartbeat",
|
"type": "session-heartbeat",
|
||||||
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 3 项未提交变更 · 最近提交:auto-save 2026-05-11 16:53 (~2)",
|
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 3 项未提交变更 · 最近提交:auto-save 2026-05-11 16:53 (~2)",
|
||||||
"files_changed": 3
|
"files_changed": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-11T16:59:20+08:00",
|
||||||
|
"type": "commit",
|
||||||
|
"message": "auto-save 2026-05-11 16:59 (~3)",
|
||||||
|
"hash": "7a150ae",
|
||||||
|
"files_changed": 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
184
src/app.js
184
src/app.js
@@ -1026,6 +1026,184 @@ async function refreshUiConfig(options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function modelProfileCard(profile) {
|
||||||
|
const defaultBadge = profile.isDefault ? '<span class="model-profile-badge">默认</span>' : "";
|
||||||
|
const disabledBadge = profile.enabled ? "" : '<span class="model-profile-badge off">停用</span>';
|
||||||
|
return `
|
||||||
|
<div class="model-profile-card ${profile.isDefault ? "active" : ""}">
|
||||||
|
<div class="model-profile-main">
|
||||||
|
<div class="model-profile-name">${escapeHTML(profile.name)}${defaultBadge}${disabledBadge}</div>
|
||||||
|
<div class="model-profile-model">${escapeHTML(profile.model)}</div>
|
||||||
|
<div class="model-profile-meta">
|
||||||
|
<span>${escapeHTML(profile.provider || "auto")}</span>
|
||||||
|
${profile.baseUrl ? `<span>${escapeHTML(profile.baseUrl)}</span>` : ""}
|
||||||
|
${profile.apiKeyRef ? `<span>${escapeHTML(profile.apiKeyRef)}</span>` : ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="model-profile-actions">
|
||||||
|
<button type="button" onclick="editModelProfile('${escapeHTML(profile.id)}')">编辑</button>
|
||||||
|
<button type="button" onclick="makeModelProfileDefault('${escapeHTML(profile.id)}')">设默认</button>
|
||||||
|
<button type="button" onclick="applyModelProfileToRuntime('${escapeHTML(profile.id)}')">应用到运行配置</button>
|
||||||
|
<button type="button" class="danger" onclick="deleteModelProfile('${escapeHTML(profile.id)}')">删除</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderModelProfiles() {
|
||||||
|
state.modelProfiles = normalizeModelProfiles(state.modelProfiles);
|
||||||
|
const list = document.getElementById("modelProfilesList");
|
||||||
|
if (list) {
|
||||||
|
list.innerHTML = state.modelProfiles.map(modelProfileCard).join("");
|
||||||
|
}
|
||||||
|
const active = activeModelProfile();
|
||||||
|
const count = document.getElementById("modelProfilesCount");
|
||||||
|
if (count) count.textContent = `${state.modelProfiles.length} 个模型 Profile · 默认 ${active?.name || "未设置"}`;
|
||||||
|
renderAgentModelProfileOptions(document.getElementById("agentModelProfile")?.value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearModelProfileForm() {
|
||||||
|
state.editingModelProfileId = null;
|
||||||
|
const fields = {
|
||||||
|
modelProfileName: "",
|
||||||
|
modelProfileProvider: "openrouter",
|
||||||
|
modelProfileModel: "",
|
||||||
|
modelProfileBaseUrl: "",
|
||||||
|
modelProfileApiKeyRef: "",
|
||||||
|
};
|
||||||
|
for (const [id, value] of Object.entries(fields)) {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (el) el.value = value;
|
||||||
|
}
|
||||||
|
const enabled = document.getElementById("modelProfileEnabled");
|
||||||
|
const isDefault = document.getElementById("modelProfileDefault");
|
||||||
|
if (enabled) enabled.checked = true;
|
||||||
|
if (isDefault) isDefault.checked = false;
|
||||||
|
const title = document.getElementById("modelProfileFormTitle");
|
||||||
|
if (title) title.textContent = "新增模型 Profile";
|
||||||
|
}
|
||||||
|
|
||||||
|
function editModelProfile(id) {
|
||||||
|
const profile = modelProfileById(id);
|
||||||
|
if (!profile) return;
|
||||||
|
state.editingModelProfileId = id;
|
||||||
|
const values = {
|
||||||
|
modelProfileName: profile.name,
|
||||||
|
modelProfileProvider: profile.provider,
|
||||||
|
modelProfileModel: profile.model,
|
||||||
|
modelProfileBaseUrl: profile.baseUrl,
|
||||||
|
modelProfileApiKeyRef: profile.apiKeyRef,
|
||||||
|
};
|
||||||
|
for (const [fieldId, value] of Object.entries(values)) {
|
||||||
|
const el = document.getElementById(fieldId);
|
||||||
|
if (el) el.value = value || "";
|
||||||
|
}
|
||||||
|
const enabled = document.getElementById("modelProfileEnabled");
|
||||||
|
const isDefault = document.getElementById("modelProfileDefault");
|
||||||
|
if (enabled) enabled.checked = profile.enabled !== false;
|
||||||
|
if (isDefault) isDefault.checked = !!profile.isDefault;
|
||||||
|
const title = document.getElementById("modelProfileFormTitle");
|
||||||
|
if (title) title.textContent = "编辑模型 Profile";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveModelProfile() {
|
||||||
|
const name = document.getElementById("modelProfileName")?.value.trim() || "";
|
||||||
|
const provider = document.getElementById("modelProfileProvider")?.value.trim() || "openrouter";
|
||||||
|
const model = document.getElementById("modelProfileModel")?.value.trim() || "";
|
||||||
|
const baseUrl = document.getElementById("modelProfileBaseUrl")?.value.trim() || "";
|
||||||
|
const apiKeyRef = document.getElementById("modelProfileApiKeyRef")?.value.trim() || "";
|
||||||
|
const enabled = document.getElementById("modelProfileEnabled")?.checked !== false;
|
||||||
|
const isDefault = !!document.getElementById("modelProfileDefault")?.checked;
|
||||||
|
if (!model) {
|
||||||
|
toast("请填写模型 ID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (baseUrl && !/^https?:\/\//i.test(baseUrl)) {
|
||||||
|
toast("Base URL 必须以 http:// 或 https:// 开头");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = state.editingModelProfileId || makeId("model");
|
||||||
|
const existing = modelProfileById(id);
|
||||||
|
const next = normalizeModelProfile({
|
||||||
|
id,
|
||||||
|
name: name || model,
|
||||||
|
provider,
|
||||||
|
model,
|
||||||
|
baseUrl,
|
||||||
|
apiKeyRef,
|
||||||
|
enabled,
|
||||||
|
isDefault,
|
||||||
|
createdAt: existing?.createdAt || Date.now(),
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
});
|
||||||
|
state.modelProfiles = state.modelProfiles.filter(profile => profile.id !== id);
|
||||||
|
if (next.isDefault) {
|
||||||
|
state.modelProfiles = state.modelProfiles.map(profile => ({ ...profile, isDefault: false }));
|
||||||
|
}
|
||||||
|
state.modelProfiles.push(next);
|
||||||
|
state.modelProfiles = normalizeModelProfiles(state.modelProfiles);
|
||||||
|
syncModelOptionsFromProfiles();
|
||||||
|
renderModelProfiles();
|
||||||
|
clearModelProfileForm();
|
||||||
|
try {
|
||||||
|
await saveSharedConfig({ silent: true });
|
||||||
|
toast("模型 Profile 已保存到服务器");
|
||||||
|
} catch (error) {
|
||||||
|
setSharedConfigStatus("模型 Profile 保存失败: " + (error.message || error), true);
|
||||||
|
toast("模型 Profile 暂存本机,服务器保存失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function makeModelProfileDefault(id) {
|
||||||
|
const profile = modelProfileById(id);
|
||||||
|
if (!profile) return;
|
||||||
|
state.modelProfiles = normalizeModelProfiles(state.modelProfiles.map(item => ({
|
||||||
|
...item,
|
||||||
|
isDefault: item.id === id,
|
||||||
|
})));
|
||||||
|
syncModelOptionsFromProfiles();
|
||||||
|
renderModelProfiles();
|
||||||
|
try {
|
||||||
|
await saveSharedConfig({ silent: true });
|
||||||
|
toast("默认模型 Profile 已更新");
|
||||||
|
} catch (error) {
|
||||||
|
setSharedConfigStatus("默认模型 Profile 保存失败: " + (error.message || error), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyModelProfileToRuntime(id) {
|
||||||
|
const profile = modelProfileById(id);
|
||||||
|
if (!profile) return;
|
||||||
|
document.getElementById("hermesModelDefault").value = profile.model || "";
|
||||||
|
document.getElementById("hermesModelProvider").value = profile.provider || "";
|
||||||
|
document.getElementById("hermesModelBaseUrl").value = profile.baseUrl || "";
|
||||||
|
toast("已填入运行配置,点击“保存模型并重启”后生效");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteModelProfile(id) {
|
||||||
|
if (state.modelProfiles.length <= 1) {
|
||||||
|
toast("至少保留一个模型 Profile");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confirm("删除这个模型 Profile? 已绑定的智能体会回退到模型 ID。")) return;
|
||||||
|
const wasDefault = modelProfileById(id)?.isDefault;
|
||||||
|
state.modelProfiles = state.modelProfiles.filter(profile => profile.id !== id);
|
||||||
|
if (wasDefault && state.modelProfiles[0]) state.modelProfiles[0].isDefault = true;
|
||||||
|
for (const agent of Object.values(state.agents)) {
|
||||||
|
if (agent.modelProfileId === id) agent.modelProfileId = "";
|
||||||
|
}
|
||||||
|
state.modelProfiles = normalizeModelProfiles(state.modelProfiles);
|
||||||
|
syncModelOptionsFromProfiles();
|
||||||
|
renderModelProfiles();
|
||||||
|
renderAgents();
|
||||||
|
try {
|
||||||
|
await saveSharedConfig({ silent: true });
|
||||||
|
toast("模型 Profile 已删除");
|
||||||
|
} catch (error) {
|
||||||
|
setSharedConfigStatus("模型 Profile 删除保存失败: " + (error.message || error), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function saveModelConfig() {
|
async function saveModelConfig() {
|
||||||
const model = readModelConfigFields();
|
const model = readModelConfigFields();
|
||||||
if (!model.default) {
|
if (!model.default) {
|
||||||
@@ -1047,7 +1225,7 @@ async function saveModelConfig() {
|
|||||||
restart: true,
|
restart: true,
|
||||||
});
|
});
|
||||||
const savedModel = saved.model || {};
|
const savedModel = saved.model || {};
|
||||||
if (savedModel.default) syncModelPick(savedModel.default, savedModel.provider || model.provider || "");
|
if (savedModel.default) syncModelPick(savedModel.default, savedModel.provider || "");
|
||||||
_hermesConfigSnapshot = {
|
_hermesConfigSnapshot = {
|
||||||
model: {
|
model: {
|
||||||
default: savedModel.default || model.default,
|
default: savedModel.default || model.default,
|
||||||
@@ -4159,6 +4337,7 @@ function exportData() {
|
|||||||
conversations: state.conversations,
|
conversations: state.conversations,
|
||||||
weeklyReports: state.weeklyReports,
|
weeklyReports: state.weeklyReports,
|
||||||
agents: state.agents,
|
agents: state.agents,
|
||||||
|
modelProfiles: normalizeModelProfiles(state.modelProfiles),
|
||||||
customSkills: state.customSkills,
|
customSkills: state.customSkills,
|
||||||
flows: state.flows,
|
flows: state.flows,
|
||||||
theme: localStorage.getItem(LS_THEME) || "dark",
|
theme: localStorage.getItem(LS_THEME) || "dark",
|
||||||
@@ -4189,6 +4368,7 @@ function importData(event) {
|
|||||||
saveWeeklyReports();
|
saveWeeklyReports();
|
||||||
}
|
}
|
||||||
if (data.agents) state.agents = data.agents;
|
if (data.agents) state.agents = data.agents;
|
||||||
|
if (Array.isArray(data.modelProfiles)) state.modelProfiles = normalizeModelProfiles(data.modelProfiles);
|
||||||
if (data.customSkills) { state.customSkills = data.customSkills; saveCustomSkillsToLS(); }
|
if (data.customSkills) { state.customSkills = data.customSkills; saveCustomSkillsToLS(); }
|
||||||
if (data.flows) { state.flows = data.flows; saveFlowsToLS(); }
|
if (data.flows) { state.flows = data.flows; saveFlowsToLS(); }
|
||||||
if (data.settings) {
|
if (data.settings) {
|
||||||
@@ -4208,6 +4388,7 @@ function importData(event) {
|
|||||||
}
|
}
|
||||||
saveConversations();
|
saveConversations();
|
||||||
saveAgents();
|
saveAgents();
|
||||||
|
saveSharedConfig({ silent: true }).catch(() => {});
|
||||||
// 重新挑一条活动对话
|
// 重新挑一条活动对话
|
||||||
const ids = sortedConvoIds();
|
const ids = sortedConvoIds();
|
||||||
state.activeId = ids[0] || null;
|
state.activeId = ids[0] || null;
|
||||||
@@ -4215,6 +4396,7 @@ function importData(event) {
|
|||||||
renderSidebar();
|
renderSidebar();
|
||||||
renderChat();
|
renderChat();
|
||||||
renderAgents();
|
renderAgents();
|
||||||
|
renderModelProfiles();
|
||||||
refreshDashboard();
|
refreshDashboard();
|
||||||
toast("已导入");
|
toast("已导入");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -396,6 +396,13 @@
|
|||||||
<label>模型 ID</label>
|
<label>模型 ID</label>
|
||||||
<input type="text" id="agentModel" list="modelOptions" placeholder="google/gemini-3.1-pro-preview" autocomplete="off">
|
<input type="text" id="agentModel" list="modelOptions" placeholder="google/gemini-3.1-pro-preview" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="setting-row setting-row-full">
|
||||||
|
<label>模型 Profile</label>
|
||||||
|
<select id="agentModelProfile" onchange="applyAgentModelProfileSelection()">
|
||||||
|
<option value="">跟随对话默认 / 仅使用模型 ID</option>
|
||||||
|
</select>
|
||||||
|
<div class="settings-help">Profile 记录 provider / base URL / API Key 引用;当前请求仍按模型 ID 发给 Hermes API。</div>
|
||||||
|
</div>
|
||||||
<div class="setting-row setting-row-full">
|
<div class="setting-row setting-row-full">
|
||||||
<label>角色设定 (System Prompt)</label>
|
<label>角色设定 (System Prompt)</label>
|
||||||
<textarea id="agentPrompt" rows="5" placeholder="告诉爱马仕这个智能体的角色、语气、规则、能力边界..."></textarea>
|
<textarea id="agentPrompt" rows="5" placeholder="告诉爱马仕这个智能体的角色、语气、规则、能力边界..."></textarea>
|
||||||
@@ -1200,7 +1207,7 @@ git push # Gitea kangwan/hermes-glass-ui-personal
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="settings-group-title">AI 模型接入</div>
|
<div class="settings-group-title">AI 模型接入</div>
|
||||||
<div class="settings-group-desc">线上 Hermes agent 的默认模型、Provider 和模型网关地址</div>
|
<div class="settings-group-desc">AI 模型 Profiles 与线上 Hermes agent 默认运行模型</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-group-body">
|
<div class="settings-group-body">
|
||||||
@@ -1232,6 +1239,52 @@ git push # Gitea kangwan/hermes-glass-ui-personal
|
|||||||
</button>
|
</button>
|
||||||
<div class="settings-help" id="hermesModelStatus">打开设置页后自动读取。</div>
|
<div class="settings-help" id="hermesModelStatus">打开设置页后自动读取。</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="settings-subpanel">
|
||||||
|
<div class="settings-subpanel-head">
|
||||||
|
<div>
|
||||||
|
<div class="settings-subtitle">模型 Profiles</div>
|
||||||
|
<div class="settings-help" id="modelProfilesCount">用于给不同智能体绑定不同模型接入信息。</div>
|
||||||
|
</div>
|
||||||
|
<button class="glass-btn-sm" type="button" onclick="clearModelProfileForm()">新增 Profile</button>
|
||||||
|
</div>
|
||||||
|
<div class="model-profile-list" id="modelProfilesList">
|
||||||
|
<div class="settings-help">正在读取服务器共享配置...</div>
|
||||||
|
</div>
|
||||||
|
<div class="model-profile-form">
|
||||||
|
<div class="settings-subtitle" id="modelProfileFormTitle">新增模型 Profile</div>
|
||||||
|
<div class="settings-grid-3">
|
||||||
|
<div class="settings-field">
|
||||||
|
<label for="modelProfileName">显示名</label>
|
||||||
|
<input type="text" id="modelProfileName" placeholder="例如 OpenRouter Gemini" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="settings-field">
|
||||||
|
<label for="modelProfileProvider">Provider</label>
|
||||||
|
<input type="text" id="modelProfileProvider" placeholder="openrouter / openai / anthropic" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="settings-field">
|
||||||
|
<label for="modelProfileModel">模型 ID</label>
|
||||||
|
<input type="text" id="modelProfileModel" placeholder="google/gemini-3.1-pro-preview" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="settings-field">
|
||||||
|
<label for="modelProfileBaseUrl">Base URL</label>
|
||||||
|
<input type="text" id="modelProfileBaseUrl" placeholder="https://openrouter.ai/api/v1" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="settings-field">
|
||||||
|
<label for="modelProfileApiKeyRef">API Key 引用</label>
|
||||||
|
<input type="text" id="modelProfileApiKeyRef" placeholder="OPENROUTER_API_KEY / 服务器环境变量" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="settings-field model-profile-checks">
|
||||||
|
<label class="settings-checkline"><input type="checkbox" id="modelProfileEnabled" checked> 启用</label>
|
||||||
|
<label class="settings-checkline"><input type="checkbox" id="modelProfileDefault"> 作为默认</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="settings-actions">
|
||||||
|
<button class="glass-btn-sm primary" type="button" onclick="saveModelProfile()">保存 Profile</button>
|
||||||
|
<button class="glass-btn-sm" type="button" onclick="clearModelProfileForm()">清空表单</button>
|
||||||
|
<div class="settings-help" id="sharedConfigStatus">共享配置会保存到服务器,供同事端同步。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1253,7 +1306,7 @@ git push # Gitea kangwan/hermes-glass-ui-personal
|
|||||||
time:
|
time:
|
||||||
command: uvx
|
command: uvx
|
||||||
args: ["mcp-server-time"]'></textarea>
|
args: ["mcp-server-time"]'></textarea>
|
||||||
<div class="settings-help">留空会移除 <code>mcp_servers</code>;保存会备份配置并重启 <code>hermes-agent</code>。</div>
|
<div class="settings-help">留空会移除 <code>mcp_servers</code>;保存只改工具接入,不再要求同时填写模型配置。</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-actions">
|
<div class="settings-actions">
|
||||||
<button class="glass-btn-sm" onclick="refreshHermesConfig(true)">读取 MCP 配置</button>
|
<button class="glass-btn-sm" onclick="refreshHermesConfig(true)">读取 MCP 配置</button>
|
||||||
|
|||||||
179
src/styles.css
179
src/styles.css
@@ -2532,6 +2532,7 @@ a { color: var(--orange-3); text-decoration: none; }
|
|||||||
.settings-field.toggle-field > div:first-child { flex: 1 1 200px; min-width: 0; }
|
.settings-field.toggle-field > div:first-child { flex: 1 1 200px; min-width: 0; }
|
||||||
.settings-field input[type="text"],
|
.settings-field input[type="text"],
|
||||||
.settings-field input[type="password"],
|
.settings-field input[type="password"],
|
||||||
|
.settings-field select,
|
||||||
.settings-field textarea {
|
.settings-field textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -2558,10 +2559,142 @@ a { color: var(--orange-3); text-decoration: none; }
|
|||||||
font-family: "SF Mono", ui-monospace, Menlo, monospace;
|
font-family: "SF Mono", ui-monospace, Menlo, monospace;
|
||||||
}
|
}
|
||||||
.settings-field input:focus,
|
.settings-field input:focus,
|
||||||
|
.settings-field select:focus,
|
||||||
.settings-field textarea:focus {
|
.settings-field textarea:focus {
|
||||||
border-color: var(--orange);
|
border-color: var(--orange);
|
||||||
box-shadow: 0 0 0 3px rgba(255,105,0,0.12);
|
box-shadow: 0 0 0 3px rgba(255,105,0,0.12);
|
||||||
}
|
}
|
||||||
|
.settings-subpanel {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(255,255,255,0.025);
|
||||||
|
padding: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.settings-subpanel-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 14px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.settings-subtitle {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
.model-profile-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.model-profile-card {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(255,255,255,0.035);
|
||||||
|
padding: 12px;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.model-profile-card.active {
|
||||||
|
border-color: rgba(255,122,26,0.55);
|
||||||
|
background: rgba(255,122,26,0.08);
|
||||||
|
}
|
||||||
|
.model-profile-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.model-profile-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.model-profile-model {
|
||||||
|
font-family: "SF Mono", ui-monospace, Menlo, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-dim);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.model-profile-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.model-profile-meta span,
|
||||||
|
.model-profile-badge {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 3px 7px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-dim2);
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.model-profile-badge {
|
||||||
|
color: #1a0f08;
|
||||||
|
background: var(--orange);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
.model-profile-badge.off {
|
||||||
|
color: var(--text-dim2);
|
||||||
|
background: rgba(255,255,255,0.06);
|
||||||
|
border-color: var(--line);
|
||||||
|
}
|
||||||
|
.model-profile-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.model-profile-actions button {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255,255,255,0.04);
|
||||||
|
color: var(--text-dim);
|
||||||
|
padding: 6px 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.model-profile-actions button:hover {
|
||||||
|
color: var(--text);
|
||||||
|
border-color: var(--line-strong);
|
||||||
|
}
|
||||||
|
.model-profile-actions button.danger:hover {
|
||||||
|
color: var(--err);
|
||||||
|
border-color: rgba(255,93,122,0.45);
|
||||||
|
}
|
||||||
|
.model-profile-form {
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
padding-top: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.model-profile-checks {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.settings-checkline {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 32px;
|
||||||
|
color: var(--text-dim);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.settings-checkline input {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
.settings-help {
|
.settings-help {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--text-dim2);
|
color: var(--text-dim2);
|
||||||
@@ -4041,3 +4174,49 @@ a { color: var(--orange-3); text-decoration: none; }
|
|||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.boot-issue {
|
||||||
|
position: fixed;
|
||||||
|
right: 18px;
|
||||||
|
bottom: 18px;
|
||||||
|
z-index: 9999;
|
||||||
|
width: min(420px, calc(100vw - 28px));
|
||||||
|
max-height: min(420px, calc(100vh - 28px));
|
||||||
|
overflow: auto;
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid rgba(255,93,122,0.45);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(22, 24, 28, 0.96);
|
||||||
|
box-shadow: 0 18px 60px rgba(0,0,0,0.35);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.boot-issue-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--err);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.boot-issue-msg {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--text-dim);
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.boot-issue button {
|
||||||
|
margin-top: 10px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
color: var(--text);
|
||||||
|
padding: 7px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.boot-issue details {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-dim2);
|
||||||
|
}
|
||||||
|
.boot-issue pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user