diff --git a/rust/crates/mnote-web/src/ssr/pages/layout.rs b/rust/crates/mnote-web/src/ssr/pages/layout.rs index 9efb2bcd..217e63b6 100644 --- a/rust/crates/mnote-web/src/ssr/pages/layout.rs +++ b/rust/crates/mnote-web/src/ssr/pages/layout.rs @@ -3634,15 +3634,18 @@ const SIDEBAR_TREE_JS: &str = r##" button.classList.toggle('is-active', active); button.setAttribute('aria-pressed', active ? 'true' : 'false'); }); - var subtitle = drawer.querySelector('.wolai-page-ai-subtitle'); - if (subtitle instanceof HTMLElement) { - subtitle.textContent = '当前页面上下文优先 · ' + pageAiProviderLabel(pageUiState.pageAiProvider); + var providerNode = drawer.querySelector('.wolai-page-ai-subtitle span:first-child'); + if (providerNode instanceof HTMLElement) { + providerNode.textContent = pageAiProviderLabel(pageUiState.pageAiProvider); } } function renderPageAiControls() { var drawer = ensurePageAiDrawer(); var activeProfile = pageAiCurrentProfile(); + drawer.setAttribute('data-page-ai-page', pageUiState.pageAiPage || 'chat'); + var profileSummary = drawer.querySelector('[data-page-ai-profile-summary]'); + if (profileSummary instanceof HTMLElement) profileSummary.textContent = activeProfile; var profileSelect = drawer.querySelector('[data-page-ai-profile-select]'); if (profileSelect instanceof HTMLSelectElement) { var profiles = pageUiState.pageAiProfiles.length ? pageUiState.pageAiProfiles : [{ name: activeProfile, active: true }]; @@ -3696,8 +3699,10 @@ const SIDEBAR_TREE_JS: &str = r##" } var memoryError = drawer.querySelector('[data-page-ai-memory-error]'); if (memoryError instanceof HTMLElement) { - memoryError.textContent = pageUiState.pageAiProfileMemoryError || ''; - memoryError.hidden = !pageUiState.pageAiProfileMemoryError; + var memoryErrorText = pageUiState.pageAiProfileMemoryError || ''; + if (memoryErrorText && memoryErrorText === pageUiState.pageAiProfileError) memoryErrorText = ''; + memoryError.textContent = memoryErrorText; + memoryError.hidden = !memoryErrorText; } var agentPanel = drawer.querySelector('[data-page-ai-agent-panel]'); if (agentPanel instanceof HTMLElement) { @@ -3814,53 +3819,27 @@ const SIDEBAR_TREE_JS: &str = r##" '
' + '
' + '

页面 AI

