docs: 添加笔临 P0/P1 设计规格

定义 Electron+React 地基与写作核心的架构、IPC、数据模型与验收标准,作为全量实现的第一阶段依据。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-05 16:47:15 +08:00
parent ca2cd29f01
commit a06038035b
4 changed files with 961 additions and 26 deletions
+191 -4
View File
@@ -1136,6 +1136,30 @@
font-family: var(--font-sans);
}
/* ============ V1.1 NEW UI ============ */
.ai-session-bar { display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--border);flex-shrink:0; }
.ai-session-bar select { flex:1;font-size:11px;padding:4px 8px;background:var(--bg-tertiary);color:#fff;border:1px solid var(--border);border-radius:4px; }
.ai-mode-tabs { display:flex;gap:2px;padding:6px 8px;border-bottom:1px solid var(--border);flex-shrink:0; }
.ai-mode-tab { flex:1;padding:5px 4px;font-size:10px;text-align:center;border-radius:4px;cursor:pointer;color:var(--text-muted);background:transparent;border:none;transition:var(--transition); }
.ai-mode-tab.active { background:var(--accent);color:#fff;font-weight:600; }
.context-preview { padding:6px 10px;font-size:10px;color:var(--text-muted);border-bottom:1px solid var(--border);cursor:pointer;flex-shrink:0; }
.context-preview:hover { color:var(--accent-light); }
#reference-panel { width:0;overflow:hidden;transition:width var(--transition-slow);border-left:1px solid var(--border);background:var(--bg-secondary);display:flex;flex-direction:column;flex-shrink:0; }
#reference-panel.open { width:240px; }
.ref-tabs { display:flex;border-bottom:1px solid var(--border); }
.ref-tab { flex:1;padding:8px 4px;font-size:10px;text-align:center;cursor:pointer;color:var(--text-muted);border:none;background:transparent; }
.ref-tab.active { color:var(--accent-light);border-bottom:2px solid var(--accent); }
.ref-list { flex:1;overflow-y:auto;padding:6px; }
.ref-item { padding:8px;margin-bottom:4px;background:var(--bg-tertiary);border-radius:var(--radius-sm);font-size:11px;cursor:grab;color:var(--text-secondary); }
.ref-item:hover { background:var(--bg-hover);color:#fff; }
.search-input-row { display:flex;gap:8px;margin-bottom:12px; }
.search-input-row input { flex:1;padding:10px 14px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg-tertiary);color:#fff;font-size:13px; }
.search-result { padding:10px 12px;border-radius:var(--radius-sm);background:var(--bg-tertiary);margin-bottom:6px;cursor:pointer;font-size:12px; }
.search-result:hover { background:var(--bg-hover); }
.search-result .sr-type { font-size:10px;color:var(--accent-light);margin-bottom:4px; }
.search-result .sr-context { color:var(--text-muted);font-size:11px; }
.inspiration-capture textarea { width:100%;min-height:100px;padding:12px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg-tertiary);color:#fff;font-size:13px;resize:vertical;font-family:var(--font-sans); }
/* ============ MODALS ============ */
.modal-overlay {
position: fixed;
@@ -1764,15 +1788,17 @@
<button onclick="showTemplateModal()" aria-label="模板快速新建"><i class="fa-solid fa-file-lines"></i> 模板新建</button>
<button onclick="addVolume()" aria-label="新建分卷"><i class="fa-solid fa-folder-plus"></i> 新卷</button>
<button onclick="showVersionModal()" aria-label="版本历史"><i class="fa-solid fa-clock-rotate-left"></i> 版本</button>
<button onclick="showLandmarksModal()" aria-label="写作地标"><i class="fa-solid fa-map-pin"></i> 地标</button>
<button class="accent" onclick="enterReadingMode()" aria-label="阅读模式"><i class="fa-solid fa-book-open"></i> 阅读</button>
</div>
</div>
<!-- 大纲面板 -->
<div class="sidebar-panel" id="outline-panel" style="padding:4px;">
<div style="padding:4px 8px;display:flex;gap:4px;flex-shrink:0;">
<div style="padding:4px 8px;display:flex;gap:4px;flex-shrink:0;align-items:center;">
<button class="btn" style="font-size:10px;padding:3px 8px;background:var(--accent);color:#fff;">全部</button>
<button class="btn" style="font-size:10px;padding:3px 8px;">未覆盖</button>
<button class="btn" style="font-size:10px;padding:3px 8px;">已覆盖</button>
<button class="btn" style="font-size:10px;padding:3px 8px;margin-left:auto;" onclick="showToast('进入大纲-正文对照模式')" title="大纲-正文对照">⇔ 对照</button>
</div>
<div style="padding:4px 8px;font-size:10px;color:var(--text-muted);">大纲树(拖拽排序 · 点击关联章节)</div>
<div class="outline-item uncovered" title="预期 3000字 vs 实际 0字 — 偏差100%">⚠ 第一卷核心剧情线</div>
@@ -1838,6 +1864,7 @@
<span class="sep"></span>
<button class="tool-btn" id="btnSpellCheck" title="拼写检查" aria-label="拼写检查" onclick="toggleSpellCheck()"><i class="fa-solid fa-spell-check"></i></button>
<button class="tool-btn" id="btnTTS" title="朗读 Ctrl+Shift+R" aria-label="朗读" onclick="toggleTTS()"><i class="fa-solid fa-headphones"></i></button>
<button class="tool-btn" id="btnReference" title="引用面板 Ctrl+Shift+P" aria-label="引用面板" onclick="toggleReferencePanel()"><i class="fa-solid fa-book-bookmark"></i></button>
<span class="sep"></span>
<span class="ch-label">当前:第3章 · 入门考验</span>
<span class="word-count-display" id="wordCountDisplay" title="点击查看用词分析" onclick="showWordFreqInPanel()">2,847 字</span>
@@ -1869,6 +1896,22 @@
</div>
</div>
<!-- REFERENCE PANEL -->
<div id="reference-panel" aria-label="引用面板">
<div class="ref-tabs">
<button class="ref-tab active" onclick="switchRefTab('setting',this)">设定</button>
<button class="ref-tab" onclick="switchRefTab('outline',this)">大纲</button>
<button class="ref-tab" onclick="switchRefTab('inspiration',this)">灵感</button>
</div>
<div style="padding:6px 8px;border-bottom:1px solid var(--border);"><input type="text" placeholder="搜索引用..." style="width:100%;padding:6px 8px;font-size:11px;border-radius:4px;border:1px solid var(--border);background:var(--bg-tertiary);color:#fff;"></div>
<div class="ref-list" id="refList">
<div class="ref-item" draggable="true" onclick="showToast('展开:林远')">👤 林远 — 三纹灵根,主角</div>
<div class="ref-item" draggable="true" onclick="showToast('展开:测灵石')">📍 测灵石 — 青云宗测试法器</div>
<div class="ref-item" draggable="true" onclick="showToast('展开:入门考验大纲')">🗺 入门考验 — 预期3000字</div>
</div>
<div style="padding:8px;border-top:1px solid var(--border);font-size:10px;color:var(--text-muted);"><label><input type="checkbox"> 钉住当前条目</label></div>
</div>
<!-- RIGHT PANEL -->
<div id="right-panel">
<div class="panel-tabs">
@@ -1879,6 +1922,21 @@
</div>
<!-- AI Chat Panel -->
<div class="panel-content active" id="ai-chat">
<div class="ai-session-bar">
<select id="aiSessionSelect" aria-label="AI会话选择" onchange="showToast('切换会话:'+this.options[this.selectedIndex].text)">
<option>第3章续写讨论</option>
<option>角色命名 brainstorm</option>
<option>第二卷大纲规划</option>
</select>
<button class="btn" style="font-size:10px;padding:4px 8px;" onclick="showToast('新建AI会话')" aria-label="新建会话">+</button>
</div>
<div class="ai-mode-tabs" role="tablist">
<button class="ai-mode-tab active" onclick="setAiMode('chat',this)">对话</button>
<button class="ai-mode-tab" onclick="setAiMode('interactive',this)">交互写作</button>
<button class="ai-mode-tab" onclick="setAiMode('auto',this)">自动写作</button>
<button class="ai-mode-tab" onclick="setAiMode('wizard',this)">向导</button>
</div>
<div class="context-preview" onclick="showToast('展开上下文编辑器:第1-2章摘要、大纲3条、设定7个')" title="点击编辑上下文">📎 上下文:第1-2章摘要 · 大纲3条 · 设定7个 · <span style="color:var(--accent-light)">更新</span></div>
<div class="offline-banner" id="offlineBanner">⚠ 当前网络不可用,已切换为离线模式。请配置本地模型或连接网络。</div>
<div class="chat-messages" id="chatMessages">
<div class="chat-msg ai">
@@ -1983,10 +2041,20 @@
<h2>⚙ 通用设置</h2>
<div class="setting-block">
<h4>语言与外观</h4>
<div class="setting-item"><span class="setting-label">界面语言</span><select><option>简体中文</option><option>繁體中文</option><option>English</option></select></div>
<div class="setting-item"><span class="setting-label">界面语言</span><select aria-label="界面语言"><option>简体中文</option><option>English</option></select></div>
<div class="setting-item"><span class="setting-label">主题</span><select id="themeSelect" onchange="switchTheme(this.value)" aria-label="主题选择"><option value="default">墨砚(默认)</option><option value="bamboo">竹语</option><option value="moonlit">月夜</option><option value="ricepaper">宣纸</option><option value="mist">晨雾</option><option value="teagarden">茶园</option><option value="twilight">暮光</option></select></div>
<div class="setting-item"><span class="setting-label">字体大小</span><select><option></option><option></option><option></option></select></div>
</div>
<div class="setting-block">
<h4>作者信息</h4>
<div class="setting-item"><span class="setting-label">笔名</span><input type="text" value="山海" placeholder="至少2个字符" style="width:160px;" aria-label="笔名"></div>
</div>
<div class="setting-block">
<h4>写作目标</h4>
<div class="setting-item"><span class="setting-label">日更字数目标</span><input type="number" value="3000" min="0" step="500" aria-label="日更目标"></div>
<div class="setting-item"><span class="setting-label">更新频率</span><select aria-label="更新频率"><option>日更</option><option>隔日更</option><option>周更</option><option>不设定</option></select></div>
<div class="setting-item"><span class="setting-label">存稿预警阈值</span><input type="number" value="3" min="1" max="30" aria-label="存稿阈值"></div>
</div>
<div class="setting-block">
<h4>默认行为</h4>
<div class="setting-item"><span class="setting-label">启动时打开上次书籍</span><select><option></option><option>否(显示主页)</option></select></div>
@@ -2001,6 +2069,7 @@
<div class="setting-item"><span class="setting-label">默认字体</span><select><option>宋体</option><option>楷体</option><option>微软雅黑</option></select></div>
<div class="setting-item"><span class="setting-label">行距</span><select><option>1.8</option><option>2.0</option><option>2.2</option></select></div>
<div class="setting-item"><span class="setting-label">专注模式背景</span><select><option>纯黑</option><option>深灰</option><option>渐变</option></select></div>
<div class="setting-item"><span class="setting-label">合规检查(敏感词提示)</span><select><option>关闭</option><option>开启</option></select></div>
</div>
</div>
<!-- AI设置 -->
@@ -2031,6 +2100,8 @@
<div class="setting-item"><span class="setting-label">全局搜索</span><span class="shortcut-key" onclick="recordShortcut(this)">Ctrl+Shift+F</span></div>
<div class="setting-item"><span class="setting-label">朗读 播放/暂停</span><span class="shortcut-key" onclick="recordShortcut(this)">Ctrl+Shift+R</span></div>
<div class="setting-item"><span class="setting-label">灵感快速捕获</span><span class="shortcut-key" onclick="recordShortcut(this)">Ctrl+Shift+I</span></div>
<div class="setting-item"><span class="setting-label">引用面板</span><span class="shortcut-key" onclick="recordShortcut(this)">Ctrl+Shift+P</span></div>
<div class="setting-item"><span class="setting-label">写作地标</span><span class="shortcut-key" onclick="recordShortcut(this)">Ctrl+Shift+M</span></div>
</div>
</div>
<!-- 备份与同步 -->
@@ -2171,6 +2242,11 @@
<div style="margin-top:16px;"><h4 style="font-size:12px;color:var(--text-muted);margin-bottom:8px;">📅 写作热力图(近30天)</h4>
<div style="display:flex;flex-wrap:wrap;gap:2px;" id="heatmapContainer"></div>
</div>
<div style="margin-top:16px;display:flex;gap:8px;flex-wrap:wrap;">
<button class="btn primary" style="font-size:11px;" onclick="closeModal('dashboardModal');showToast('回到上次编辑位置')">↩ 回到上次编辑</button>
<button class="btn" style="font-size:11px;" onclick="closeModal('dashboardModal');showBridgeModal()">🔗 检查章间衔接</button>
<button class="btn" style="font-size:11px;" onclick="closeModal('dashboardModal');switchRightPanel('knowledge',document.querySelector('.panel-tab:nth-child(2)'))">⚠ 处理遗忘伏笔</button>
</div>
</div>
</div>
</div>
@@ -2222,6 +2298,7 @@
<div class="export-opt" onclick="showToast('导出为 .docx');closeModal('exportModal')"><span class="export-icon">📝</span><div class="export-info"><span class="export-name">Word 文档 .docx</span><span class="export-desc">保留格式,自动生成目录</span></div></div>
<div class="export-opt" onclick="showToast('导出为 .md');closeModal('exportModal')"><span class="export-icon">📋</span><div class="export-info"><span class="export-name">Markdown .md</span><span class="export-desc">适合发布到网络平台</span></div></div>
<div class="export-opt" onclick="showToast('导出为 PDF (A4模板)');closeModal('exportModal')"><span class="export-icon">📕</span><div class="export-info"><span class="export-name">PDF 文档 .pdf</span><span class="export-desc">A4/信纸排版,页眉含书名+章节名+页码</span></div></div>
<div class="export-opt" onclick="showToast('已复制到剪贴板(网文投稿格式)');closeModal('exportModal')"><span class="export-icon">📋</span><div class="export-info"><span class="export-name">复制到剪贴板</span><span class="export-desc">网文投稿预设:段首空两格、含章节标题</span></div></div>
<div class="export-opt" onclick="showToast('打包为 .novel 项目包');closeModal('exportModal')"><span class="export-icon">📦</span><div class="export-info"><span class="export-name">笔临项目包 .novel</span><span class="export-desc">整书数据打包,含版本历史+设定+大纲</span></div></div>
</div></div>
</div></div>
@@ -2244,6 +2321,83 @@
<div class="modal-footer"><button class="btn" onclick="closeModal('templateModal')">取消</button><button class="btn primary" onclick="applyTemplate('generic');closeModal('templateModal')">创建章节</button></div>
</div></div>
<!-- Global Search -->
<div class="modal-overlay hidden" id="searchModal" role="dialog" aria-modal="true" aria-label="全局搜索">
<div class="modal" style="max-width:680px;">
<div class="modal-header"><h3>🔍 全局搜索</h3><button class="modal-close" onclick="closeModal('searchModal')" aria-label="关闭"></button></div>
<div class="modal-body">
<div class="search-input-row">
<input type="text" id="searchInput" placeholder="搜索章节、大纲、设定、灵感、地标..." autofocus>
<select style="padding:8px;font-size:11px;background:var(--bg-tertiary);color:#fff;border:1px solid var(--border);border-radius:4px;" aria-label="搜索范围"><option>全书</option><option>当前卷</option><option>当前章</option></select>
</div>
<div style="display:flex;gap:8px;margin-bottom:12px;font-size:11px;">
<label><input type="checkbox"> 正则</label><label><input type="checkbox"> 全词匹配</label><label><input type="checkbox"> 区分大小写</label>
</div>
<div id="searchResults">
<div class="search-result" onclick="showToast('跳转到第3章');closeModal('searchModal')"><div class="sr-type">章节 · 第3章 入门考验</div><div>...林远深吸一口气,推开木门走了出去。门外是一个宽阔的<b>演武场</b>...</div></div>
<div class="search-result" onclick="showToast('跳转到设定:测灵石');closeModal('searchModal')"><div class="sr-type">设定 · 测灵石</div><div class="sr-context">青云宗测试弟子灵根的法器,可显现一至五纹...</div></div>
<div class="search-result" onclick="showToast('跳转到地标');closeModal('searchModal')"><div class="sr-type">地标 · 第5章 TODO</div><div class="sr-context">[TODO: 补写林远与长老的私下对话]</div></div>
</div>
</div>
<div class="modal-footer"><button class="btn" onclick="closeModal('searchModal')">关闭</button><button class="btn" onclick="showToast('展开替换预览')">替换...</button></div>
</div>
</div>
<!-- Import Book -->
<div class="modal-overlay hidden" id="importModal" role="dialog" aria-modal="true" aria-label="导入书籍">
<div class="modal" style="max-width:520px;">
<div class="modal-header"><h3>📥 导入书籍</h3><button class="modal-close" onclick="closeModal('importModal')" aria-label="关闭"></button></div>
<div class="modal-body">
<p style="color:var(--text-secondary);font-size:12px;margin-bottom:12px;">支持 .txt、.docx、.md 及笔临专用 .novel 项目包</p>
<div class="form-group"><label>选择文件</label><button class="btn primary" style="width:100%;padding:12px;" onclick="showToast('打开文件选择器...')"><i class="fa-solid fa-folder-open"></i> 浏览文件...</button></div>
<div class="form-group"><label>章节分隔规则</label><select style="width:100%;padding:8px;background:var(--bg-tertiary);color:#fff;border:1px solid var(--border);border-radius:4px;"><option>自动识别(# 第.*章)</option><option>双换行分段</option><option>自定义正则</option></select></div>
<p style="font-size:11px;color:var(--text-muted);margin-top:8px;">大于 20MB 的文件将提示确认,导入过程显示进度条。</p>
</div>
<div class="modal-footer"><button class="btn" onclick="closeModal('importModal')">取消</button><button class="btn primary" onclick="showToast('📥 开始导入...');closeModal('importModal')">开始导入</button></div>
</div>
</div>
<!-- Inspiration Capture -->
<div class="modal-overlay hidden" id="inspirationModal" role="dialog" aria-modal="true" aria-label="灵感快速捕获">
<div class="modal" style="max-width:480px;">
<div class="modal-header"><h3>💡 灵感快速捕获</h3><button class="modal-close" onclick="closeModal('inspirationModal')" aria-label="关闭"></button></div>
<div class="modal-body inspiration-capture">
<textarea id="inspirationInput" placeholder="记录一闪而过的想法..."></textarea>
<div class="form-group" style="margin-top:10px;"><label>标签(可选)</label><input type="text" placeholder="如:伏笔、第三卷、角色" style="width:100%;padding:8px;border-radius:4px;border:1px solid var(--border);background:var(--bg-tertiary);color:#fff;"></div>
<div class="form-group"><label>关联书籍</label><select style="width:100%;padding:8px;background:var(--bg-tertiary);color:#fff;border:1px solid var(--border);border-radius:4px;"><option>仙道长青(当前)</option><option>不关联书籍</option></select></div>
</div>
<div class="modal-footer"><button class="btn" onclick="showToast('🎤 语音输入...')"><i class="fa-solid fa-microphone"></i> 语音</button><button class="btn" onclick="closeModal('inspirationModal')">取消</button><button class="btn primary" onclick="saveInspiration()">保存</button></div>
</div>
</div>
<!-- Landmarks List -->
<div class="modal-overlay hidden" id="landmarksModal" role="dialog" aria-modal="true" aria-label="写作地标清单">
<div class="modal" style="max-width:560px;">
<div class="modal-header"><h3>📌 写作地标与待办</h3><button class="modal-close" onclick="closeModal('landmarksModal')" aria-label="关闭"></button></div>
<div class="modal-body">
<div style="display:flex;gap:6px;margin-bottom:12px;"><button class="btn" style="font-size:10px;background:var(--accent);color:#fff;">全部</button><button class="btn" style="font-size:10px;">待办</button><button class="btn" style="font-size:10px;">伏笔</button><button class="btn" style="font-size:10px;">待查证</button></div>
<div class="search-result" onclick="showToast('跳转到第5章地标');closeModal('landmarksModal')"><div class="sr-type">TODO · 第5章</div><div>补写林远与长老的私下对话</div></div>
<div class="search-result" onclick="showToast('跳转到第3章');closeModal('landmarksModal')"><div class="sr-type">伏笔提醒 · 第3章</div><div>测灵石异常发热 — 需在后续章节回收</div></div>
</div>
<div class="modal-footer"><button class="btn" onclick="closeModal('landmarksModal')">关闭</button><button class="btn primary" onclick="showToast('插入新地标');closeModal('landmarksModal')">+ 插入地标</button></div>
</div>
</div>
<!-- Chapter Bridge (衔接检查) -->
<div class="modal-overlay hidden" id="bridgeModal" role="dialog" aria-modal="true" aria-label="章间衔接检查">
<div class="modal" style="max-width:600px;">
<div class="modal-header"><h3>🔗 章间衔接 — 第2章 → 第3章</h3><button class="modal-close" onclick="closeModal('bridgeModal')" aria-label="关闭"></button></div>
<div class="modal-body">
<h4 style="font-size:12px;color:var(--text-muted);margin-bottom:6px;">上一章末尾(第2章)</h4>
<div style="padding:12px;background:var(--bg-tertiary);border-radius:var(--radius-sm);font-size:12px;line-height:1.7;margin-bottom:12px;border-left:3px solid var(--accent);">...三纹灵根觉醒的异象尚未散去,林远站在原地,感受着体内翻涌的灵力。他知道,从这一刻起,一切都将不同。</div>
<h4 style="font-size:12px;color:var(--text-muted);margin-bottom:6px;">本章已写开头(第3章)</h4>
<div style="padding:12px;background:var(--bg-tertiary);border-radius:var(--radius-sm);font-size:12px;line-height:1.7;margin-bottom:12px;">晨光透过稀疏的竹帘,在青石地面上投下细碎的光斑。林远深吸一口气,推开木门走了出去...</div>
<div style="padding:10px;background:var(--accent-glow);border-radius:var(--radius-sm);font-size:11px;color:var(--text-secondary);">💡 AI 建议:上一章以「一切都将不同」收束,本章可从时间跳转(数日后抵达宗门)或接续同一日清晨出发,避免重复「深吸一口气」式开头。</div>
</div>
<div class="modal-footer"><label style="font-size:11px;color:var(--text-muted);margin-right:auto;"><input type="checkbox"> 本章不再提示</label><button class="btn primary" onclick="closeModal('bridgeModal')">开始写作</button></div>
</div>
</div>
<!-- Onboarding Wizard -->
<div class="modal-overlay hidden" id="onboardingModal"><div class="modal" style="max-width:560px;">
<div class="modal-header"><h3>✒ 欢迎使用笔临</h3></div>
@@ -2430,7 +2584,36 @@
showToast('✅ 书籍已创建:' + name);
}
function showImportModal() { showToast('📥 导入功能:支持.txt/.docx/.md及.novel项目包。大于20MB会提示确认。'); }
function showImportModal() { document.getElementById('importModal').classList.remove('hidden'); }
function showSearchModal() { document.getElementById('searchModal').classList.remove('hidden'); setTimeout(function() { var i = document.getElementById('searchInput'); if (i) i.focus(); }, 100); }
function showInspirationModal() { document.getElementById('inspirationModal').classList.remove('hidden'); setTimeout(function() { var i = document.getElementById('inspirationInput'); if (i) i.focus(); }, 100); }
function showLandmarksModal() { document.getElementById('landmarksModal').classList.remove('hidden'); }
function showBridgeModal() { document.getElementById('bridgeModal').classList.remove('hidden'); }
function saveInspiration() {
var t = document.getElementById('inspirationInput').value.trim();
if (!t) { showToast('请输入灵感内容'); return; }
closeModal('inspirationModal');
document.getElementById('inspirationInput').value = '';
showToast('💡 灵感已保存');
}
function toggleReferencePanel() {
var panel = document.getElementById('reference-panel');
var btn = document.getElementById('btnReference');
panel.classList.toggle('open');
if (btn) btn.classList.toggle('active', panel.classList.contains('open'));
showToast(panel.classList.contains('open') ? '📎 引用面板已打开' : '引用面板已关闭');
}
function switchRefTab(type, el) {
document.querySelectorAll('.ref-tab').forEach(function(t) { t.classList.remove('active'); });
el.classList.add('active');
showToast('引用:' + (type === 'setting' ? '设定' : type === 'outline' ? '大纲' : '灵感'));
}
function setAiMode(mode, el) {
document.querySelectorAll('.ai-mode-tab').forEach(function(t) { t.classList.remove('active'); });
el.classList.add('active');
var labels = { chat: '对话', interactive: '交互写作', auto: '自动写作', wizard: '向导模式' };
showToast('AI 模式:' + (labels[mode] || mode));
}
// ============ SIDEBAR ============
function switchSidebarPanel(panelId, btn) {
@@ -2604,7 +2787,11 @@
if (e.ctrlKey && e.altKey && e.key === 'f') { e.preventDefault(); toggleFocusMode(); }
if (e.ctrlKey && e.shiftKey && e.key === 'R') { e.preventDefault(); toggleTTS(); }
if (e.ctrlKey && e.shiftKey && e.key === 'N') { e.preventDefault(); addChapter(); }
if (e.ctrlKey && e.shiftKey && e.key === 'I') { e.preventDefault(); showToast('💡 灵感快速捕获窗已打开'); }
if (e.ctrlKey && e.shiftKey && e.key === 'F') { e.preventDefault(); showSearchModal(); }
if (e.ctrlKey && e.shiftKey && e.key === 'I') { e.preventDefault(); showInspirationModal(); }
if (e.ctrlKey && e.shiftKey && e.key === 'P') { e.preventDefault(); toggleReferencePanel(); }
if (e.ctrlKey && e.shiftKey && e.key === 'M') { e.preventDefault(); showLandmarksModal(); }
if (e.ctrlKey && e.shiftKey && e.key === 'L') { e.preventDefault(); showLandmarksModal(); }
});
// ============ V2.0 NEW FUNCTIONS ============