diff --git a/popup.js b/popup.js index 11077d7..5073bbd 100644 --- a/popup.js +++ b/popup.js @@ -163,6 +163,8 @@ document.addEventListener('DOMContentLoaded', () => { isMainOperationInProgress = true; currentMainOperationAbortController = new AbortController(); + const translateTabBtn = document.getElementById('translate-tab'); + if (translateTabBtn) translateTabBtn.classList.add('is-running'); if (clearOrStopBtn) { clearOrStopBtn.textContent = '停止'; clearOrStopBtn.classList.add('stop-btn'); @@ -174,12 +176,14 @@ document.addEventListener('DOMContentLoaded', () => { translateOutput.value = ''; try { + const isStreaming = streamTranslateCheckbox && streamTranslateCheckbox.checked; const result = await callAPI(inputVal, type, [], currentMainOperationAbortController.signal); - if (typeof result === 'string') { + // Bug 3 fix: skip overwrite if streaming already filled the output incrementally + if (typeof result === 'string' && !isStreaming) { translateOutput.value = result; - if (document.getElementById('history') && !document.getElementById('history').hidden) { - await initializeHistory(); - } + } + if (document.getElementById('history') && !document.getElementById('history').hidden) { + await initializeHistory(); } } catch (error) { if (error.name === 'AbortError') { @@ -190,6 +194,7 @@ document.addEventListener('DOMContentLoaded', () => { } } finally { isMainOperationInProgress = false; + if (translateTabBtn) translateTabBtn.classList.remove('is-running'); if (clearOrStopBtn) { clearOrStopBtn.textContent = '清空'; clearOrStopBtn.classList.remove('stop-btn'); @@ -444,8 +449,6 @@ document.addEventListener('DOMContentLoaded', () => { const currentActiveTabId = currentActiveTabButton ? currentActiveTabButton.dataset.tab : null; const targetTabId = button.dataset.tab; - - document.querySelectorAll('.tab-nav__btn').forEach(btn => { btn.classList.remove('is-active'); btn.setAttribute('aria-selected', 'false'); diff --git a/style.css b/style.css index c469a80..9408850 100644 --- a/style.css +++ b/style.css @@ -88,6 +88,28 @@ body { box-shadow: var(--shadow-md); } +/* Animated dot shown on the translate tab button while a background task is running */ +.tab-nav__btn.is-running::after { + content: ''; + display: inline-block; + width: 6px; + height: 6px; + margin-left: 5px; + border-radius: 50%; + background-color: var(--primary-color); + vertical-align: middle; + animation: pulse-dot 1.2s ease-in-out infinite; +} + +.tab-nav__btn.is-active.is-running::after { + background-color: var(--surface-color); +} + +@keyframes pulse-dot { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.4; transform: scale(0.7); } +} + /* Tab Panels */ .tab-container { display: flex;