fix: v1.3.1 - 四项优化

1. VRAM/内存进度条改为仅 sticky 置顶显示
   - 去掉页面内重复的 vram-display 进度条
   - 只保留顶部 sticky bar,滚动时始终可见

2. 去掉参数修改标记
   - 不再用红色线框标记已更改的参数

3. 命令区域简化
   - 去掉独立的「复制命令」和「重新生成」按钮
   - 复制按钮改为命令文本框右下角悬空小按钮

4. h2 标题 margin-top 改为 0
This commit is contained in:
2026-07-19 23:48:18 +08:00
parent 3c27a205e5
commit fb3d7290bf
3 changed files with 41 additions and 37 deletions
+24 -11
View File
@@ -109,7 +109,6 @@
}
.nl-input-container textarea:focus { outline: none; border-color: var(--accent); }
.nl-input-container button { padding: 10px 24px; background: var(--accent2); color: var(--bg); border: none; border-radius: var(--radius); cursor: pointer; font-weight: 600; flex-shrink: 0; }
}
* { margin: 0; padding: 0; box-sizing: border-box; }
@@ -249,7 +248,7 @@ header h1 {
box-shadow: var(--shadow);
}
.panel h2 { font-size: 1.2em; margin-bottom: 16px; color: var(--accent2); border-bottom: 1px solid var(--border); padding-bottom: 8px; }
.panel h2 { font-size: 1.2em; margin-top: 0; margin-bottom: 16px; color: var(--accent2); border-bottom: 1px solid var(--border); padding-bottom: 8px; }
.hidden { display: none !important; }
@@ -263,8 +262,9 @@ header h1 {
.btn-add { background: transparent; border: 1px dashed var(--border); color: var(--text-dim); padding: 8px 16px; border-radius: var(--radius); cursor: pointer; width: 100%; margin-top: 8px; }
.btn-add:hover { border-color: var(--accent2); color: var(--accent2); }
/* ===== VRAM Display ===== */
.vram-display { margin-top: 16px; padding: 12px; background: var(--bg-input); border-radius: var(--radius); }
/* ===== VRAM Display (hidden when sticky bar visible) ===== */
.vram-display { margin-top: 16px; padding: 12px; background: var(--bg-input); border-radius: var(--radius); display: none; }
.vram-display.visible { display: block; }
.vram-bar-container { position: relative; height: 30px; background: var(--bg); border-radius: 4px; overflow: hidden; border: 1px solid var(--border); }
.vram-bar { height: 100%; background: linear-gradient(90deg, #4ecca3, #e9c46a); border-radius: 3px; transition: width 0.3s; width: 0%; }
.vram-bar.warning { background: linear-gradient(90deg, #e9c46a, #f4a261); }
@@ -376,7 +376,9 @@ header h1 {
transition: border-color 0.15s;
}
.param-item:hover { border-color: var(--accent2); }
.param-item.modified { border-color: var(--accent); background: rgba(233, 69, 96, 0.05); }
.param-item.modified { border-color: var(--accent2); }
/* keep old .modified for backwards compat but remove red styling */
.param-item .param-flag {
font-family: monospace;
@@ -435,12 +437,23 @@ header h1 {
/* ===== Command Output ===== */
.command-panel { position: sticky; bottom: 20px; }
.command-output { background: #0d1117; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.9em; color: #4ecca3; word-break: break-all; min-height: 60px; white-space: pre-wrap; }
.command-actions { margin-top: 12px; display: flex; gap: 8px; }
.btn-copy, .btn-gen { padding: 8px 20px; border: none; border-radius: var(--radius); cursor: pointer; font-size: 0.9em; font-weight: 500; }
.btn-copy { background: var(--accent2); color: var(--bg); }
.btn-copy:hover { opacity: 0.85; }
.btn-gen { background: var(--bg-input); color: var(--text); border: 1px solid var(--border); }
.command-output { position: relative; background: #0d1117; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.9em; color: #4ecca3; word-break: break-all; min-height: 60px; white-space: pre-wrap; }
.command-copy-btn {
position: absolute;
bottom: 6px;
right: 6px;
background: var(--bg-input);
border: 1px solid var(--border);
color: var(--text-dim);
padding: 3px 10px;
border-radius: 4px;
cursor: pointer;
font-size: 0.75em;
transition: all 0.15s;
opacity: 0.7;
}
.command-copy-btn:hover { opacity: 1; border-color: var(--accent2); color: var(--accent2); }
.command-copy-btn.copied { background: var(--accent2); color: var(--bg); border-color: var(--accent2); opacity: 1; }
/* ===== Admin ===== */
.admin-tabs { display: flex; gap: 4px; margin-bottom: 20px; flex-wrap: wrap; }
+3 -4
View File
@@ -134,12 +134,11 @@
<!-- Generated Command -->
<section class="panel command-panel">
<h2>📋 生成命令</h2>
<div class="command-output-wrap">
<div class="command-output" id="command-output">请在上方配置参数...</div>
<div class="command-hint" id="command-hint"></div>
<div class="command-actions">
<button onclick="copyCommand()" class="btn-copy">📋 复制命令</button>
<button onclick="generateCommand()" class="btn-gen">🔄 重新生成</button>
<button class="command-copy-btn" onclick="copyCommand()" id="copy-btn">📋 复制</button>
</div>
<div class="command-hint" id="command-hint"></div>
</section>
</div>
<script src="/js/main.js"></script>
+13 -21
View File
@@ -183,8 +183,7 @@ function renderParams() {
function renderParamItem(p) {
const val = state.paramValues[p.param_key];
const isMod = isParamModified(p, val);
const mc = isMod ? 'modified' : '';
const mc = '';
const vb = p.affects_vram ? '<span class="vram-badge">⚡显存</span>' : '';
// Show both short and long flag
const shortFlag = p.short_flag || '';
@@ -221,8 +220,7 @@ function isParamModified(p, val) {
function setParam(key, value) {
state.paramValues[key] = value;
const item = document.querySelector(`.param-item[data-key="${key}"]`);
if (item) { const p = state.params.find(p => p.param_key === key); if (p && isParamModified(p, value)) item.classList.add('modified'); else item.classList.remove('modified'); }
// No visual modification marker per user request
generateCommand(); updateEstimate();
}
@@ -259,25 +257,13 @@ function collectParamsForEstimate() {
}
function renderVramDisplay(data) {
const bar = document.getElementById('vram-bar'), label = document.getElementById('vram-label'), bd = document.getElementById('vram-breakdown');
if (!data.total_vram_available_mb) { bar.style.width = '0%'; label.textContent = '请选择GPU'; bd.innerHTML = ''; return; }
const pct = data.usage_percent || 0;
bar.style.width = Math.min(pct, 100) + '%';
bar.className = 'vram-bar' + (pct > 90 ? ' danger' : pct > 75 ? ' warning' : '');
label.textContent = `VRAM: ${data.total_gb}GB / ${data.total_vram_available_gb}GB (${pct}%)`;
bd.innerHTML = `<div class="breakdown-item"><span class="label">模型权重</span><span class="value">${data.weights_gb}GB</span></div><div class="breakdown-item"><span class="label">KV缓存</span><span class="value">${data.kv_cache_gb}GB</span></div><div class="breakdown-item"><span class="label">计算/开销</span><span class="value">${(data.compute_mb/1024).toFixed(2)}GB</span></div><div class="breakdown-item"><span class="label">CUDA开销</span><span class="value">${(data.cuda_overhead_mb/1024).toFixed(2)}GB</span></div>`;
// Update sticky bar instead of inline display
updateStickyBar(data, parseFloat(document.getElementById('sys-memory').value) || 0, (parseFloat(document.getElementById('sys-memory').value) || 0) === 0);
}
function renderRamDisplay(data, sysGb, isUnlimited) {
const bar = document.getElementById('ram-bar'), label = document.getElementById('ram-label'), bd = document.getElementById('ram-breakdown');
if (isUnlimited) { bar.style.width = '0%'; label.textContent = `内存: ${data.cpu_total_gb}GB (无限制)`; }
else {
const pct = data.cpu_usage_percent || 0;
bar.style.width = Math.min(pct, 100) + '%';
bar.className = 'vram-bar ram-bar' + (pct > 90 ? ' danger' : pct > 75 ? ' warning' : '');
label.textContent = `内存: ${data.cpu_total_gb}GB / ${sysGb}GB (${pct}%)`;
}
bd.innerHTML = `<div class="breakdown-item"><span class="label">CPU模型权重</span><span class="value">${data.cpu_weights_gb}GB</span></div><div class="breakdown-item"><span class="label">CPU KV缓存</span><span class="value">${(data.cpu_kv_cache_mb/1024).toFixed(2)}GB</span></div>`;
// Update sticky ram bar instead of inline display
// (sticky bar is already updated in updateStickyBar)
}
// ===== Sticky top bar =====
@@ -386,7 +372,13 @@ function copyCommand() {
const ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta); ta.select();
try { document.execCommand('copy'); const btn = document.querySelector('.btn-copy'); const o = btn.textContent; btn.textContent = '✅ 已复制!'; setTimeout(() => btn.textContent = o, 2000); } catch(e) { alert('复制失败,请手动选择文本复制'); }
try {
document.execCommand('copy');
const btn = document.getElementById('copy-btn');
btn.textContent = '✅ 已复制';
btn.classList.add('copied');
setTimeout(() => { btn.textContent = '📋 复制'; btn.classList.remove('copied'); }, 2000);
} catch(e) { alert('复制失败,请手动选择文本复制'); }
document.body.removeChild(ta);
}