diff --git a/docutranslate/static/index.html b/docutranslate/static/index.html index 2ceb6f2..01e7300 100644 --- a/docutranslate/static/index.html +++ b/docutranslate/static/index.html @@ -115,9 +115,9 @@ } .preview-pane-wrapper .preview-pane { - flex-grow: 1; /* Make the inner pane grow */ - border: 1px solid var(--bs-border-color); - border-radius: .375rem; + flex-grow: 1; /* Make the inner pane grow */ + border: 1px solid var(--bs-border-color); + border-radius: .375rem; overflow: auto; } @@ -230,7 +230,8 @@
-
@@ -276,9 +277,11 @@ title="获取API Key">
- -
@@ -306,10 +309,16 @@
@@ -433,7 +442,8 @@ -
+
预览
@@ -563,806 +574,866 @@ + if (mode === 'bilingual') { + previewOffcanvasLabel.textContent = '双语预览'; + + if (isMobileView) { + previewSplitInstance = Split(['#originalPreviewContainer', '#translatedPreviewContainer'], { + direction: 'vertical', sizes: [50, 50], minSize: 150, gutterSize: 10, cursor: 'row-resize', + }); + } else { + previewSplitInstance = Split(['#originalPreviewContainer', '#translatedPreviewContainer'], { + direction: 'horizontal', sizes: [50, 50], minSize: 200, gutterSize: 10, cursor: 'col-resize', + }); + } + + setBilingualViewBtn.classList.add('btn-primary'); + setBilingualViewBtn.classList.remove('btn-outline-primary'); + setTranslatedOnlyViewBtn.classList.remove('btn-primary'); + setTranslatedOnlyViewBtn.classList.add('btn-outline-primary'); + + } else { // mode === 'translatedOnly' + previewOffcanvasLabel.textContent = '译文预览'; + originalPreviewContainer.style.display = 'none'; + + if (isMobileView) { + translatedPreviewContainer.style.height = '100%'; + } else { + translatedPreviewContainer.style.width = '100%'; + } + + setTranslatedOnlyViewBtn.classList.add('btn-primary'); + setTranslatedOnlyViewBtn.classList.remove('btn-outline-primary'); + setBilingualViewBtn.classList.remove('btn-primary'); + setBilingualViewBtn.classList.add('btn-outline-primary'); + } + } + + // --- Password Toggle Functionality --- + function setupPasswordToggle(button) { + const targetId = button.dataset.target; + const passwordInput = document.getElementById(targetId); + const icon = button.querySelector('i'); + + button.addEventListener('click', () => { + if (passwordInput.type === 'password') { + passwordInput.type = 'text'; + icon.classList.remove('bi-eye-slash'); + icon.classList.add('bi-eye'); + } else { + passwordInput.type = 'password'; + icon.classList.remove('bi-eye'); + icon.classList.add('bi-eye-slash'); + } + }); + } + + + // --- Initialization --- + async function init() { + isAdminMode = window.location.pathname === '/admin'; + try { + const [metaRes, enginRes, paramsRes] = await Promise.all([ + fetch("/service/meta"), fetch('/service/engin-list'), fetch("/service/default-params") + ]); + const meta = await metaRes.json(); + versionDisplay.textContent = `v${meta.version}`; + const enginList = await enginRes.json(); + Array.from(convertEnginSelect.options).forEach(option => { + if (!enginList.includes(option.value)) { + option.disabled = true; + option.textContent += " (不可用)"; + } + }); + defaultParams = await paramsRes.json(); + } catch (error) { + console.error("Initialization failed:", error); + alert("页面初始化失败,请检查后端服务是否正常并刷新页面。"); + return; + } + + platformSelect.value = getFromStorage('translator_last_platform', 'https://api.openai.com/v1'); + updatePlatformUI(); + convertEnginSelect.value = getFromStorage('translator_convert_engin', 'mineru'); + updateConvertEnginUI(); + toLangSelect.value = getFromStorage('translator_to_lang', '中文'); + formulaCheckbox.checked = getFromStorage('translator_formula_ocr') === 'true'; + codeCheckbox.checked = getFromStorage('translator_code_ocr') === 'true'; + refineCheckbox.checked = getFromStorage('translator_refine_markdown') === 'true'; + customPromptTranslateArea.value = getFromStorage("custom_prompt_translate"); + + setupSlider(chunkSizeSlider, chunkSizeDisplay, chunkSizeReset, 'chunk_size', defaultParams); + setupSlider(concurrentSlider, concurrentDisplay, concurrentReset, 'concurrent', defaultParams); + setupSlider(temperatureSlider, temperatureDisplay, temperatureReset, 'temperature', defaultParams); + + // Setup password toggles + document.querySelectorAll('.toggle-password').forEach(button => { + setupPasswordToggle(button); + }); + + if (isAdminMode) { + document.title = "DocuTranslate - Admin Panel"; + try { + const response = await fetch('/service/task-list'); + if (!response.ok) throw new Error(`Failed to fetch task list: ${response.statusText}`); + const allTaskIds = await response.json(); + if (allTaskIds && Array.isArray(allTaskIds) && allTaskIds.length > 0) { + allTaskIds.reverse().forEach(taskId => createTaskCard(taskId, true)); + } + } catch (error) { + console.error("Admin mode: Failed to load task list from server.", error); + alert("无法从服务器加载任务列表,请检查后台连接。"); + } + updateTaskPlaceholderVisibility(); + } else { + const savedTaskIds = JSON.parse(getFromStorage('active_task_ids', '[]')); + if (savedTaskIds.length > 0) { + savedTaskIds.forEach(taskId => createTaskCard(taskId, true)); + } else { + createTaskCard(); + } + } + + platformSelect.addEventListener('change', updatePlatformUI); + apikeyInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_apikey`, e.target.value)); + modelInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_model_id`, e.target.value)); + baseUrlInput.addEventListener('input', e => { + if (platformSelect.value === 'custom') saveToStorage('translator_platform_custom_base_url', e.target.value); + }); + convertEnginSelect.addEventListener('change', updateConvertEnginUI); + mineruTokenInput.addEventListener('input', e => saveToStorage('translator_mineru_token', e.target.value)); + toLangSelect.addEventListener('change', e => saveToStorage('translator_to_lang', e.target.value)); + formulaCheckbox.addEventListener('change', e => saveToStorage('translator_formula_ocr', e.target.checked)); + codeCheckbox.addEventListener('change', e => saveToStorage('translator_code_ocr', e.target.checked)); + refineCheckbox.addEventListener('change', e => saveToStorage('translator_refine_markdown', e.target.checked)); + customPromptTranslateArea.addEventListener('input', () => saveToStorage("custom_prompt_translate", customPromptTranslateArea.value)); + + addNewTaskBtn.addEventListener('click', () => createTaskCard()); + setBilingualViewBtn.addEventListener('click', () => setPreviewDisplayMode('bilingual')); + setTranslatedOnlyViewBtn.addEventListener('click', () => setPreviewDisplayMode('translatedOnly')); + } + + // --- Theme switcher logic --- + const getPreferredTheme = () => { + const storedTheme = localStorage.getItem('theme'); + if (storedTheme) { + return storedTheme; + } + return 'auto'; + }; + const setTheme = theme => { + if (theme === 'auto') { + document.documentElement.setAttribute('data-bs-theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + } else { + document.documentElement.setAttribute('data-bs-theme', theme); + } + }; + const showActiveTheme = (theme) => { + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + element.classList.remove('active'); + }); + const activeButton = document.querySelector(`[data-bs-theme-value="${theme}"]`); + if (activeButton) { + activeButton.classList.add('active'); + } + }; + const preferredTheme = getPreferredTheme(); + setTheme(preferredTheme); + showActiveTheme(preferredTheme); + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = localStorage.getItem('theme'); + if (storedTheme === 'auto' || !storedTheme) { + setTheme('auto'); + } + }); + document.querySelectorAll('[data-bs-theme-value]').forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value'); + localStorage.setItem('theme', theme); + setTheme(theme); + showActiveTheme(theme); + }); + }); + + // --- Start the application --- + document.addEventListener('DOMContentLoaded', init); + \ No newline at end of file