Files
diodiogod-TTS-Audio-Suite/web/widget-tabs.js
T
diodiogod d9d9164382 Add tabbed Inline Edit interface to Multiline TTS Tag Editor
Implements comprehensive inline edit tag UI for Step Audio EditX post-processing with trapezoid tab design and full persistence.

New Features:
- Tabbed interface: "Character/Parameters" and "Inline Edit" tabs
- Trapezoid tab design with cyan active indicator
- Tab text never wraps (nowrap + ellipsis overflow)
- Inline edit tag sections for all tag types:
  * Paralinguistic (Laughter, Breathing, Sigh, etc.) - 10 types
  * Emotion (happy, sad, angry, etc.) - 14 emotions
  * Style (whisper, serious, child, etc.) - 32 styles
  * Speed (faster, slower, more_faster, more_slower)
  * Voice Restoration (with VC passes and reference iteration)

Intelligent Tag Insertion:
- Pipe-separator support for combining multiple tags (e.g., <Laughter:2|emotion:happy>)
- Smart tag detection: cursor inside/after existing tag adds with pipe separator
- Tag type replacement: adding same type replaces existing (e.g., emotion:sad replaces emotion:happy)
- Iteration control via sliders (1-5 iterations)
- Toast notifications for insertion feedback

Full Persistence:
- All dropdown selections saved to localStorage
- All iteration slider positions saved to localStorage
- Values restored on ComfyUI restart/browser reload
- Fixed parameter section to restore saved values (was only saving, not restoring)

