diff --git a/static/app.js b/static/app.js index 014631e..0a5511f 100644 --- a/static/app.js +++ b/static/app.js @@ -1970,12 +1970,15 @@ document.querySelectorAll('.s-eye-btn').forEach(btn => { }); }); $('settings-btn')?.addEventListener('click', async () => { await loadSettings(); openSettings(false); }); -$('s-close-btn').addEventListener('click', async () => { await loadSettings(); toast('Settings reloaded', 'success'); }); +document.addEventListener('click', async e => { + if (e.target.closest('.s-reload-btn')) { await loadSettings(); toast('Settings reloaded', 'success'); } +}); $('s-use-parakeet-asr')?.addEventListener('click', () => { $('s-whisper-url').value = $('s-nvidia-asr-url').value || 'http://host.docker.internal:8092'; }); $('s-use-nvidia-router')?.addEventListener('click', () => { const url = $('s-nvidia-router-url').value || 'http://host.docker.internal:8090'; $('s-whisper-url').value = url; $('s-nvidia-tts-url').value = url; }); $('s-use-faster-whisper')?.addEventListener('click', () => { $('s-whisper-url').value = $('s-faster-whisper-url').value || 'http://host.docker.internal:8000'; }); $('s-use-whisper-cpp')?.addEventListener('click', () => { $('s-whisper-url').value = $('s-whisper-cpp-url').value || 'http://host.docker.internal:8080'; }); -$('s-save-btn').addEventListener('click', async () => { +document.addEventListener('click', async e => { if (!e.target.closest('.s-save-btn')) return; +{ let ttsExtraParamsByBackend = {}; const paramFields = [ ['voice_clone', 's-tts-extra-voice-clone', 'Voice Clone/Base'], @@ -2036,7 +2039,7 @@ $('s-save-btn').addEventListener('click', async () => { markSettingsSeen(); renderIntegrationSnippets(); toast('Settings saved', 'success'); -}); +}}); // Theme select in General settings document.addEventListener('change', e => { diff --git a/static/nav.js b/static/nav.js index 4a9195c..bbe1351 100644 --- a/static/nav.js +++ b/static/nav.js @@ -29,6 +29,15 @@ if (name === 'getvoices' && typeof loadGetVoices === 'function') loadGetVoices(); } + function applySettingsPage(cat) { + document.querySelectorAll('.s-settings-page').forEach(function (p) { + p.classList.toggle('is-active', p.dataset.page === cat); + }); + document.querySelectorAll('[data-settings-cat]').forEach(function (el) { + el.classList.toggle('is-active', el.dataset.settingsCat === cat); + }); + } + function showSection(sectionId) { SECTIONS.forEach(function (id) { var el = document.getElementById(id); @@ -41,16 +50,19 @@ // Voices nav tree var voicesTree = document.getElementById('nav-voices-tree'); var voicesChevron = document.getElementById('nav-voices-chevron'); - var isVoices = sectionId === 's-voices'; - if (voicesTree) voicesTree.classList.toggle('open', isVoices); - if (voicesChevron) voicesChevron.classList.toggle('open', isVoices); + if (voicesTree) voicesTree.classList.toggle('open', sectionId === 's-voices'); + if (voicesChevron) voicesChevron.classList.toggle('open', sectionId === 's-voices'); // Settings nav tree var settingsTree = document.getElementById('nav-settings-tree'); var settingsChevron = document.getElementById('nav-settings-chevron'); - var isSettings = sectionId === 's-settings'; - if (settingsTree) settingsTree.classList.toggle('open', isSettings); - if (settingsChevron) settingsChevron.classList.toggle('open', isSettings); + if (settingsTree) settingsTree.classList.toggle('open', sectionId === 's-settings'); + if (settingsChevron) settingsChevron.classList.toggle('open', sectionId === 's-settings'); + + // When entering settings, show the active sub-page (default: connections) + if (sectionId === 's-settings') { + applySettingsPage(window._settingsSidebarCat || 'connections'); + } var main = document.getElementById('main-content'); if (main) main.scrollTop = 0; @@ -96,27 +108,13 @@ }; // ── Settings tree sub-navigation ────────────────────────────────────────── - window._settingsSidebarCat = null; + window._settingsSidebarCat = 'connections'; window.navSettingsCat = function (cat) { - navTo('s-settings'); window._settingsSidebarCat = cat; - document.querySelectorAll('[data-settings-cat]').forEach(function (el) { - el.classList.toggle('is-active', el.dataset.settingsCat === cat); - }); + navTo('s-settings'); // showSection will call applySettingsPage(cat) if (cat === 'logs' && typeof loadSettingsLogs === 'function') loadSettingsLogs(); - // Scroll inside main-content to the target section - var target = document.getElementById('s-settings-' + cat); - if (target) { - setTimeout(function () { - var main = document.getElementById('main-content'); - if (main) { - var mainRect = main.getBoundingClientRect(); - var targetRect = target.getBoundingClientRect(); - main.scrollTo({ top: main.scrollTop + targetRect.top - mainRect.top - 16, behavior: 'smooth' }); - } - }, 50); - } + if (cat === 'about' && typeof renderSettingsAbout === 'function') renderSettingsAbout(); }; // Show default section on load diff --git a/static/sections/s-settings.html b/static/sections/s-settings.html index ca3365c..b2470b4 100644 --- a/static/sections/s-settings.html +++ b/static/sections/s-settings.html @@ -7,20 +7,14 @@
Configure the service URLs you use. Advanced payloads, folders, and keys are below.
+ +Interface preferences.
Service URLs for each backend. Change these first when setting up.
+ +Service URLs for each backend. Change these first when setting up.
+Controls how previews play and how OpenAI-compatible requests are shaped.
+Controls how previews play and how OpenAI-compatible requests are shaped.
+Extra JSON fields sent alongside each backend request. Usually only needed for advanced tuning.
+Container paths for voice files. Match these to your Portainer volume mounts.
+Usually empty for local containers. Set a dummy value like sk-local if a backend requires an Authorization header.
Export all voices and settings as a ZIP for backup or migration. Import to restore. API keys are excluded from exports.
-Export all voices and settings as a ZIP for backup or migration. API keys are excluded from exports.
+Recent server activity. Useful for debugging backend connections and API errors.
+ +Recent server activity. Useful for debugging backend connections and API errors.
+Clone, design, and deploy custom voices using local AI backends. Compatible with Qwen3-TTS, Kokoro FastAPI, NVIDIA Magpie, and any OpenAI-compatible TTS/STT endpoint.
@@ -338,6 +372,6 @@