mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Enhance dashboard and prepare wizard functionality with speaker step handling and UI updates
This commit is contained in:
@@ -205,14 +205,19 @@ const initDashboard = () => {
|
||||
});
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
const readerClose = event.target.closest('[data-role="reader-modal-close"]');
|
||||
const target = event.target;
|
||||
if (!(target instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readerClose = target.closest('[data-role="reader-modal-close"]');
|
||||
if (readerClose) {
|
||||
event.preventDefault();
|
||||
closeReaderModal();
|
||||
return;
|
||||
}
|
||||
|
||||
const readerTriggerBtn = event.target.closest('[data-role="open-reader"]');
|
||||
const readerTriggerBtn = target.closest('[data-role="open-reader"]');
|
||||
if (readerTriggerBtn) {
|
||||
event.preventDefault();
|
||||
openReaderModal(readerTriggerBtn);
|
||||
|
||||
@@ -244,6 +244,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const panels = new Map();
|
||||
const initialStep = wizard.dataset.initialStep || "chapters";
|
||||
const speakerModeSelect = form.querySelector("#speaker_mode");
|
||||
const speakerIndicator = indicator ? indicator.querySelector('[data-step-key="speakers"]') : null;
|
||||
const chapterActions = wizard.querySelector('[data-role="chapter-actions"]');
|
||||
const continueButton = chapterActions ? chapterActions.querySelector('[data-chapter-action="continue"]') : null;
|
||||
const finalizeButton = chapterActions ? chapterActions.querySelector('[data-chapter-action="finalize"]') : null;
|
||||
stepOrder.forEach((step) => {
|
||||
const panel = wizard.querySelector(`[data-step-panel="${step}"]`);
|
||||
if (panel) {
|
||||
@@ -311,23 +315,27 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
};
|
||||
|
||||
const setStep = (step) => {
|
||||
if (!panels.has(step)) {
|
||||
let targetStep = step;
|
||||
if (targetStep === "speakers" && shouldSkipSpeakersStep()) {
|
||||
targetStep = "chapters";
|
||||
}
|
||||
if (!panels.has(targetStep)) {
|
||||
return;
|
||||
}
|
||||
currentStep = step;
|
||||
wizard.dataset.activeStep = step;
|
||||
currentStep = targetStep;
|
||||
wizard.dataset.activeStep = targetStep;
|
||||
if (activeStepInput) {
|
||||
activeStepInput.value = step;
|
||||
activeStepInput.value = targetStep;
|
||||
}
|
||||
panels.forEach((panel, key) => {
|
||||
const isActive = key === step;
|
||||
const isActive = key === targetStep;
|
||||
panel.hidden = !isActive;
|
||||
panel.setAttribute("aria-hidden", isActive ? "false" : "true");
|
||||
});
|
||||
navButtons.forEach((button) => {
|
||||
const target = button.dataset.stepTarget;
|
||||
if (!target) return;
|
||||
const isActive = target === step;
|
||||
const isActive = target === targetStep;
|
||||
button.classList.toggle("is-active", isActive);
|
||||
if (button.dataset.state === "locked" && !unlockedSteps.has(target)) {
|
||||
button.disabled = true;
|
||||
@@ -337,7 +345,46 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
button.removeAttribute("aria-disabled");
|
||||
}
|
||||
});
|
||||
updateIndicator(step);
|
||||
updateIndicator(targetStep);
|
||||
};
|
||||
|
||||
const updateSpeakerControls = () => {
|
||||
const skipSpeakers = shouldSkipSpeakersStep();
|
||||
if (wizard) {
|
||||
wizard.dataset.speakerStep = skipSpeakers ? "disabled" : "enabled";
|
||||
}
|
||||
if (speakerIndicator) {
|
||||
if (skipSpeakers) {
|
||||
speakerIndicator.hidden = true;
|
||||
speakerIndicator.setAttribute("aria-hidden", "true");
|
||||
} else {
|
||||
speakerIndicator.hidden = false;
|
||||
speakerIndicator.removeAttribute("aria-hidden");
|
||||
}
|
||||
}
|
||||
if (continueButton) {
|
||||
if (skipSpeakers) {
|
||||
continueButton.hidden = true;
|
||||
continueButton.setAttribute("aria-hidden", "true");
|
||||
continueButton.setAttribute("tabindex", "-1");
|
||||
} else {
|
||||
continueButton.hidden = false;
|
||||
continueButton.removeAttribute("aria-hidden");
|
||||
continueButton.removeAttribute("tabindex");
|
||||
}
|
||||
}
|
||||
if (finalizeButton) {
|
||||
if (skipSpeakers) {
|
||||
finalizeButton.hidden = false;
|
||||
finalizeButton.removeAttribute("aria-hidden");
|
||||
} else {
|
||||
finalizeButton.hidden = true;
|
||||
finalizeButton.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
}
|
||||
if (skipSpeakers && currentStep === "speakers") {
|
||||
setStep("chapters");
|
||||
}
|
||||
};
|
||||
|
||||
const submitForAnalysis = () => {
|
||||
@@ -399,7 +446,23 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
});
|
||||
|
||||
if (speakerModeSelect) {
|
||||
speakerModeSelect.addEventListener("change", () => {
|
||||
updateSpeakerControls();
|
||||
});
|
||||
}
|
||||
|
||||
if (finalizeButton) {
|
||||
finalizeButton.addEventListener("click", (event) => {
|
||||
if (shouldSkipSpeakersStep()) {
|
||||
event.preventDefault();
|
||||
submitFinalize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setStep(currentStep);
|
||||
updateSpeakerControls();
|
||||
}
|
||||
|
||||
const voiceModal = document.querySelector('[data-role="voice-modal"]');
|
||||
|
||||
@@ -298,7 +298,7 @@ body {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
padding: 0 2rem 2rem;
|
||||
padding: 1.25rem 2rem 2.75rem;
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.12);
|
||||
background: linear-gradient(180deg, transparent, rgba(15, 23, 42, 0.3));
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
</div>
|
||||
<footer class="modal__footer">
|
||||
<button type="button" class="button button--ghost" data-role="upload-modal-close">Cancel</button>
|
||||
<button type="submit" class="button">Queue Conversion</button>
|
||||
<button type="submit" class="button">Chapter Selection</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
|
||||
{% block content %}
|
||||
{% set wizard_step = (active_step or 'chapters') %}
|
||||
{% set is_multi_speaker = pending.speaker_mode == 'multi' %}
|
||||
{% if wizard_step == 'speakers' and not is_multi_speaker %}
|
||||
{% set wizard_step = 'chapters' %}
|
||||
{% endif %}
|
||||
{% set is_chapters = wizard_step == 'chapters' %}
|
||||
{% set is_speakers = wizard_step == 'speakers' %}
|
||||
<section class="card" data-role="prepare-wizard" data-initial-step="{{ wizard_step }}">
|
||||
<section class="card" data-role="prepare-wizard" data-initial-step="{{ wizard_step }}" data-speaker-step="{{ 'enabled' if is_multi_speaker else 'disabled' }}">
|
||||
<div class="step-indicator" aria-label="Audiobook workflow" data-role="wizard-indicator">
|
||||
<span class="step-indicator__item is-complete" data-role="wizard-step" data-step-key="setup">
|
||||
<span class="step-indicator__index">1</span>
|
||||
@@ -16,7 +20,7 @@
|
||||
<span class="step-indicator__index">2</span>
|
||||
<span class="step-indicator__label">Chapters</span>
|
||||
</span>
|
||||
<span class="step-indicator__item{% if is_speakers %} is-active{% endif %}" data-role="wizard-step" data-step-key="speakers">
|
||||
<span class="step-indicator__item{% if is_speakers %} is-active{% endif %}" data-role="wizard-step" data-step-key="speakers" {% if not is_multi_speaker %}hidden aria-hidden="true"{% endif %}>
|
||||
<span class="step-indicator__index">3</span>
|
||||
<span class="step-indicator__label">Speakers</span>
|
||||
</span>
|
||||
@@ -148,12 +152,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prepare-step__actions">
|
||||
<button type="button" class="button" data-role="step-next" data-step-target="speakers">Continue to speakers</button>
|
||||
<div class="prepare-step__actions" data-role="chapter-actions">
|
||||
<button type="button"
|
||||
class="button"
|
||||
data-role="step-next"
|
||||
data-step-target="speakers"
|
||||
data-chapter-action="continue"
|
||||
{% if not is_multi_speaker %}hidden aria-hidden="true"{% endif %}>
|
||||
Continue to speakers
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="button"
|
||||
data-chapter-action="finalize"
|
||||
{% if is_multi_speaker %}hidden aria-hidden="true"{% endif %}>
|
||||
Queue conversion
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="prepare-step" data-step-panel="speakers" hidden>
|
||||
<section class="prepare-step" data-step-panel="speakers" data-speaker-panel="true" hidden>
|
||||
<header class="prepare-step__header">
|
||||
<h2>Step 3 · Select speakers</h2>
|
||||
<p class="hint">Assign voices, audition samples, and finalize your roster.</p>
|
||||
@@ -408,9 +425,8 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="prepare-actions">
|
||||
<button type="button" class="button button--ghost" data-role="step-prev" data-step-target="chapters">Back to chapters</button>
|
||||
<button type="button" class="button button--ghost" data-role="step-prev" data-step-target="chapters">Back to upload & settings</button>
|
||||
<button type="submit" class="button">Queue conversion</button>
|
||||
<button type="submit" class="button button--ghost" form="cancel-form">Cancel</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user