' + - '
当前页面上下文优先 · Hermes
' + + '
' + + 'Hermes' + + 'default' + + '由 Hermes 决定' + + '
' + + '
' + + '
' + + '' + + '' + '
' + - '' + '
' + - '
' + - '
' + - '会话' + - '等待 Hermes session' + - '
' + - '
' + - '状态' + - '空闲' + - '
' + - '
' + - '模型' + - '由 Hermes 决定' + - '
' + - '
' + - '上下文' + - '当前页' + - '
' + - '' + - '
' + - '
' + - '' + - '' + - '
' + - '' + '
' + - '
' + - '' + - '' + - '' + - '' + - '
' + '
' + + '
' + + '' + + '当前页' + + '空闲' + + '
' + + '
' + '
' + '
' + '推荐问题' + @@ -3872,21 +3851,44 @@ const SIDEBAR_TREE_JS: &str = r##" '
' + '
' + '
' + - '
' + - '
' + - 'mnote tools' + - '暂无 tool call' + - '
' + - '' + - '
' + - '
' + - '
' + '
' + '' + '' + + '' + '' + '
' + ''; @@ -3920,6 +3945,10 @@ const SIDEBAR_TREE_JS: &str = r##" var drawer = ensurePageAiDrawer(); var list = drawer.querySelector('[data-page-ai-panel="chat"] [data-page-ai-suggestion-list]'); if (!(list instanceof HTMLElement)) return; + var container = list.closest('.wolai-page-ai-suggestions'); + if (container instanceof HTMLElement) { + container.hidden = pageUiState.pageAiPage !== 'chat' || pageUiState.pageAiMessages.length > 0; + } var suggestions = pageAiSuggestions(); var offset = pageUiState.pageAiSuggestionIndex % suggestions.length; var ordered = suggestions.slice(offset).concat(suggestions.slice(0, offset)).slice(0, 3); @@ -3930,6 +3959,7 @@ const SIDEBAR_TREE_JS: &str = r##" function renderPageAiConversation() { var drawer = ensurePageAiDrawer(); + renderPageAiSuggestions(); var conversation = drawer.querySelector('[data-page-ai-panel="' + cssEscape(pageUiState.pageAiPage || 'chat') + '"] [data-page-ai-conversation]'); if (!(conversation instanceof HTMLElement)) return; if (pageUiState.pageAiPage === 'history') { diff --git a/rust/crates/mnote-web/src/ssr/styles.rs b/rust/crates/mnote-web/src/ssr/styles.rs index a0fc7abe..b398edab 100644 --- a/rust/crates/mnote-web/src/ssr/styles.rs +++ b/rust/crates/mnote-web/src/ssr/styles.rs @@ -2654,10 +2654,10 @@ body { height: 100%; display: flex; flex-direction: column; - gap: 14px; - padding: 16px; + gap: 12px; + padding: 14px; border: 1px solid rgba(27, 28, 28, 0.08); - border-radius: 18px; + border-radius: 14px; background: rgba(255, 255, 255, 0.98); box-shadow: -18px 0 42px rgba(27, 28, 28, 0.14); } @@ -2668,19 +2668,28 @@ body { gap: 4px; } -.wolai-page-ai-statusbar { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(68px, auto) minmax(82px, auto) minmax(72px, auto) auto; - gap: 8px; - align-items: stretch; +.wolai-page-ai-header-actions { + display: inline-flex; + align-items: center; + gap: 4px; } -.wolai-page-ai-statusitem { - min-width: 0; - padding: 8px; - border: 1px solid rgba(27, 28, 28, 0.08); - border-radius: 8px; - background: #FAFAFA; +.wolai-page-ai-icon { + width: 28px; + height: 28px; + border: 0; + border-radius: 6px; + background: transparent; + color: #5A5A5A; + font-size: 16px; + line-height: 1; + cursor: pointer; +} + +.wolai-page-ai-icon:hover, +.wolai-page-ai-icon.is-active { + background: #F3F3F2; + color: #1B1C1C; } .wolai-page-ai-statuslabel, @@ -2695,6 +2704,27 @@ body { line-height: 16px; } +.wolai-page-ai-subtitle { + display: flex; + min-width: 0; + flex-wrap: wrap; + gap: 4px 8px; +} + +.wolai-page-ai-subtitle span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.wolai-page-ai-subtitle span:not(:first-child)::before, +.wolai-page-ai-chat-meta span:not(:first-child)::before { + margin-right: 8px; + color: #C9C5BE; + content: "·"; +} + .wolai-page-ai-statusvalue { display: block; min-width: 0; @@ -2726,7 +2756,7 @@ body { cursor: not-allowed; } -.wolai-page-ai-topbar { +.wolai-page-ai-settings-grid { display: grid; grid-template-columns: minmax(0, 1fr) 132px; gap: 8px; @@ -2769,13 +2799,7 @@ body { min-height: 0; flex: 1 1 auto; flex-direction: column; - gap: 16px; -} - -.wolai-page-ai-tabs { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 6px; + gap: 10px; } .wolai-page-ai-panel-section { @@ -2783,17 +2807,87 @@ body { min-height: 0; flex: 1 1 auto; flex-direction: column; - gap: 12px; + gap: 10px; } .wolai-page-ai-panel-section[hidden] { display: none !important; } +.wolai-page-ai-drawer:not([data-page-ai-page="chat"]) .wolai-page-ai-footer { + display: none; +} + +.wolai-page-ai-chat-meta { + display: flex; + min-height: 24px; + align-items: center; + gap: 8px; + overflow: hidden; + color: #8B8782; + font-size: 11px; + line-height: 16px; +} + +.wolai-page-ai-session-button { + min-width: 0; + max-width: 190px; + overflow: hidden; + padding: 0; + border: 0; + background: transparent; + color: #5A5A5A; + font: inherit; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; +} + +.wolai-page-ai-session-button:hover { + color: #1B1C1C; +} + +.wolai-page-ai-settings-head { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 8px; + align-items: center; +} + +.wolai-page-ai-back { + height: 30px; + padding: 0 8px; + border: 0; + border-radius: 6px; + background: transparent; + color: #5A5A5A; + font-size: 12px; + cursor: pointer; +} + +.wolai-page-ai-back:hover { + background: #F3F3F2; + color: #1B1C1C; +} + +.wolai-page-ai-settings-tabs { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 4px; + padding: 2px; + border-radius: 8px; + background: #F3F3F2; +} + .wolai-page-ai-suggestions { display: flex; flex-direction: column; - gap: 10px; + gap: 8px; +} + +.wolai-page-ai-suggestions[hidden] { + display: none !important; } .wolai-page-ai-suggestions-header, @@ -2886,10 +2980,10 @@ body { } .wolai-page-ai-suggestion { - min-height: 32px; - padding: 8px 10px; + min-height: 30px; + padding: 6px 9px; border: 1px solid rgba(27, 28, 28, 0.08); - border-radius: 10px; + border-radius: 8px; background: #FFF; color: #1B1C1C; font-size: 12px; @@ -3057,7 +3151,18 @@ body { .wolai-page-ai-footer { display: flex; flex-direction: column; - gap: 10px; + gap: 8px; +} + +.wolai-page-ai-tab { + min-height: 28px; + padding: 0 8px; + border: 0; + border-radius: 6px; + background: transparent; + color: #5A5A5A; + font-size: 12px; + cursor: pointer; } .wolai-page-ai-tab.is-active { @@ -3070,33 +3175,90 @@ body { color: #FFF; } -.wolai-page-ai-input-row { +.wolai-page-ai-composer { display: flex; - gap: 8px; - align-items: flex-end; + flex-direction: column; + overflow: hidden; + border: 1px solid rgba(27, 28, 28, 0.12); + border-radius: 10px; + background: #FFF; +} + +.wolai-page-ai-composer:focus-within { + border-color: rgba(27, 28, 28, 0.32); +} + +.wolai-page-ai-composer-bar { + display: flex; + min-height: 36px; + align-items: center; + gap: 6px; + padding: 0 6px 6px; +} + +.wolai-page-ai-composer-spacer { + flex: 1 1 auto; +} + +.wolai-page-ai-tool-button { + width: 28px; + height: 28px; + border: 1px solid rgba(27, 28, 28, 0.1); + border-radius: 6px; + background: #FFF; + color: #5A5A5A; + font-size: 14px; + cursor: pointer; +} + +.wolai-page-ai-tool-button:hover { + border-color: rgba(27, 28, 28, 0.2); + color: #1B1C1C; } .wolai-page-ai-input { - flex: 1 1 auto; - min-height: 88px; - padding: 10px 12px; - border: 1px solid rgba(27, 28, 28, 0.1); - border-radius: 12px; - background: #FFF; + width: 100%; + min-height: 76px; + padding: 10px 10px 4px; + border: 0; + background: transparent; color: #1B1C1C; font-size: 13px; line-height: 20px; resize: none; } -.wolai-page-ai-send { - width: 36px; - height: 36px; +.wolai-page-ai-input:focus { + outline: none; +} + +.wolai-page-ai-stop { + min-width: 42px; + height: 28px; + padding: 0 10px; border: 0; - border-radius: 10px; + border-radius: 6px; + background: #F3F3F2; + color: #5A5A5A; + font-size: 12px; + cursor: pointer; +} + +.wolai-page-ai-stop:disabled { + color: #B5B1AA; + cursor: not-allowed; +} + +.wolai-page-ai-send { + min-width: 52px; + height: 28px; + padding: 0 12px; + border: 0; + border-radius: 6px; background: #1B1C1C; color: #FFF; - font-size: 16px; + font-size: 12px; + font-weight: 600; cursor: pointer; } @@ -3119,11 +3281,8 @@ body { width: min(100vw - 24px, 420px); } - .wolai-page-ai-statusbar { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .wolai-page-ai-topbar { + .wolai-page-ai-settings-grid, + .wolai-page-ai-settings-head { grid-template-columns: minmax(0, 1fr); } diff --git a/scripts/task-hermes-page-ai-agent-skill-smoke.js b/scripts/task-hermes-page-ai-agent-skill-smoke.js index 49700e14..462ed887 100644 --- a/scripts/task-hermes-page-ai-agent-skill-smoke.js +++ b/scripts/task-hermes-page-ai-agent-skill-smoke.js @@ -166,19 +166,19 @@ async function main() { ); await page.getByTestId("wolai-floating-ai").click({ timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-icon[data-page-ai-tab="agent"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator("[data-page-ai-profile-select]").selectOption("chemist", { timeout: UI_TIMEOUT_MS }); await page.waitForFunction(() => document.documentElement.getAttribute("data-mnote-page-ai-profile") === "chemist", null, { timeout: UI_TIMEOUT_MS, }); - await page.locator('[data-page-ai-tab="agent"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator('[data-page-ai-memory-editor="soul"]').fill(`SOUL-${suffix}`, { timeout: UI_TIMEOUT_MS }); await page.locator('[data-page-ai-memory-save="soul"]').click({ timeout: UI_TIMEOUT_MS }); await page.waitForFunction(() => document.documentElement.getAttribute("data-mnote-page-ai-memory-saved") === "soul", null, { timeout: UI_TIMEOUT_MS, }); - await page.locator('[data-page-ai-tab="skills"]').click({ timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-panel-section:not([hidden]) [data-page-ai-tab="skills"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator("[data-page-ai-skill-search]").fill("writing", { timeout: UI_TIMEOUT_MS }); await page.locator('[data-page-ai-skill-toggle="ai-writing-detection"]').click({ timeout: UI_TIMEOUT_MS }); await page.waitForFunction( @@ -187,7 +187,7 @@ async function main() { { timeout: UI_TIMEOUT_MS }, ); - await page.locator('[data-page-ai-tab="chat"]').click({ timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-panel-section:not([hidden]) [data-page-ai-tab="chat"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator("[data-page-ai-input]").fill(`请使用 chemist agent 总结 ${title}`, { timeout: UI_TIMEOUT_MS }); await page.locator('[data-page-ai-action="send"]').click({ timeout: UI_TIMEOUT_MS }); await page.waitForFunction( diff --git a/scripts/task-hermes-page-ai-runtime-controls-smoke.js b/scripts/task-hermes-page-ai-runtime-controls-smoke.js index 6ea86b6d..623017a9 100644 --- a/scripts/task-hermes-page-ai-runtime-controls-smoke.js +++ b/scripts/task-hermes-page-ai-runtime-controls-smoke.js @@ -119,6 +119,8 @@ async function main() { ); await page.getByTestId("wolai-floating-ai").click({ timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-icon[data-page-ai-tab="agent"]').click({ timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-panel-section:not([hidden]) [data-page-ai-tab="runtime"]').click({ timeout: UI_TIMEOUT_MS }); await page.waitForFunction( (expected) => window.__mnoteHermesSettingsUrl === expected, EXPECTED_SETTINGS_URL, @@ -132,7 +134,9 @@ async function main() { const settingsDisabled = await page.locator('[data-page-ai-action="open-hermes-settings"]').isDisabled(); assert.equal(settingsDisabled, false, "配置 Hermes upstream 后设置入口不应禁用"); + await page.locator('.wolai-page-ai-panel-section:not([hidden]) [data-page-ai-tab="agent"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator("[data-page-ai-context-scope]").selectOption("options", { timeout: UI_TIMEOUT_MS }); + await page.locator('.wolai-page-ai-panel-section:not([hidden]) [data-page-ai-tab="chat"]').click({ timeout: UI_TIMEOUT_MS }); await page.locator("[data-page-ai-input]").fill(`请只读取页面设置 ${title}`, { timeout: UI_TIMEOUT_MS }); await page.locator('[data-page-ai-action="send"]').click({ timeout: UI_TIMEOUT_MS }); await page.waitForFunction(