Spaces:
Running
Running
Commit ·
3a2a2e5
1
Parent(s): d2356ec
Citrus theme, 3D buttons, voice picker dropdown, settings accordion
Browse files- index.html +135 -50
index.html
CHANGED
|
@@ -8,22 +8,22 @@
|
|
| 8 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 9 |
<style>
|
| 10 |
:root {
|
| 11 |
-
--bg: #
|
| 12 |
-
--surface: #
|
| 13 |
-
--surface2: #
|
| 14 |
-
--surface3: #
|
| 15 |
-
--border: #
|
| 16 |
-
--border-hover: #
|
| 17 |
-
--text: #
|
| 18 |
-
--text-secondary: #
|
| 19 |
-
--text-muted: #
|
| 20 |
-
--accent: #
|
| 21 |
-
--accent-hover: #
|
| 22 |
-
--accent-subtle: rgba(
|
| 23 |
-
--accent-glow: rgba(
|
| 24 |
--danger: #ef4444;
|
| 25 |
--success: #22c55e;
|
| 26 |
-
--warning: #
|
| 27 |
}
|
| 28 |
|
| 29 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
@@ -66,7 +66,7 @@ body {
|
|
| 66 |
.logo-icon {
|
| 67 |
width: 28px;
|
| 68 |
height: 28px;
|
| 69 |
-
background: linear-gradient(135deg, var(--accent), #
|
| 70 |
border-radius: 7px;
|
| 71 |
display: flex;
|
| 72 |
align-items: center;
|
|
@@ -281,29 +281,65 @@ body {
|
|
| 281 |
}
|
| 282 |
.lang-select:focus { outline: none; border-color: var(--accent); }
|
| 283 |
|
| 284 |
-
/* Settings */
|
| 285 |
-
.settings-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
.setting-group { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; }
|
| 287 |
.setting-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 8px; }
|
| 288 |
.setting-value { display: flex; align-items: center; gap: 10px; }
|
| 289 |
.setting-value input[type="range"] { flex: 1; accent-color: var(--accent); height: 4px; }
|
| 290 |
.setting-num { font-size: 13px; color: var(--text-secondary); min-width: 30px; text-align: right; font-variant-numeric: tabular-nums; }
|
| 291 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
/* Generate */
|
| 293 |
.generate-bar { display: flex; gap: 12px; align-items: center; }
|
| 294 |
|
| 295 |
.btn-generate {
|
| 296 |
flex: 1; padding: 14px 24px;
|
| 297 |
-
background: linear-gradient(135deg, var(--accent)
|
| 298 |
-
color:
|
| 299 |
font-size: 14px; font-weight: 600; font-family: 'Inter', sans-serif;
|
| 300 |
-
cursor: pointer; transition: all 0.
|
| 301 |
display: flex; align-items: center; justify-content: center; gap: 8px;
|
|
|
|
|
|
|
| 302 |
}
|
| 303 |
-
.btn-generate:hover { filter: brightness(1.
|
| 304 |
-
.btn-generate:active { transform: translateY(0); }
|
| 305 |
-
.btn-generate:disabled { opacity: 0.4; cursor: not-allowed; transform: none; filter: none; }
|
| 306 |
-
.btn-generate .spinner { width: 16px; height: 16px; border: 2px solid rgba(
|
| 307 |
.btn-generate.loading .spinner { display: block; }
|
| 308 |
.btn-generate.loading .btn-text { display: none; }
|
| 309 |
@keyframes spin { to { transform: rotate(360deg); } }
|
|
@@ -314,7 +350,7 @@ body {
|
|
| 314 |
font-size: 13px; display: none; gap: 8px; flex-direction: column;
|
| 315 |
}
|
| 316 |
.status-bar.visible { display: flex; }
|
| 317 |
-
.status-bar.info { background: rgba(
|
| 318 |
.status-bar.success { background: rgba(34,197,94,0.08); color: var(--success); border: 1px solid rgba(34,197,94,0.15); }
|
| 319 |
.status-bar.error { background: rgba(239,68,68,0.08); color: var(--danger); border: 1px solid rgba(239,68,68,0.15); }
|
| 320 |
|
|
@@ -328,12 +364,12 @@ body {
|
|
| 328 |
}
|
| 329 |
.status-cta.upgrade { background: #ff9d00; color: #000; }
|
| 330 |
.status-cta.upgrade:hover { background: #ffb340; }
|
| 331 |
-
.status-cta.credits { background: var(--accent); color:
|
| 332 |
.status-cta.credits:hover { background: var(--accent-hover); }
|
| 333 |
|
| 334 |
.progress-track { width: 100%; height: 3px; background: var(--surface3); border-radius: 2px; margin-top: 6px; overflow: hidden; display: none; }
|
| 335 |
.progress-track.visible { display: block; }
|
| 336 |
-
.progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent), #
|
| 337 |
|
| 338 |
/* Player */
|
| 339 |
.player-card { margin-top: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 16px 20px; display: none; }
|
|
@@ -342,7 +378,7 @@ body {
|
|
| 342 |
|
| 343 |
.play-btn {
|
| 344 |
width: 40px; height: 40px; border-radius: 50%; background: var(--accent);
|
| 345 |
-
border: none; color:
|
| 346 |
display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.15s;
|
| 347 |
}
|
| 348 |
.play-btn:hover { background: var(--accent-hover); transform: scale(1.05); }
|
|
@@ -396,7 +432,7 @@ body {
|
|
| 396 |
font-family: 'Inter', sans-serif; cursor: pointer; border: none; transition: all 0.1s;
|
| 397 |
}
|
| 398 |
|
| 399 |
-
.voice-tile-btn.use { background: var(--accent); color:
|
| 400 |
.voice-tile-btn.use:hover { background: var(--accent-hover); }
|
| 401 |
.voice-tile-btn.del { background: transparent; color: var(--text-muted); border: 1px solid var(--border); }
|
| 402 |
.voice-tile-btn.del:hover { color: var(--danger); border-color: var(--danger); }
|
|
@@ -477,7 +513,7 @@ pre {
|
|
| 477 |
}
|
| 478 |
.cm { color: var(--text-muted); }
|
| 479 |
.s { color: #86efac; }
|
| 480 |
-
.k { color: #
|
| 481 |
.f { color: #93c5fd; }
|
| 482 |
|
| 483 |
/* ── Modal ── */
|
|
@@ -517,7 +553,7 @@ pre {
|
|
| 517 |
.btn-modal { padding: 9px 20px; border-radius: 8px; font-size: 13px; font-weight: 500; font-family: 'Inter', sans-serif; cursor: pointer; transition: all 0.1s; border: none; }
|
| 518 |
.btn-cancel { background: var(--surface2); color: var(--text-secondary); border: 1px solid var(--border); }
|
| 519 |
.btn-cancel:hover { background: var(--surface3); color: var(--text); }
|
| 520 |
-
.btn-save { background: var(--accent); color:
|
| 521 |
.btn-save:hover { background: var(--accent-hover); }
|
| 522 |
.btn-save:disabled { opacity: 0.4; cursor: not-allowed; }
|
| 523 |
|
|
@@ -537,9 +573,11 @@ pre {
|
|
| 537 |
.btn-hf {
|
| 538 |
padding: 13px 32px; background: #ff9d00; color: #000; border: none; border-radius: 10px;
|
| 539 |
font-size: 15px; font-weight: 600; font-family: 'Inter', sans-serif; cursor: pointer;
|
| 540 |
-
display: inline-flex; align-items: center; gap: 8px; transition: all 0.
|
|
|
|
| 541 |
}
|
| 542 |
-
.btn-hf:hover { background: #ffb340; transform: translateY(-
|
|
|
|
| 543 |
.landing-note { font-size: 12px; color: var(--text-muted); }
|
| 544 |
|
| 545 |
::-webkit-scrollbar { width: 6px; }
|
|
@@ -627,13 +665,16 @@ pre {
|
|
| 627 |
<div class="page-desc">Select a voice and type your text to generate speech.</div>
|
| 628 |
</div>
|
| 629 |
|
| 630 |
-
<div class="voice-selector" id="voice-selector" onclick="
|
| 631 |
<div class="voice-avatar" id="sel-voice-avatar" style="background:var(--surface3)">🎤</div>
|
| 632 |
<div class="voice-selector-info">
|
| 633 |
<div class="voice-selector-name" id="sel-voice-name">No voice selected</div>
|
| 634 |
-
<div class="voice-selector-hint" id="sel-voice-hint">Click to add a voice</div>
|
|
|
|
|
|
|
|
|
|
| 635 |
</div>
|
| 636 |
-
<div class="voice-
|
| 637 |
</div>
|
| 638 |
|
| 639 |
<div class="editor">
|
|
@@ -660,19 +701,27 @@ pre {
|
|
| 660 |
</div>
|
| 661 |
</div>
|
| 662 |
|
| 663 |
-
<div class="settings-
|
| 664 |
-
<
|
| 665 |
-
<
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
<
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 676 |
</div>
|
| 677 |
</div>
|
| 678 |
</div>
|
|
@@ -974,10 +1023,46 @@ function updateVoiceSelector() {
|
|
| 974 |
avatar.textContent = "🎤";
|
| 975 |
avatar.style.background = "var(--surface3)";
|
| 976 |
name.textContent = "No voice selected";
|
| 977 |
-
hint.textContent = "Click to add a voice";
|
| 978 |
}
|
| 979 |
}
|
| 980 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 981 |
// ── Usage Tracker ──
|
| 982 |
|
| 983 |
function updateUsageTracker(addSeconds) {
|
|
|
|
| 8 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 9 |
<style>
|
| 10 |
:root {
|
| 11 |
+
--bg: #0f0e0d;
|
| 12 |
+
--surface: #1c1917;
|
| 13 |
+
--surface2: #292524;
|
| 14 |
+
--surface3: #44403c;
|
| 15 |
+
--border: #44403c;
|
| 16 |
+
--border-hover: #57534e;
|
| 17 |
+
--text: #fafaf9;
|
| 18 |
+
--text-secondary: #a8a29e;
|
| 19 |
+
--text-muted: #78716c;
|
| 20 |
+
--accent: #f59e0b;
|
| 21 |
+
--accent-hover: #fbbf24;
|
| 22 |
+
--accent-subtle: rgba(245,158,11,0.1);
|
| 23 |
+
--accent-glow: rgba(245,158,11,0.12);
|
| 24 |
--danger: #ef4444;
|
| 25 |
--success: #22c55e;
|
| 26 |
+
--warning: #fbbf24;
|
| 27 |
}
|
| 28 |
|
| 29 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
| 66 |
.logo-icon {
|
| 67 |
width: 28px;
|
| 68 |
height: 28px;
|
| 69 |
+
background: linear-gradient(135deg, var(--accent), #d97706);
|
| 70 |
border-radius: 7px;
|
| 71 |
display: flex;
|
| 72 |
align-items: center;
|
|
|
|
| 281 |
}
|
| 282 |
.lang-select:focus { outline: none; border-color: var(--accent); }
|
| 283 |
|
| 284 |
+
/* Settings accordion */
|
| 285 |
+
.settings-accordion {
|
| 286 |
+
margin-bottom: 16px;
|
| 287 |
+
}
|
| 288 |
+
.settings-toggle {
|
| 289 |
+
display: flex; align-items: center; gap: 6px;
|
| 290 |
+
padding: 8px 0; font-size: 12px; font-weight: 500;
|
| 291 |
+
color: var(--text-muted); cursor: pointer; border: none; background: none;
|
| 292 |
+
font-family: 'Inter', sans-serif; transition: color 0.1s;
|
| 293 |
+
}
|
| 294 |
+
.settings-toggle:hover { color: var(--text-secondary); }
|
| 295 |
+
.settings-toggle svg { width: 14px; height: 14px; transition: transform 0.2s; }
|
| 296 |
+
.settings-toggle.open svg { transform: rotate(90deg); }
|
| 297 |
+
.settings-body { display: none; padding-top: 8px; }
|
| 298 |
+
.settings-body.open { display: block; }
|
| 299 |
+
.settings-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
| 300 |
.setting-group { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; }
|
| 301 |
.setting-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 8px; }
|
| 302 |
.setting-value { display: flex; align-items: center; gap: 10px; }
|
| 303 |
.setting-value input[type="range"] { flex: 1; accent-color: var(--accent); height: 4px; }
|
| 304 |
.setting-num { font-size: 13px; color: var(--text-secondary); min-width: 30px; text-align: right; font-variant-numeric: tabular-nums; }
|
| 305 |
|
| 306 |
+
/* Voice picker dropdown */
|
| 307 |
+
.voice-picker-dropdown {
|
| 308 |
+
position: absolute; top: 100%; left: 0; right: 0;
|
| 309 |
+
background: var(--surface); border: 1px solid var(--border);
|
| 310 |
+
border-radius: 10px; margin-top: 4px; z-index: 20;
|
| 311 |
+
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
|
| 312 |
+
max-height: 240px; overflow-y: auto; display: none;
|
| 313 |
+
}
|
| 314 |
+
.voice-picker-dropdown.visible { display: block; }
|
| 315 |
+
.voice-picker-item {
|
| 316 |
+
display: flex; align-items: center; gap: 10px;
|
| 317 |
+
padding: 10px 14px; cursor: pointer; transition: background 0.1s;
|
| 318 |
+
border: none; background: none; width: 100%; text-align: left;
|
| 319 |
+
color: var(--text); font-family: 'Inter', sans-serif; font-size: 13px;
|
| 320 |
+
}
|
| 321 |
+
.voice-picker-item:hover { background: var(--surface2); }
|
| 322 |
+
.voice-picker-item .voice-avatar { width: 30px; height: 30px; font-size: 13px; }
|
| 323 |
+
.voice-picker-item:last-child { border-top: 1px solid var(--border); color: var(--accent); }
|
| 324 |
+
.voice-selector { position: relative; }
|
| 325 |
+
|
| 326 |
/* Generate */
|
| 327 |
.generate-bar { display: flex; gap: 12px; align-items: center; }
|
| 328 |
|
| 329 |
.btn-generate {
|
| 330 |
flex: 1; padding: 14px 24px;
|
| 331 |
+
background: linear-gradient(135deg, #fbbf24, var(--accent));
|
| 332 |
+
color: #1c1917; border: none; border-radius: 10px;
|
| 333 |
font-size: 14px; font-weight: 600; font-family: 'Inter', sans-serif;
|
| 334 |
+
cursor: pointer; transition: all 0.15s;
|
| 335 |
display: flex; align-items: center; justify-content: center; gap: 8px;
|
| 336 |
+
box-shadow: 0 4px 0 #92400e, 0 6px 12px rgba(0,0,0,0.3);
|
| 337 |
+
transform: translateY(0);
|
| 338 |
}
|
| 339 |
+
.btn-generate:hover { filter: brightness(1.05); transform: translateY(-2px); box-shadow: 0 6px 0 #92400e, 0 8px 16px rgba(0,0,0,0.3); }
|
| 340 |
+
.btn-generate:active { transform: translateY(2px); box-shadow: 0 1px 0 #92400e, 0 2px 4px rgba(0,0,0,0.3); }
|
| 341 |
+
.btn-generate:disabled { opacity: 0.4; cursor: not-allowed; transform: none; filter: none; box-shadow: none; }
|
| 342 |
+
.btn-generate .spinner { width: 16px; height: 16px; border: 2px solid rgba(0,0,0,0.2); border-top-color: #1c1917; border-radius: 50%; animation: spin 0.6s linear infinite; display: none; }
|
| 343 |
.btn-generate.loading .spinner { display: block; }
|
| 344 |
.btn-generate.loading .btn-text { display: none; }
|
| 345 |
@keyframes spin { to { transform: rotate(360deg); } }
|
|
|
|
| 350 |
font-size: 13px; display: none; gap: 8px; flex-direction: column;
|
| 351 |
}
|
| 352 |
.status-bar.visible { display: flex; }
|
| 353 |
+
.status-bar.info { background: rgba(245,158,11,0.08); color: var(--accent-hover); border: 1px solid rgba(245,158,11,0.15); }
|
| 354 |
.status-bar.success { background: rgba(34,197,94,0.08); color: var(--success); border: 1px solid rgba(34,197,94,0.15); }
|
| 355 |
.status-bar.error { background: rgba(239,68,68,0.08); color: var(--danger); border: 1px solid rgba(239,68,68,0.15); }
|
| 356 |
|
|
|
|
| 364 |
}
|
| 365 |
.status-cta.upgrade { background: #ff9d00; color: #000; }
|
| 366 |
.status-cta.upgrade:hover { background: #ffb340; }
|
| 367 |
+
.status-cta.credits { background: var(--accent); color: #1c1917; }
|
| 368 |
.status-cta.credits:hover { background: var(--accent-hover); }
|
| 369 |
|
| 370 |
.progress-track { width: 100%; height: 3px; background: var(--surface3); border-radius: 2px; margin-top: 6px; overflow: hidden; display: none; }
|
| 371 |
.progress-track.visible { display: block; }
|
| 372 |
+
.progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent), #fcd34d); border-radius: 2px; transition: width 0.3s; width: 0%; }
|
| 373 |
|
| 374 |
/* Player */
|
| 375 |
.player-card { margin-top: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 16px 20px; display: none; }
|
|
|
|
| 378 |
|
| 379 |
.play-btn {
|
| 380 |
width: 40px; height: 40px; border-radius: 50%; background: var(--accent);
|
| 381 |
+
border: none; color: #1c1917; cursor: pointer;
|
| 382 |
display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.15s;
|
| 383 |
}
|
| 384 |
.play-btn:hover { background: var(--accent-hover); transform: scale(1.05); }
|
|
|
|
| 432 |
font-family: 'Inter', sans-serif; cursor: pointer; border: none; transition: all 0.1s;
|
| 433 |
}
|
| 434 |
|
| 435 |
+
.voice-tile-btn.use { background: var(--accent); color: #1c1917; font-weight: 600; }
|
| 436 |
.voice-tile-btn.use:hover { background: var(--accent-hover); }
|
| 437 |
.voice-tile-btn.del { background: transparent; color: var(--text-muted); border: 1px solid var(--border); }
|
| 438 |
.voice-tile-btn.del:hover { color: var(--danger); border-color: var(--danger); }
|
|
|
|
| 513 |
}
|
| 514 |
.cm { color: var(--text-muted); }
|
| 515 |
.s { color: #86efac; }
|
| 516 |
+
.k { color: #fcd34d; }
|
| 517 |
.f { color: #93c5fd; }
|
| 518 |
|
| 519 |
/* ── Modal ── */
|
|
|
|
| 553 |
.btn-modal { padding: 9px 20px; border-radius: 8px; font-size: 13px; font-weight: 500; font-family: 'Inter', sans-serif; cursor: pointer; transition: all 0.1s; border: none; }
|
| 554 |
.btn-cancel { background: var(--surface2); color: var(--text-secondary); border: 1px solid var(--border); }
|
| 555 |
.btn-cancel:hover { background: var(--surface3); color: var(--text); }
|
| 556 |
+
.btn-save { background: var(--accent); color: #1c1917; font-weight: 600; }
|
| 557 |
.btn-save:hover { background: var(--accent-hover); }
|
| 558 |
.btn-save:disabled { opacity: 0.4; cursor: not-allowed; }
|
| 559 |
|
|
|
|
| 573 |
.btn-hf {
|
| 574 |
padding: 13px 32px; background: #ff9d00; color: #000; border: none; border-radius: 10px;
|
| 575 |
font-size: 15px; font-weight: 600; font-family: 'Inter', sans-serif; cursor: pointer;
|
| 576 |
+
display: inline-flex; align-items: center; gap: 8px; transition: all 0.15s;
|
| 577 |
+
box-shadow: 0 4px 0 #b45309, 0 6px 12px rgba(0,0,0,0.3);
|
| 578 |
}
|
| 579 |
+
.btn-hf:hover { background: #ffb340; transform: translateY(-2px); box-shadow: 0 6px 0 #b45309, 0 8px 16px rgba(0,0,0,0.3); }
|
| 580 |
+
.btn-hf:active { transform: translateY(2px); box-shadow: 0 1px 0 #b45309, 0 2px 4px rgba(0,0,0,0.3); }
|
| 581 |
.landing-note { font-size: 12px; color: var(--text-muted); }
|
| 582 |
|
| 583 |
::-webkit-scrollbar { width: 6px; }
|
|
|
|
| 665 |
<div class="page-desc">Select a voice and type your text to generate speech.</div>
|
| 666 |
</div>
|
| 667 |
|
| 668 |
+
<div class="voice-selector" id="voice-selector" onclick="toggleVoicePicker(event)">
|
| 669 |
<div class="voice-avatar" id="sel-voice-avatar" style="background:var(--surface3)">🎤</div>
|
| 670 |
<div class="voice-selector-info">
|
| 671 |
<div class="voice-selector-name" id="sel-voice-name">No voice selected</div>
|
| 672 |
+
<div class="voice-selector-hint" id="sel-voice-hint">Click to select or add a voice</div>
|
| 673 |
+
</div>
|
| 674 |
+
<div class="voice-selector-change">
|
| 675 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
|
| 676 |
</div>
|
| 677 |
+
<div class="voice-picker-dropdown" id="voice-picker"></div>
|
| 678 |
</div>
|
| 679 |
|
| 680 |
<div class="editor">
|
|
|
|
| 701 |
</div>
|
| 702 |
</div>
|
| 703 |
|
| 704 |
+
<div class="settings-accordion">
|
| 705 |
+
<button class="settings-toggle" onclick="this.classList.toggle('open');this.nextElementSibling.classList.toggle('open')">
|
| 706 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
| 707 |
+
Advanced Settings
|
| 708 |
+
</button>
|
| 709 |
+
<div class="settings-body">
|
| 710 |
+
<div class="settings-row">
|
| 711 |
+
<div class="setting-group">
|
| 712 |
+
<div class="setting-label">Inference Steps</div>
|
| 713 |
+
<div class="setting-value">
|
| 714 |
+
<input type="range" id="setting-steps" min="4" max="64" value="32">
|
| 715 |
+
<span class="setting-num" id="steps-val">32</span>
|
| 716 |
+
</div>
|
| 717 |
+
</div>
|
| 718 |
+
<div class="setting-group">
|
| 719 |
+
<div class="setting-label">Speed</div>
|
| 720 |
+
<div class="setting-value">
|
| 721 |
+
<input type="range" id="setting-speed" min="50" max="150" value="100">
|
| 722 |
+
<span class="setting-num" id="speed-val">1.0x</span>
|
| 723 |
+
</div>
|
| 724 |
+
</div>
|
| 725 |
</div>
|
| 726 |
</div>
|
| 727 |
</div>
|
|
|
|
| 1023 |
avatar.textContent = "🎤";
|
| 1024 |
avatar.style.background = "var(--surface3)";
|
| 1025 |
name.textContent = "No voice selected";
|
| 1026 |
+
hint.textContent = "Click to select or add a voice";
|
| 1027 |
}
|
| 1028 |
}
|
| 1029 |
|
| 1030 |
+
// ── Voice Picker Dropdown ──
|
| 1031 |
+
|
| 1032 |
+
window.toggleVoicePicker = async function(e) {
|
| 1033 |
+
e.stopPropagation();
|
| 1034 |
+
const picker = document.getElementById("voice-picker");
|
| 1035 |
+
if (picker.classList.contains("visible")) {
|
| 1036 |
+
picker.classList.remove("visible");
|
| 1037 |
+
return;
|
| 1038 |
+
}
|
| 1039 |
+
const voices = await getVoices();
|
| 1040 |
+
picker.innerHTML = voices.map(v => `
|
| 1041 |
+
<button class="voice-picker-item" onclick="event.stopPropagation();pickVoice('${v.id}')">
|
| 1042 |
+
<div class="voice-avatar" style="background:${v.color}">${v.name[0].toUpperCase()}</div>
|
| 1043 |
+
<span>${v.name}</span>
|
| 1044 |
+
</button>
|
| 1045 |
+
`).join("") + `
|
| 1046 |
+
<button class="voice-picker-item" onclick="event.stopPropagation();closePickerAndAdd()">
|
| 1047 |
+
+ Add new voice
|
| 1048 |
+
</button>`;
|
| 1049 |
+
picker.classList.add("visible");
|
| 1050 |
+
};
|
| 1051 |
+
|
| 1052 |
+
window.pickVoice = async function(id) {
|
| 1053 |
+
document.getElementById("voice-picker").classList.remove("visible");
|
| 1054 |
+
await window.selectVoice(id);
|
| 1055 |
+
};
|
| 1056 |
+
|
| 1057 |
+
window.closePickerAndAdd = function() {
|
| 1058 |
+
document.getElementById("voice-picker").classList.remove("visible");
|
| 1059 |
+
openAddVoice();
|
| 1060 |
+
};
|
| 1061 |
+
|
| 1062 |
+
document.addEventListener("click", () => {
|
| 1063 |
+
document.getElementById("voice-picker")?.classList.remove("visible");
|
| 1064 |
+
});
|
| 1065 |
+
|
| 1066 |
// ── Usage Tracker ──
|
| 1067 |
|
| 1068 |
function updateUsageTracker(addSeconds) {
|