Update index.html
Browse files- index.html +154 -107
index.html
CHANGED
|
@@ -38,6 +38,14 @@
|
|
| 38 |
from { opacity: 0; transform: translateY(20px); }
|
| 39 |
to { opacity: 1; transform: translateY(0); }
|
| 40 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
|
| 43 |
body {
|
|
@@ -55,7 +63,7 @@
|
|
| 55 |
display: flex;
|
| 56 |
justify-content: center;
|
| 57 |
align-items: flex-start;
|
| 58 |
-
overflow-x: hidden;
|
| 59 |
}
|
| 60 |
|
| 61 |
.container {
|
|
@@ -65,27 +73,27 @@
|
|
| 65 |
}
|
| 66 |
|
| 67 |
.app-header {
|
| 68 |
-
padding: 0.5rem 0 2.5rem 0;
|
| 69 |
text-align: center;
|
| 70 |
-
margin-bottom: 1.5rem;
|
| 71 |
animation: fadeInDown 0.8s 0.1s ease-out backwards;
|
| 72 |
}
|
| 73 |
.app-header h1 {
|
| 74 |
-
font-size: 2.1em;
|
| 75 |
font-weight: 900;
|
| 76 |
-
margin:0 0 0.6rem 0;
|
| 77 |
background: linear-gradient(45deg, var(--accent-primary), var(--accent-secondary));
|
| 78 |
-webkit-background-clip: text;
|
| 79 |
-webkit-text-fill-color: transparent;
|
| 80 |
-
letter-spacing: -0.5px;
|
| 81 |
}
|
| 82 |
.app-header p {
|
| 83 |
-
font-size: 1em;
|
| 84 |
color: var(--text-secondary);
|
| 85 |
margin-top:0;
|
| 86 |
-
opacity: 0.85;
|
| 87 |
font-weight: 400;
|
| 88 |
-
line-height: 1.6;
|
| 89 |
}
|
| 90 |
|
| 91 |
.main-content {
|
|
@@ -109,7 +117,7 @@
|
|
| 109 |
margin-bottom: 0;
|
| 110 |
}
|
| 111 |
|
| 112 |
-
.info-tooltip-icon
|
| 113 |
display: inline-flex;
|
| 114 |
align-items: center;
|
| 115 |
justify-content: center;
|
|
@@ -126,49 +134,14 @@
|
|
| 126 |
transition: var(--transition-smooth);
|
| 127 |
user-select: none;
|
| 128 |
}
|
| 129 |
-
.info-
|
| 130 |
background-color: var(--accent-primary);
|
| 131 |
color: white;
|
| 132 |
border-color: var(--accent-primary);
|
| 133 |
transform: scale(1.1);
|
| 134 |
outline: none;
|
| 135 |
}
|
| 136 |
-
.tooltip-text
|
| 137 |
-
visibility: hidden;
|
| 138 |
-
width: 280px;
|
| 139 |
-
background-color: var(--text-primary);
|
| 140 |
-
color: #fff;
|
| 141 |
-
text-align: right;
|
| 142 |
-
border-radius: var(--radius-input);
|
| 143 |
-
padding: 10px 15px;
|
| 144 |
-
position: absolute;
|
| 145 |
-
z-index: 10;
|
| 146 |
-
bottom: 140%;
|
| 147 |
-
left: 50%;
|
| 148 |
-
transform: translateX(-50%) translateY(10px);
|
| 149 |
-
opacity: 0;
|
| 150 |
-
transition: opacity 0.3s, visibility 0.3s, transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
| 151 |
-
font-size: 0.88em;
|
| 152 |
-
font-weight: 400;
|
| 153 |
-
line-height: 1.6;
|
| 154 |
-
box-shadow: var(--shadow-medium);
|
| 155 |
-
}
|
| 156 |
-
.tooltip-text::after {
|
| 157 |
-
content: "";
|
| 158 |
-
position: absolute;
|
| 159 |
-
top: 100%;
|
| 160 |
-
left: 50%;
|
| 161 |
-
margin-left: -5px;
|
| 162 |
-
border-width: 5px;
|
| 163 |
-
border-style: solid;
|
| 164 |
-
border-color: var(--text-primary) transparent transparent transparent;
|
| 165 |
-
}
|
| 166 |
-
.info-tooltip-icon.active .tooltip-text {
|
| 167 |
-
visibility: visible;
|
| 168 |
-
opacity: 1;
|
| 169 |
-
transform: translateX(-50%) translateY(0);
|
| 170 |
-
}
|
| 171 |
-
|
| 172 |
|
| 173 |
label {
|
| 174 |
display: block;
|
|
@@ -273,34 +246,48 @@
|
|
| 273 |
}
|
| 274 |
|
| 275 |
|
| 276 |
-
/* --- مودال
|
| 277 |
-
|
| 278 |
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
| 279 |
-
background-color: rgba(18, 24, 38, 0.
|
| 280 |
backdrop-filter: blur(8px) saturate(150%);
|
| 281 |
-
display: none;
|
|
|
|
| 282 |
z-index: 1000; opacity: 0;
|
| 283 |
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 284 |
}
|
| 285 |
-
|
| 286 |
-
|
|
|
|
| 287 |
background: var(--panel-bg);
|
| 288 |
padding: 2rem;
|
| 289 |
border-radius: var(--radius-card);
|
| 290 |
-
width: 90%;
|
| 291 |
-
max-height: 85vh; overflow-y: auto;
|
| 292 |
-
transform: scale(0.95) translateY(20px);
|
| 293 |
-
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.35s;
|
| 294 |
-
border: 1px solid var(--panel-border);
|
| 295 |
box-shadow: var(--shadow-strong);
|
| 296 |
-
|
|
|
|
|
|
|
|
|
|
| 297 |
}
|
| 298 |
-
|
| 299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
.modal-header h2 { margin: 0; font-size: 1.6em; font-weight: 800; color: var(--accent-primary);}
|
| 301 |
.close-modal-btn { background: none; border: none; font-size: 2.5rem; cursor: pointer; color: var(--text-secondary); transition: var(--transition-smooth); line-height: 1; }
|
| 302 |
.close-modal-btn:hover { color: var(--accent-primary); transform: rotate(90deg) scale(1.1); }
|
| 303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
#speaker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 1.2rem; }
|
| 305 |
@media (min-width: 640px) { #speaker-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); } }
|
| 306 |
.speaker-card { cursor: pointer; transition: var(--transition-smooth); text-align: center; position: relative;}
|
|
@@ -317,7 +304,7 @@
|
|
| 317 |
.speaker-card:hover .speaker-visual {
|
| 318 |
transform: translateY(-5px) scale(1.06);
|
| 319 |
box-shadow: var(--shadow-medium);
|
| 320 |
-
border-color: rgba(var(--accent-secondary-rgb), 0.3);
|
| 321 |
}
|
| 322 |
.speaker-card input[type="radio"] { display: none; }
|
| 323 |
.speaker-card img {
|
|
@@ -344,6 +331,30 @@
|
|
| 344 |
font-weight: 700;
|
| 345 |
}
|
| 346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
/* --- Slider & Button & Output --- */
|
| 348 |
.slider-container { display: flex; align-items: center; gap: 1.2rem; }
|
| 349 |
input[type="range"] {
|
|
@@ -582,8 +593,8 @@
|
|
| 582 |
<div class="form-group">
|
| 583 |
<div class="label-with-info">
|
| 584 |
<label for="temperature-slider">🌡️ میزان خلاقیت و نوآوری صدا</label>
|
| 585 |
-
<div class="info-
|
| 586 |
-
|
| 587 |
</div>
|
| 588 |
</div>
|
| 589 |
<div class="slider-container">
|
|
@@ -610,11 +621,12 @@
|
|
| 610 |
</main>
|
| 611 |
</div>
|
| 612 |
|
| 613 |
-
|
| 614 |
-
|
|
|
|
| 615 |
<div class="modal-header">
|
| 616 |
<h2>گالری گویندگان آلفا نوا</h2>
|
| 617 |
-
<button type="button" class="close-modal-btn" aria-label="بستن مودال">×</button>
|
| 618 |
</div>
|
| 619 |
<div id="speaker-grid">
|
| 620 |
<!-- Speaker cards will be generated here by JS -->
|
|
@@ -622,6 +634,23 @@
|
|
| 622 |
</div>
|
| 623 |
</div>
|
| 624 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 625 |
<input type="hidden" id="selected_speaker_id_storage" value="Charon">
|
| 626 |
|
| 627 |
<script>
|
|
@@ -678,27 +707,30 @@
|
|
| 678 |
const loadingAnimationWrapper = document.getElementById('loading-animation-wrapper');
|
| 679 |
|
| 680 |
const selectedSpeakerIdStorage = document.getElementById('selected_speaker_id_storage');
|
| 681 |
-
const speakerModal = document.getElementById('speaker-modal');
|
| 682 |
const changeSpeakerBtn = document.getElementById('change-speaker-btn');
|
| 683 |
const selectedSpeakerCard = document.getElementById('selected-speaker-card');
|
| 684 |
-
const closeModalBtn = document.querySelector('.close-modal-btn');
|
| 685 |
const speakerGridInModal = document.getElementById('speaker-grid');
|
| 686 |
const selectedSpeakerImgDisplay = document.getElementById('selected-speaker-img');
|
| 687 |
const selectedSpeakerNameDisplay = document.getElementById('selected-speaker-name');
|
| 688 |
const selectedSpeakerDescDisplay = document.getElementById('selected-speaker-desc');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 689 |
const tempInfoIcon = document.getElementById('temp-info-icon');
|
| 690 |
|
|
|
|
| 691 |
// Character Counter
|
| 692 |
const charCountSpan = document.getElementById('char-count');
|
| 693 |
const charMaxSpan = document.getElementById('char-max');
|
| 694 |
-
const MAX_CHARS = 50000;
|
| 695 |
-
charMaxSpan.textContent = MAX_CHARS.toLocaleString('fa-IR');
|
| 696 |
|
| 697 |
textInput.addEventListener('input', () => {
|
| 698 |
const currentLength = textInput.value.length;
|
| 699 |
charCountSpan.textContent = currentLength.toLocaleString('fa-IR');
|
| 700 |
if (currentLength > MAX_CHARS) {
|
| 701 |
-
charCountSpan.style.color = 'var(--accent-secondary-hover)';
|
| 702 |
} else {
|
| 703 |
charCountSpan.style.color = 'var(--accent-primary)';
|
| 704 |
}
|
|
@@ -714,7 +746,6 @@
|
|
| 714 |
const imageIndex = (index * 7 + speaker.id.length * 3 + 5) % 100;
|
| 715 |
let portraitSizePath = 'thumb/';
|
| 716 |
if (size === 'large') portraitSizePath = '';
|
| 717 |
-
|
| 718 |
return `https://randomuser.me/api/portraits/${portraitSizePath}${gender}/${imageIndex}.jpg`;
|
| 719 |
}
|
| 720 |
|
|
@@ -735,7 +766,6 @@
|
|
| 735 |
cardLabel.className = 'speaker-card';
|
| 736 |
cardLabel.setAttribute('for', `modal-speaker-${speaker.id}`);
|
| 737 |
const isChecked = speaker.id === selectedSpeakerIdStorage.value ? 'checked' : '';
|
| 738 |
-
|
| 739 |
cardLabel.innerHTML = `
|
| 740 |
<input type="radio" name="modal_speaker_selection" value="${speaker.id}" id="modal-speaker-${speaker.id}" ${isChecked}>
|
| 741 |
<div class="speaker-visual">
|
|
@@ -743,64 +773,81 @@
|
|
| 743 |
<div class="speaker-name">${speaker.name}</div>
|
| 744 |
</div>
|
| 745 |
`;
|
| 746 |
-
|
| 747 |
cardLabel.addEventListener('click', (e) => {
|
| 748 |
if (e.target.name !== "modal_speaker_selection") {
|
| 749 |
const radio = cardLabel.querySelector('input[type="radio"]');
|
| 750 |
if(radio) radio.checked = true;
|
| 751 |
}
|
| 752 |
updateSelectedSpeakerDisplay(speaker.id);
|
| 753 |
-
|
| 754 |
});
|
| 755 |
-
|
| 756 |
speakerGridInModal.appendChild(cardLabel);
|
| 757 |
});
|
| 758 |
}
|
| 759 |
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
|
|
|
| 763 |
setTimeout(() => {
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
}, 50);
|
| 768 |
}
|
| 769 |
|
| 770 |
-
|
| 771 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 772 |
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
}
|
| 778 |
});
|
| 779 |
-
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
}
|
| 783 |
});
|
| 784 |
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
tempInfoIcon.addEventListener('
|
| 788 |
-
e.stopPropagation();
|
| 789 |
-
tempInfoIcon.classList.toggle('active');
|
| 790 |
-
});
|
| 791 |
-
tempInfoIcon.addEventListener('keydown', (e) => {
|
| 792 |
if (e.key === 'Enter' || e.key === ' ') {
|
| 793 |
e.preventDefault();
|
| 794 |
-
|
| 795 |
}
|
| 796 |
});
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 800 |
}
|
| 801 |
});
|
| 802 |
|
| 803 |
|
|
|
|
|
|
|
|
|
|
| 804 |
function showLoadingState() {
|
| 805 |
outputSection.classList.remove('has-content');
|
| 806 |
statusMessage.style.display = 'none';
|
|
@@ -874,7 +921,7 @@
|
|
| 874 |
|
| 875 |
let finalFilePath = null;
|
| 876 |
const startTime = Date.now();
|
| 877 |
-
const timeoutDuration = 90000;
|
| 878 |
|
| 879 |
while (Date.now() - startTime < timeoutDuration) {
|
| 880 |
const dataResponse = await fetch(`${GET_DATA_URL_BASE}?session_hash=${sessionHash}`);
|
|
|
|
| 38 |
from { opacity: 0; transform: translateY(20px); }
|
| 39 |
to { opacity: 1; transform: translateY(0); }
|
| 40 |
}
|
| 41 |
+
@keyframes modalZoomIn {
|
| 42 |
+
from { opacity: 0; transform: scale(0.8) translateY(20px); }
|
| 43 |
+
to { opacity: 1; transform: scale(1) translateY(0); }
|
| 44 |
+
}
|
| 45 |
+
@keyframes modalZoomOut {
|
| 46 |
+
from { opacity: 1; transform: scale(1) translateY(0); }
|
| 47 |
+
to { opacity: 0; transform: scale(0.8) translateY(20px); }
|
| 48 |
+
}
|
| 49 |
|
| 50 |
|
| 51 |
body {
|
|
|
|
| 63 |
display: flex;
|
| 64 |
justify-content: center;
|
| 65 |
align-items: flex-start;
|
| 66 |
+
overflow-x: hidden;
|
| 67 |
}
|
| 68 |
|
| 69 |
.container {
|
|
|
|
| 73 |
}
|
| 74 |
|
| 75 |
.app-header {
|
| 76 |
+
padding: 0.5rem 0 2.5rem 0;
|
| 77 |
text-align: center;
|
| 78 |
+
margin-bottom: 1.5rem;
|
| 79 |
animation: fadeInDown 0.8s 0.1s ease-out backwards;
|
| 80 |
}
|
| 81 |
.app-header h1 {
|
| 82 |
+
font-size: 2.1em;
|
| 83 |
font-weight: 900;
|
| 84 |
+
margin:0 0 0.6rem 0;
|
| 85 |
background: linear-gradient(45deg, var(--accent-primary), var(--accent-secondary));
|
| 86 |
-webkit-background-clip: text;
|
| 87 |
-webkit-text-fill-color: transparent;
|
| 88 |
+
letter-spacing: -0.5px;
|
| 89 |
}
|
| 90 |
.app-header p {
|
| 91 |
+
font-size: 1em;
|
| 92 |
color: var(--text-secondary);
|
| 93 |
margin-top:0;
|
| 94 |
+
opacity: 0.85;
|
| 95 |
font-weight: 400;
|
| 96 |
+
line-height: 1.6;
|
| 97 |
}
|
| 98 |
|
| 99 |
.main-content {
|
|
|
|
| 117 |
margin-bottom: 0;
|
| 118 |
}
|
| 119 |
|
| 120 |
+
.info-icon { /* Renamed from info-tooltip-icon for clarity */
|
| 121 |
display: inline-flex;
|
| 122 |
align-items: center;
|
| 123 |
justify-content: center;
|
|
|
|
| 134 |
transition: var(--transition-smooth);
|
| 135 |
user-select: none;
|
| 136 |
}
|
| 137 |
+
.info-icon:hover, .info-icon:focus {
|
| 138 |
background-color: var(--accent-primary);
|
| 139 |
color: white;
|
| 140 |
border-color: var(--accent-primary);
|
| 141 |
transform: scale(1.1);
|
| 142 |
outline: none;
|
| 143 |
}
|
| 144 |
+
/* Removed .tooltip-text and .info-tooltip-icon.active as it's now a modal */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
label {
|
| 147 |
display: block;
|
|
|
|
| 246 |
}
|
| 247 |
|
| 248 |
|
| 249 |
+
/* --- مودال عمومی --- */
|
| 250 |
+
.modal-overlay {
|
| 251 |
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
| 252 |
+
background-color: rgba(18, 24, 38, 0.6);
|
| 253 |
backdrop-filter: blur(8px) saturate(150%);
|
| 254 |
+
display: none; /* Hidden by default */
|
| 255 |
+
align-items: center; justify-content: center;
|
| 256 |
z-index: 1000; opacity: 0;
|
| 257 |
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 258 |
}
|
| 259 |
+
.modal-overlay.visible { display: flex; opacity: 1; }
|
| 260 |
+
|
| 261 |
+
.modal-dialog {
|
| 262 |
background: var(--panel-bg);
|
| 263 |
padding: 2rem;
|
| 264 |
border-radius: var(--radius-card);
|
| 265 |
+
width: 90%;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
box-shadow: var(--shadow-strong);
|
| 267 |
+
border: 1px solid var(--panel-border);
|
| 268 |
+
opacity: 0; /* For animation */
|
| 269 |
+
animation-duration: 0.35s;
|
| 270 |
+
animation-fill-mode: forwards;
|
| 271 |
}
|
| 272 |
+
.modal-overlay.visible .modal-dialog {
|
| 273 |
+
animation-name: modalZoomIn;
|
| 274 |
+
}
|
| 275 |
+
.modal-overlay.hiding .modal-dialog {
|
| 276 |
+
animation-name: modalZoomOut;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid var(--panel-border); }
|
| 281 |
.modal-header h2 { margin: 0; font-size: 1.6em; font-weight: 800; color: var(--accent-primary);}
|
| 282 |
.close-modal-btn { background: none; border: none; font-size: 2.5rem; cursor: pointer; color: var(--text-secondary); transition: var(--transition-smooth); line-height: 1; }
|
| 283 |
.close-modal-btn:hover { color: var(--accent-primary); transform: rotate(90deg) scale(1.1); }
|
| 284 |
|
| 285 |
+
|
| 286 |
+
/* --- مودال گالری گویندگان (اختصاصی) --- */
|
| 287 |
+
#speaker-modal .modal-dialog { /* Target specific modal dialog */
|
| 288 |
+
max-width: 700px;
|
| 289 |
+
max-height: 85vh; overflow-y: auto;
|
| 290 |
+
}
|
| 291 |
#speaker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 1.2rem; }
|
| 292 |
@media (min-width: 640px) { #speaker-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); } }
|
| 293 |
.speaker-card { cursor: pointer; transition: var(--transition-smooth); text-align: center; position: relative;}
|
|
|
|
| 304 |
.speaker-card:hover .speaker-visual {
|
| 305 |
transform: translateY(-5px) scale(1.06);
|
| 306 |
box-shadow: var(--shadow-medium);
|
| 307 |
+
/* border-color: rgba(var(--accent-secondary-rgb), 0.3); */ /* Requires CSS var for RGB components */
|
| 308 |
}
|
| 309 |
.speaker-card input[type="radio"] { display: none; }
|
| 310 |
.speaker-card img {
|
|
|
|
| 331 |
font-weight: 700;
|
| 332 |
}
|
| 333 |
|
| 334 |
+
/* --- مودال اطلاعات (اختصاصی) --- */
|
| 335 |
+
#info-modal .modal-dialog {
|
| 336 |
+
max-width: 480px; /* Smaller width for info */
|
| 337 |
+
}
|
| 338 |
+
#info-modal-content p {
|
| 339 |
+
font-size: 1em;
|
| 340 |
+
line-height: 1.7;
|
| 341 |
+
color: var(--text-secondary);
|
| 342 |
+
margin-bottom: 0.5rem;
|
| 343 |
+
}
|
| 344 |
+
#info-modal-content p strong {
|
| 345 |
+
color: var(--text-primary);
|
| 346 |
+
font-weight: 600;
|
| 347 |
+
}
|
| 348 |
+
#info-modal-content .range-info {
|
| 349 |
+
font-size: 0.9em;
|
| 350 |
+
color: var(--accent-primary);
|
| 351 |
+
font-weight: 500;
|
| 352 |
+
margin-top: 1rem;
|
| 353 |
+
display: block;
|
| 354 |
+
text-align: center;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
|
| 358 |
/* --- Slider & Button & Output --- */
|
| 359 |
.slider-container { display: flex; align-items: center; gap: 1.2rem; }
|
| 360 |
input[type="range"] {
|
|
|
|
| 593 |
<div class="form-group">
|
| 594 |
<div class="label-with-info">
|
| 595 |
<label for="temperature-slider">🌡️ میزان خلاقیت و نوآوری صدا</label>
|
| 596 |
+
<div class="info-icon" id="temp-info-icon" role="button" tabindex="0" aria-label="اطلاعات بیشتر">!
|
| 597 |
+
<!-- Tooltip text removed, will be shown in modal -->
|
| 598 |
</div>
|
| 599 |
</div>
|
| 600 |
<div class="slider-container">
|
|
|
|
| 621 |
</main>
|
| 622 |
</div>
|
| 623 |
|
| 624 |
+
<!-- مودال گالری گویندگان -->
|
| 625 |
+
<div id="speaker-modal" class="modal-overlay">
|
| 626 |
+
<div class="modal-dialog">
|
| 627 |
<div class="modal-header">
|
| 628 |
<h2>گالری گویندگان آلفا نوا</h2>
|
| 629 |
+
<button type="button" class="close-modal-btn" data-modal-id="speaker-modal" aria-label="بستن مودال">×</button>
|
| 630 |
</div>
|
| 631 |
<div id="speaker-grid">
|
| 632 |
<!-- Speaker cards will be generated here by JS -->
|
|
|
|
| 634 |
</div>
|
| 635 |
</div>
|
| 636 |
|
| 637 |
+
<!-- مودال اطلاعات خلاقیت صدا -->
|
| 638 |
+
<div id="info-modal" class="modal-overlay">
|
| 639 |
+
<div class="modal-dialog">
|
| 640 |
+
<div class="modal-header">
|
| 641 |
+
<h2>🌡️ خلاقیت و نوآوری صدا</h2>
|
| 642 |
+
<button type="button" class="close-modal-btn" data-modal-id="info-modal" aria-label="بستن توضیحات">×</button>
|
| 643 |
+
</div>
|
| 644 |
+
<div id="info-modal-content">
|
| 645 |
+
<p>این تنظیم مشخص میکند که هوش مصنوعی تا چه حد در تولید صدا <strong>خلاقیت</strong> به خرج دهد.</p>
|
| 646 |
+
<p><strong>مقادیر بالاتر:</strong> منجر به صدایی متنوعتر، پویاتر و گاهی اوقات غیرمنتظرهتر میشود. مناسب برای زمانی که به دنبال لحنی خاص و منحصربهفرد هستید.</p>
|
| 647 |
+
<p><strong>مقادیر پایینتر:</strong> صدایی پایدارتر، قابل پیشبینیتر و نزدیکتر به صدای استاندارد گوینده تولید میکند. مناسب برای خوانش متون رسمی یا زمانی که ثبات لحن اهمیت دارد.</p>
|
| 648 |
+
<span class="range-info">محدوده پیشنهادی: ۰.۱ (پایدار) تا ۱.۵ (بسیار خلاق)</span>
|
| 649 |
+
</div>
|
| 650 |
+
</div>
|
| 651 |
+
</div>
|
| 652 |
+
|
| 653 |
+
|
| 654 |
<input type="hidden" id="selected_speaker_id_storage" value="Charon">
|
| 655 |
|
| 656 |
<script>
|
|
|
|
| 707 |
const loadingAnimationWrapper = document.getElementById('loading-animation-wrapper');
|
| 708 |
|
| 709 |
const selectedSpeakerIdStorage = document.getElementById('selected_speaker_id_storage');
|
|
|
|
| 710 |
const changeSpeakerBtn = document.getElementById('change-speaker-btn');
|
| 711 |
const selectedSpeakerCard = document.getElementById('selected-speaker-card');
|
|
|
|
| 712 |
const speakerGridInModal = document.getElementById('speaker-grid');
|
| 713 |
const selectedSpeakerImgDisplay = document.getElementById('selected-speaker-img');
|
| 714 |
const selectedSpeakerNameDisplay = document.getElementById('selected-speaker-name');
|
| 715 |
const selectedSpeakerDescDisplay = document.getElementById('selected-speaker-desc');
|
| 716 |
+
|
| 717 |
+
// Modal Elements
|
| 718 |
+
const speakerModal = document.getElementById('speaker-modal');
|
| 719 |
+
const infoModal = document.getElementById('info-modal');
|
| 720 |
const tempInfoIcon = document.getElementById('temp-info-icon');
|
| 721 |
|
| 722 |
+
|
| 723 |
// Character Counter
|
| 724 |
const charCountSpan = document.getElementById('char-count');
|
| 725 |
const charMaxSpan = document.getElementById('char-max');
|
| 726 |
+
const MAX_CHARS = 50000;
|
| 727 |
+
charMaxSpan.textContent = MAX_CHARS.toLocaleString('fa-IR');
|
| 728 |
|
| 729 |
textInput.addEventListener('input', () => {
|
| 730 |
const currentLength = textInput.value.length;
|
| 731 |
charCountSpan.textContent = currentLength.toLocaleString('fa-IR');
|
| 732 |
if (currentLength > MAX_CHARS) {
|
| 733 |
+
charCountSpan.style.color = 'var(--accent-secondary-hover)';
|
| 734 |
} else {
|
| 735 |
charCountSpan.style.color = 'var(--accent-primary)';
|
| 736 |
}
|
|
|
|
| 746 |
const imageIndex = (index * 7 + speaker.id.length * 3 + 5) % 100;
|
| 747 |
let portraitSizePath = 'thumb/';
|
| 748 |
if (size === 'large') portraitSizePath = '';
|
|
|
|
| 749 |
return `https://randomuser.me/api/portraits/${portraitSizePath}${gender}/${imageIndex}.jpg`;
|
| 750 |
}
|
| 751 |
|
|
|
|
| 766 |
cardLabel.className = 'speaker-card';
|
| 767 |
cardLabel.setAttribute('for', `modal-speaker-${speaker.id}`);
|
| 768 |
const isChecked = speaker.id === selectedSpeakerIdStorage.value ? 'checked' : '';
|
|
|
|
| 769 |
cardLabel.innerHTML = `
|
| 770 |
<input type="radio" name="modal_speaker_selection" value="${speaker.id}" id="modal-speaker-${speaker.id}" ${isChecked}>
|
| 771 |
<div class="speaker-visual">
|
|
|
|
| 773 |
<div class="speaker-name">${speaker.name}</div>
|
| 774 |
</div>
|
| 775 |
`;
|
|
|
|
| 776 |
cardLabel.addEventListener('click', (e) => {
|
| 777 |
if (e.target.name !== "modal_speaker_selection") {
|
| 778 |
const radio = cardLabel.querySelector('input[type="radio"]');
|
| 779 |
if(radio) radio.checked = true;
|
| 780 |
}
|
| 781 |
updateSelectedSpeakerDisplay(speaker.id);
|
| 782 |
+
hideModal(speakerModal);
|
| 783 |
});
|
|
|
|
| 784 |
speakerGridInModal.appendChild(cardLabel);
|
| 785 |
});
|
| 786 |
}
|
| 787 |
|
| 788 |
+
// --- Modal Management ---
|
| 789 |
+
function showModal(modalElement) {
|
| 790 |
+
modalElement.classList.add('visible');
|
| 791 |
+
// Focus first focusable element in modal
|
| 792 |
setTimeout(() => {
|
| 793 |
+
const firstFocusable = modalElement.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
| 794 |
+
if (firstFocusable) firstFocusable.focus();
|
| 795 |
+
}, 50); // Allow transition to start
|
|
|
|
| 796 |
}
|
| 797 |
|
| 798 |
+
function hideModal(modalElement) {
|
| 799 |
+
modalElement.classList.add('hiding'); // Add class for exit animation
|
| 800 |
+
modalElement.addEventListener('animationend', () => {
|
| 801 |
+
modalElement.classList.remove('visible', 'hiding');
|
| 802 |
+
}, { once: true });
|
| 803 |
+
}
|
| 804 |
|
| 805 |
+
// Speaker Modal Listeners
|
| 806 |
+
changeSpeakerBtn.addEventListener('click', () => {
|
| 807 |
+
createSpeakerCardsInModal();
|
| 808 |
+
showModal(speakerModal);
|
|
|
|
| 809 |
});
|
| 810 |
+
selectedSpeakerCard.addEventListener('click', () => {
|
| 811 |
+
createSpeakerCardsInModal();
|
| 812 |
+
showModal(speakerModal);
|
|
|
|
| 813 |
});
|
| 814 |
|
| 815 |
+
// Info Modal Listener
|
| 816 |
+
tempInfoIcon.addEventListener('click', () => showModal(infoModal));
|
| 817 |
+
tempInfoIcon.addEventListener('keydown', (e) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 818 |
if (e.key === 'Enter' || e.key === ' ') {
|
| 819 |
e.preventDefault();
|
| 820 |
+
showModal(infoModal);
|
| 821 |
}
|
| 822 |
});
|
| 823 |
+
|
| 824 |
+
|
| 825 |
+
// General Modal Close Listeners (for all modals)
|
| 826 |
+
document.querySelectorAll('.modal-overlay').forEach(overlay => {
|
| 827 |
+
overlay.addEventListener('click', (e) => {
|
| 828 |
+
if (e.target === overlay) { // Click on backdrop
|
| 829 |
+
hideModal(overlay);
|
| 830 |
+
}
|
| 831 |
+
});
|
| 832 |
+
});
|
| 833 |
+
document.querySelectorAll('.close-modal-btn').forEach(button => {
|
| 834 |
+
button.addEventListener('click', () => {
|
| 835 |
+
const modalId = button.dataset.modalId;
|
| 836 |
+
if (modalId) {
|
| 837 |
+
hideModal(document.getElementById(modalId));
|
| 838 |
+
}
|
| 839 |
+
});
|
| 840 |
+
});
|
| 841 |
+
document.addEventListener('keydown', (e) => {
|
| 842 |
+
if (e.key === 'Escape') {
|
| 843 |
+
document.querySelectorAll('.modal-overlay.visible').forEach(hideModal);
|
| 844 |
}
|
| 845 |
});
|
| 846 |
|
| 847 |
|
| 848 |
+
tempSlider.addEventListener('input', () => { tempValueSpan.textContent = tempSlider.value; });
|
| 849 |
+
|
| 850 |
+
|
| 851 |
function showLoadingState() {
|
| 852 |
outputSection.classList.remove('has-content');
|
| 853 |
statusMessage.style.display = 'none';
|
|
|
|
| 921 |
|
| 922 |
let finalFilePath = null;
|
| 923 |
const startTime = Date.now();
|
| 924 |
+
const timeoutDuration = 90000;
|
| 925 |
|
| 926 |
while (Date.now() - startTime < timeoutDuration) {
|
| 927 |
const dataResponse = await fetch(`${GET_DATA_URL_BASE}?session_hash=${sessionHash}`);
|