Syntax Highlighting:
- Inline edit tags highlighted in magenta (#ff66ff)
- Distinguishes from character tags (cyan)

Files Added:
- web/widget-inline-edit-section.js - Inline edit UI builder
- web/widget-tabs.js - Tabbed interface system

Files Modified:
- web/string_multiline_tag_editor.js - Integrated tabs and inline edit section
- web/widget-event-handlers.js - Tag insertion logic with pipe-separator support
- web/widget-parameter-section.js - Fixed parameter value restoration
2025-12-09 15:38:42 -03:00

140 lines
5.8 KiB
JavaScript

/**
* 🏷️ Widget Tabs System
* Creates tabbed interface for Character/Parameters and Inline Edit sections
*/
export function buildTabSystem(state, storageKey) {
// Tab container
const tabContainer = document.createElement("div");
tabContainer.style.display = "flex";
tabContainer.style.flexDirection = "column";
tabContainer.style.height = "100%";
tabContainer.style.overflow = "hidden";
// Tab headers
const tabHeaders = document.createElement("div");
tabHeaders.style.display = "flex";
tabHeaders.style.borderBottom = "1px solid #444";
tabHeaders.style.marginBottom = "10px";
tabHeaders.style.flexShrink = "0";
const charParamTab = document.createElement("div");
charParamTab.textContent = "Character/Parameters";
charParamTab.style.flex = "1";
charParamTab.style.padding = "8px 10px 6px 10px";
charParamTab.style.textAlign = "center";
charParamTab.style.cursor = "pointer";
charParamTab.style.fontSize = "11px";
charParamTab.style.fontWeight = "bold";
charParamTab.style.background = "linear-gradient(to bottom, #3a3a3a 0%, #2e2e2e 100%)";
charParamTab.style.borderRight = "1px solid #1a1a1a";
charParamTab.style.borderTop = "2px solid #555";
charParamTab.style.borderLeft = "1px solid #555";
charParamTab.style.borderBottom = "none";
charParamTab.style.clipPath = "polygon(8% 0%, 92% 0%, 100% 100%, 0% 100%)";
charParamTab.style.transition = "all 0.2s ease";
charParamTab.style.position = "relative";
charParamTab.style.marginRight = "2px";
charParamTab.style.whiteSpace = "nowrap";
charParamTab.style.overflow = "hidden";
charParamTab.style.textOverflow = "ellipsis";
charParamTab.dataset.tab = "char-param";
const inlineEditTab = document.createElement("div");
inlineEditTab.textContent = "Inline Edit";
inlineEditTab.style.flex = "1";
inlineEditTab.style.padding = "8px 10px 6px 10px";
inlineEditTab.style.textAlign = "center";
inlineEditTab.style.cursor = "pointer";
inlineEditTab.style.fontSize = "11px";
inlineEditTab.style.fontWeight = "bold";
inlineEditTab.style.background = "linear-gradient(to bottom, #2a2a2a 0%, #222 100%)";
inlineEditTab.style.borderTop = "2px solid #444";
inlineEditTab.style.borderRight = "1px solid #555";
inlineEditTab.style.borderBottom = "none";
inlineEditTab.style.clipPath = "polygon(8% 0%, 92% 0%, 100% 100%, 0% 100%)";
inlineEditTab.style.transition = "all 0.2s ease";
inlineEditTab.style.position = "relative";
inlineEditTab.style.whiteSpace = "nowrap";
inlineEditTab.style.overflow = "hidden";
inlineEditTab.style.textOverflow = "ellipsis";
inlineEditTab.dataset.tab = "inline-edit";
tabHeaders.appendChild(charParamTab);
tabHeaders.appendChild(inlineEditTab);
// Tab content containers
const charParamContent = document.createElement("div");
charParamContent.style.display = "flex";
charParamContent.style.flexDirection = "column";
charParamContent.style.overflowY = "auto";
charParamContent.style.overflowX = "hidden";
charParamContent.style.flex = "1";
charParamContent.dataset.content = "char-param";
const inlineEditContent = document.createElement("div");
inlineEditContent.style.display = "none";
inlineEditContent.style.flexDirection = "column";
inlineEditContent.style.overflowY = "auto";
inlineEditContent.style.overflowX = "hidden";
inlineEditContent.style.flex = "1";
inlineEditContent.dataset.content = "inline-edit";
// Tab switching logic
const switchTab = (tabName) => {
// Update tab headers
if (tabName === "char-param") {
// Active tab
charParamTab.style.background = "linear-gradient(to bottom, #4a4a4a 0%, #3a3a3a 100%)";
charParamTab.style.borderTop = "2px solid #0af";
charParamTab.style.color = "#fff";
charParamTab.style.zIndex = "10";
// Inactive tab
inlineEditTab.style.background = "linear-gradient(to bottom, #2a2a2a 0%, #222 100%)";
inlineEditTab.style.borderTop = "2px solid #444";
inlineEditTab.style.color = "#999";
inlineEditTab.style.zIndex = "5";
// Content
charParamContent.style.display = "flex";
inlineEditContent.style.display = "none";
} else if (tabName === "inline-edit") {
// Inactive tab
charParamTab.style.background = "linear-gradient(to bottom, #2a2a2a 0%, #222 100%)";
charParamTab.style.borderTop = "2px solid #444";
charParamTab.style.color = "#999";
charParamTab.style.zIndex = "5";
// Active tab
inlineEditTab.style.background = "linear-gradient(to bottom, #4a4a4a 0%, #3a3a3a 100%)";
inlineEditTab.style.borderTop = "2px solid #0af";
inlineEditTab.style.color = "#fff";
inlineEditTab.style.zIndex = "10";
// Content
charParamContent.style.display = "none";
inlineEditContent.style.display = "flex";
}
// Save active tab to state
state.activeTab = tabName;
state.saveToLocalStorage(storageKey);
};
charParamTab.addEventListener("click", () => switchTab("char-param"));
inlineEditTab.addEventListener("click", () => switchTab("inline-edit"));
// Assemble tab system
tabContainer.appendChild(tabHeaders);
tabContainer.appendChild(charParamContent);
tabContainer.appendChild(inlineEditContent);
// Load saved tab state (default to char-param)
const activeTab = state.activeTab || "char-param";
switchTab(activeTab);
return {
tabContainer,
charParamContent,
inlineEditContent,
switchTab
};
}