Add theme options and timed agent dividers
This commit is contained in:
104
public/app.js
104
public/app.js
@@ -2,10 +2,11 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const ASSET_VERSION = '20260613-codexapp-tools2';
|
||||
const ASSET_VERSION = '20260614-divider-time-selectfix';
|
||||
const WS_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`;
|
||||
const RENDER_DEBOUNCE = 100;
|
||||
const COMPOSER_SUGGESTION_DEBOUNCE = 120;
|
||||
const DIVIDER_TIME_STORAGE_KEY = 'cc-web-show-divider-time';
|
||||
|
||||
const SLASH_COMMANDS = [
|
||||
{ cmd: '/clear', desc: '清除当前会话' },
|
||||
@@ -73,6 +74,42 @@
|
||||
desc: '更明亮的留白和更克制的棕色强调,像编辑台一样安静。',
|
||||
swatches: ['#f6f1e8', '#efe8dc', '#8b5e3c', '#2f4b45'],
|
||||
},
|
||||
{
|
||||
value: 'sage',
|
||||
label: 'Sage Console',
|
||||
desc: '清透鼠尾草绿与石墨文字,适合长时间工作流。',
|
||||
swatches: ['#f5f8f2', '#e6efdf', '#2f6f64', '#557ba3'],
|
||||
},
|
||||
{
|
||||
value: 'ink',
|
||||
label: 'Ink Focus',
|
||||
desc: '浅灰纸面配靛蓝重点,信息密度更高也更冷静。',
|
||||
swatches: ['#f6f7fb', '#e8edf5', '#3f5fb5', '#3f8f73'],
|
||||
},
|
||||
{
|
||||
value: 'dawn',
|
||||
label: 'Dawn Studio',
|
||||
desc: '晨光米白配珊瑚红,保留温度但比暖纸更轻。',
|
||||
swatches: ['#fff7f2', '#f3e8e1', '#b5524d', '#4f8a6b'],
|
||||
},
|
||||
{
|
||||
value: 'carbon',
|
||||
label: 'Carbon Mint',
|
||||
desc: '石墨黑底配薄荷绿重点,夜间使用更稳。',
|
||||
swatches: ['#0f1314', '#202829', '#67d8b2', '#9fb7ff'],
|
||||
},
|
||||
{
|
||||
value: 'nocturne',
|
||||
label: 'Nocturne Teal',
|
||||
desc: '深海青黑配电光蓝,适合高专注会话。',
|
||||
swatches: ['#081417', '#142b31', '#5ecdf5', '#f0c36a'],
|
||||
},
|
||||
{
|
||||
value: 'cinder',
|
||||
label: 'Cinder Rose',
|
||||
desc: '炭黑底配低饱和玫瑰色,暗色里保留一点温度。',
|
||||
swatches: ['#151112', '#2a2022', '#e68193', '#67c587'],
|
||||
},
|
||||
];
|
||||
|
||||
// --- State ---
|
||||
@@ -98,6 +135,7 @@
|
||||
let currentModel = 'opus';
|
||||
let currentAgent = AGENT_LABELS[localStorage.getItem('cc-web-agent')] ? localStorage.getItem('cc-web-agent') : DEFAULT_AGENT;
|
||||
let currentTheme = (document.documentElement.dataset.theme || localStorage.getItem('cc-web-theme') || 'washi');
|
||||
let showAgentDividerTime = localStorage.getItem(DIVIDER_TIME_STORAGE_KEY) !== '0';
|
||||
let codexConfigCache = null;
|
||||
let loadedHistorySessionId = null;
|
||||
let activeSessionLoad = null;
|
||||
@@ -123,6 +161,7 @@
|
||||
let noteDraftSeq = 0;
|
||||
const pendingNotesByTarget = new Map();
|
||||
const userMessageIndex = new Map();
|
||||
document.documentElement.dataset.dividerTime = showAgentDividerTime ? 'show' : 'hide';
|
||||
|
||||
// --- DOM ---
|
||||
const $ = (sel) => document.querySelector(sel);
|
||||
@@ -447,6 +486,26 @@
|
||||
refreshThemeSummaries();
|
||||
}
|
||||
|
||||
function getDividerTimeSummary() {
|
||||
return showAgentDividerTime ? '显示时间' : '不显示时间';
|
||||
}
|
||||
|
||||
function refreshDividerTimeControls(root = document) {
|
||||
root.querySelectorAll('[data-divider-time-summary]').forEach((node) => {
|
||||
node.textContent = getDividerTimeSummary();
|
||||
});
|
||||
root.querySelectorAll('[data-divider-time-toggle]').forEach((node) => {
|
||||
node.checked = showAgentDividerTime;
|
||||
});
|
||||
}
|
||||
|
||||
function applyDividerTimePreference(visible) {
|
||||
showAgentDividerTime = !!visible;
|
||||
document.documentElement.dataset.dividerTime = showAgentDividerTime ? 'show' : 'hide';
|
||||
localStorage.setItem(DIVIDER_TIME_STORAGE_KEY, showAgentDividerTime ? '1' : '0');
|
||||
refreshDividerTimeControls();
|
||||
}
|
||||
|
||||
function buildThemePickerHtml(options = {}) {
|
||||
const { showSectionTitle = true } = options;
|
||||
return `
|
||||
@@ -476,7 +535,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function buildThemeEntryHtml() {
|
||||
function buildAppearanceSettingsHtml() {
|
||||
return `
|
||||
<div class="settings-section-title">外观</div>
|
||||
<button class="settings-nav-card" type="button" data-open-theme-page>
|
||||
@@ -486,9 +545,34 @@
|
||||
</span>
|
||||
<span class="settings-nav-card-arrow" aria-hidden="true">›</span>
|
||||
</button>
|
||||
<label class="settings-toggle-row">
|
||||
<span class="settings-toggle-copy">
|
||||
<span class="settings-toggle-title">分隔线时间</span>
|
||||
<span class="settings-toggle-meta">当前:<span data-divider-time-summary>${escapeHtml(getDividerTimeSummary())}</span></span>
|
||||
</span>
|
||||
<span class="settings-switch">
|
||||
<input type="checkbox" data-divider-time-toggle ${showAgentDividerTime ? 'checked' : ''}>
|
||||
<span class="settings-switch-track" aria-hidden="true">
|
||||
<span class="settings-switch-thumb"></span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
|
||||
function mountAppearanceSettings(panel) {
|
||||
const themePageBtn = panel.querySelector('[data-open-theme-page]');
|
||||
if (themePageBtn) themePageBtn.addEventListener('click', openThemeSubpage);
|
||||
const dividerTimeToggle = panel.querySelector('[data-divider-time-toggle]');
|
||||
if (dividerTimeToggle) {
|
||||
dividerTimeToggle.checked = showAgentDividerTime;
|
||||
dividerTimeToggle.addEventListener('change', () => {
|
||||
applyDividerTimePreference(dividerTimeToggle.checked);
|
||||
});
|
||||
}
|
||||
refreshDividerTimeControls(panel);
|
||||
}
|
||||
|
||||
function buildNotifyEntryHtml(config) {
|
||||
const provider = config?.provider || 'off';
|
||||
const providerLabel = PROVIDER_OPTIONS.find(o => o.value === provider)?.label || '关闭';
|
||||
@@ -4319,7 +4403,7 @@
|
||||
${title}
|
||||
<div style="font-size:0.9em;color:var(--text-primary);margin-bottom:20px;line-height:1.7;word-break:break-word;white-space:pre-line">${escapeHtml(options.message || '')}</div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px">
|
||||
<button id="simple-confirm-ok" style="width:100%;padding:10px;border:none;border-radius:10px;background:var(--accent);color:#fff;font-size:0.95em;font-weight:600;cursor:pointer;font-family:inherit">${escapeHtml(confirmText)}</button>
|
||||
<button id="simple-confirm-ok" style="width:100%;padding:10px;border:none;border-radius:10px;background:var(--accent);color:var(--accent-ink, #fff);font-size:0.95em;font-weight:600;cursor:pointer;font-family:inherit">${escapeHtml(confirmText)}</button>
|
||||
<button id="simple-confirm-cancel" style="width:100%;padding:9px;border:none;border-radius:10px;background:transparent;color:var(--text-muted);font-size:0.85em;cursor:pointer;font-family:inherit">${escapeHtml(cancelText)}</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -4355,7 +4439,7 @@
|
||||
box.innerHTML = `
|
||||
<div style="font-size:0.9em;color:var(--text-primary);margin-bottom:20px;line-height:1.7">${escapeHtml(getDeleteConfirmMessage(agent))}</div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px">
|
||||
<button id="del-confirm-ok" style="width:100%;padding:10px;border:none;border-radius:10px;background:var(--accent);color:#fff;font-size:0.95em;font-weight:600;cursor:pointer;font-family:inherit">确认删除</button>
|
||||
<button id="del-confirm-ok" style="width:100%;padding:10px;border:none;border-radius:10px;background:var(--accent);color:var(--accent-ink, #fff);font-size:0.95em;font-weight:600;cursor:pointer;font-family:inherit">确认删除</button>
|
||||
<button id="del-confirm-skip" style="width:100%;padding:9px;border:1px solid var(--border-color);border-radius:10px;background:var(--bg-tertiary);color:var(--text-secondary);font-size:0.85em;cursor:pointer;font-family:inherit">确认且不再提示</button>
|
||||
<button id="del-confirm-cancel" style="width:100%;padding:9px;border:none;border-radius:10px;background:transparent;color:var(--text-muted);font-size:0.85em;cursor:pointer;font-family:inherit">取消</button>
|
||||
</div>
|
||||
@@ -4588,7 +4672,7 @@
|
||||
if (!currentSessionId || chatTitle.contentEditable === 'true') return;
|
||||
const originalText = chatTitle.textContent;
|
||||
chatTitle.contentEditable = 'true';
|
||||
chatTitle.style.background = '#fff';
|
||||
chatTitle.style.background = 'var(--surface-strong)';
|
||||
chatTitle.style.outline = '1px solid var(--accent)';
|
||||
chatTitle.style.borderRadius = '6px';
|
||||
chatTitle.style.padding = '2px 8px';
|
||||
@@ -5647,7 +5731,7 @@
|
||||
|
||||
<div class="settings-divider"></div>
|
||||
|
||||
${buildThemeEntryHtml()}
|
||||
${buildAppearanceSettingsHtml()}
|
||||
|
||||
<div class="settings-divider"></div>
|
||||
|
||||
@@ -5665,8 +5749,7 @@
|
||||
|
||||
overlay.appendChild(panel);
|
||||
document.body.appendChild(overlay);
|
||||
const themePageBtn = panel.querySelector('[data-open-theme-page]');
|
||||
if (themePageBtn) themePageBtn.addEventListener('click', openThemeSubpage);
|
||||
mountAppearanceSettings(panel);
|
||||
const notifyPageBtn = panel.querySelector('[data-open-notify-page]');
|
||||
if (notifyPageBtn) notifyPageBtn.addEventListener('click', openNotifySubpage);
|
||||
|
||||
@@ -5934,7 +6017,7 @@
|
||||
|
||||
<div class="settings-divider"></div>
|
||||
|
||||
${buildThemeEntryHtml()}
|
||||
${buildAppearanceSettingsHtml()}
|
||||
|
||||
<div class="settings-divider"></div>
|
||||
|
||||
@@ -5952,8 +6035,7 @@
|
||||
|
||||
overlay.appendChild(panel);
|
||||
document.body.appendChild(overlay);
|
||||
const themePageBtn = panel.querySelector('[data-open-theme-page]');
|
||||
if (themePageBtn) themePageBtn.addEventListener('click', openThemeSubpage);
|
||||
mountAppearanceSettings(panel);
|
||||
const notifyPageBtn2 = panel.querySelector('[data-open-notify-page]');
|
||||
if (notifyPageBtn2) notifyPageBtn2.addEventListener('click', openNotifySubpage);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user