From 33fecf3afe9ebc8cfee145b94e2d93731edcebd5 Mon Sep 17 00:00:00 2001 From: Mic Date: Wed, 25 Mar 2026 00:01:00 +0100 Subject: [PATCH] summary: see more / see less added. see #580 --- _locales/en/messages.json | 16 ++++++++++++++++ claude-spec/05-options.md | 4 +++- js/mzta-compose-script.js | 27 +++++++++++++++++++++++++++ mzta-background.js | 9 +++++---- options/mzta-options-default.js | 1 + pages/summarize/mzta-summarize.html | 9 +++++++++ 6 files changed, 61 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7bbd2509..7f28055b 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1964,6 +1964,22 @@ "message": "Choose where the summary result is displayed. Inline mode shows a summary banner directly in the message pane. Chat window mode opens the AI chat window.", "description": "" }, + "prefs_OptionText_summarize_max_display_length": { + "message": "Max display length", + "description": "" + }, + "prefs_OptionText_summarize_max_display_length_Info": { + "message": "Maximum number of characters to display in the inline summary. Set to 0 for no limit.", + "description": "" + }, + "summarize_see_more": { + "message": "See more", + "description": "" + }, + "summarize_see_less": { + "message": "See less", + "description": "" + }, "summarize_title": { "message": "ThunderAI Overview", "description": "" diff --git a/claude-spec/05-options.md b/claude-spec/05-options.md index 8f402497..81b1747a 100644 --- a/claude-spec/05-options.md +++ b/claude-spec/05-options.md @@ -97,6 +97,7 @@ These are generated programmatically at the bottom of `mzta-options-default.js` | `summarize` | `false` | Enable email summarization | | `summarize_auto` | `0` | Auto-summarize mode: `0` = disabled, `1` = manual (show "click to generate" button), `2` = automatic (generate on message open) | | `summarize_display_mode` | `'inline'` | Where to display summaries: `'inline'` = message pane banner, `'webchat'` = AI chat window. Note: `summarize_auto = 2` always uses inline regardless of this setting. | +| `summarize_max_display_length` | `0` | Maximum characters shown in inline summary before truncation. `0` = no limit (show full text). When set, text is truncated at a word boundary and a "See more"/"See less" toggle link is shown. | ### Summarize Settings Page (`pages/summarize/`) @@ -111,7 +112,8 @@ The summarize settings page provides: - `'inline'` — summary banner in the message pane (default) - `'webchat'` — opens the AI chat window - Note: `summarize_auto = 2` always generates inline regardless of this setting. Context menu summarize with multiple messages always falls back to webchat. -4. **Three editable prompts** (used by context menu summarize and webchat mode): +4. **Max display length** (`summarize_max_display_length`) — number input, limits inline summary text to N characters. `0` = no limit. When truncated, a "See more"/"See less" toggle link is appended. +5. **Three editable prompts** (used by context menu summarize and webchat mode): - Summarize instruction prompt (`prompt_summarize`) - Email template prompt (`prompt_summarize_email_template`) - Email separator prompt (`prompt_summarize_email_separator`) diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index fac4799c..4b9f7e28 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -933,6 +933,33 @@ switch (message.command) { summaryTextWrapper.appendChild(summaryText); + const maxLen = summaryData.maxDisplayLength || 0; + const fullText = summaryData.summary; + if (!summaryData.error && maxLen > 0 && fullText && fullText.length > maxLen) { + let cutPos = fullText.lastIndexOf(' ', maxLen); + if (cutPos <= 0) cutPos = maxLen; + const truncated = fullText.substring(0, cutPos) + '\u2026'; + summaryText.textContent = truncated; + + const toggleLink = document.createElement('a'); + toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more"; + toggleLink.href = '#'; + toggleLink.style.cssText = 'display: inline-block; margin-top: 4px; font-size: 13px; color: ' + + (isDarkSummary ? '#6db3f2' : '#1a5fa8') + '; cursor: pointer; text-decoration: underline;'; + + let expanded = false; + toggleLink.addEventListener('click', (e) => { + e.preventDefault(); + expanded = !expanded; + summaryText.textContent = expanded ? fullText : truncated; + toggleLink.textContent = expanded + ? (browser.i18n.getMessage("summarize_see_less") || "See less") + : (browser.i18n.getMessage("summarize_see_more") || "See more"); + }); + + summaryTextWrapper.appendChild(toggleLink); + } + const summaryBody = document.createElement('div'); summaryBody.style.cssText = 'display: flex; gap: 8px; align-items: flex-start;'; summaryBody.appendChild(summaryIcon); diff --git a/mzta-background.js b/mzta-background.js index 02f9bbdf..49cc9cb8 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -220,7 +220,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { async function _initSummary() { try { let tabId = sender.tab.id; - let prefs = await browser.storage.sync.get({ summarize_auto: prefs_default.summarize_auto, summarize_display_mode: prefs_default.summarize_display_mode }); + let prefs = await browser.storage.sync.get({ summarize_auto: prefs_default.summarize_auto, summarize_display_mode: prefs_default.summarize_display_mode, summarize_max_display_length: prefs_default.summarize_max_display_length }); let message = await browser.messageDisplay.getDisplayedMessage(tabId); if (!message) return; @@ -228,7 +228,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { // Always show cached summary if available, regardless of summarize_auto let cachedSummary = await summaryStore.loadSummary(message.headerMessageId); if (cachedSummary && !cachedSummary.error) { - browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary }); + browser.tabs.sendMessage(tabId, { command: "showSummary", data: { ...cachedSummary, maxDisplayLength: prefs.summarize_max_display_length } }); return; } @@ -464,12 +464,13 @@ async function _generateSummaryForMessage(headerMessageId, tabId) { connection_type: prefs_default.connection_type, do_debug: prefs_default.do_debug, default_chatgpt_lang: prefs_default.default_chatgpt_lang, + summarize_max_display_length: prefs_default.summarize_max_display_length, ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); let cachedSummary = await summaryStore.loadSummary(headerMessageId); if (cachedSummary && !cachedSummary.error) { - browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary }); + browser.tabs.sendMessage(tabId, { command: "showSummary", data: { ...cachedSummary, maxDisplayLength: prefs.summarize_max_display_length } }); return; } @@ -524,7 +525,7 @@ async function _generateSummaryForMessage(headerMessageId, tabId) { headerMessageId: headerMessageId }; await summaryStore.saveSummary(summaryData, headerMessageId); - browser.tabs.sendMessage(tabId, { command: "showSummary", data: summaryData }); + browser.tabs.sendMessage(tabId, { command: "showSummary", data: { ...summaryData, maxDisplayLength: prefs.summarize_max_display_length } }); taWorkingStatus.stopWorking(); } catch (error) { diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 4a4cbda0..20dea23d 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -139,6 +139,7 @@ export const prefs_default = { spamfilter_enabled_accounts: [], summarize_auto: 0, // 0: disabled, 1: manual button, 2: automatic summarize_display_mode: 'inline', // 'inline' or 'webchat' + summarize_max_display_length: 0, // 0 = no limit, otherwise max chars shown inline spamfilter_show_msg_panel: true, summarize: false, ...generated_prefs diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html index 0f02deac..ea6f59c7 100644 --- a/pages/summarize/mzta-summarize.html +++ b/pages/summarize/mzta-summarize.html @@ -51,6 +51,15 @@ + + __MSG_prefs_OptionText_summarize_max_display_length__ + + + +