apolinario commited on
Commit
63fd7b5
·
1 Parent(s): 77edcd1

Audiobook: row remove button, voice chip with arrow + name label, subtler lines, wider page

Browse files
Files changed (1) hide show
  1. index.html +50 -12
index.html CHANGED
@@ -284,6 +284,7 @@ body {
284
  }
285
 
286
  .content-inner { width: 100%; max-width: 720px; }
 
287
 
288
  .page { display: none; }
289
  .page.active { display: block; }
@@ -369,22 +370,38 @@ body {
369
  padding: 8px 14px; border: 1px solid var(--border); border-top: none;
370
  border-radius: 0 0 12px 12px; background: var(--surface2); margin-bottom: 16px;
371
  }
372
- .ab-row { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0; position: relative; }
373
  .ab-chip {
374
- flex: none; width: 30px; height: 30px; border-radius: 50%; border: 2px solid var(--border);
375
- background: var(--surface3); color: #fff; font-size: 12px; font-weight: 700; cursor: pointer;
376
- display: flex; align-items: center; justify-content: center; margin-top: 1px; padding: 0;
377
- position: relative;
 
 
 
 
 
 
 
 
 
378
  }
379
- .ab-chip.overridden { box-shadow: 0 0 0 2px var(--accent); }
380
  .ab-para {
381
- flex: 1; font-size: 15px; line-height: 1.55; color: var(--text); padding: 3px 6px;
382
- border-radius: 6px; background: rgba(255, 251, 5, 0.16); outline: none; min-height: 1.55em;
383
  white-space: pre-wrap; word-break: break-word;
384
  }
385
- .ab-para:focus { background: rgba(255, 251, 5, 0.28); }
 
386
  .ab-para:empty::before { content: "Type or paste a paragraph… (Enter starts a new line, each line is its own voice)"; color: var(--text-muted); pointer-events: none; }
387
  .ab-row-side { flex: none; display: flex; align-items: center; gap: 6px; margin-top: 2px; }
 
 
 
 
 
 
388
  .ab-play-one {
389
  width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--border);
390
  background: var(--surface3); color: var(--text-secondary); cursor: pointer; padding: 0;
@@ -3793,8 +3810,14 @@ function renderAbRows() {
3793
  chip.type = "button";
3794
  chip.className = "ab-chip" + (s.voiceId ? " overridden" : "");
3795
  const eff = abEffectiveVoice(s.voiceId);
3796
- chip.style.background = eff.color;
3797
- chip.textContent = eff.initial;
 
 
 
 
 
 
3798
  chip.title = `Voice: ${eff.label}${s.voiceId ? " (override)" : " (default)"} — click to change`;
3799
  chip.onmousedown = (e) => e.preventDefault();
3800
  chip.onclick = (e) => abOpenVoiceMenu(e, i);
@@ -3818,7 +3841,10 @@ function renderAbRows() {
3818
  const st = document.createElement("span");
3819
  st.className = "ab-row-status " + (s.status === "idle" ? "" : s.status);
3820
  st.textContent = s.status === "done" ? "✓" : s.status === "error" ? "✕" : s.status === "active" ? "…" : "";
3821
- side.appendChild(play); side.appendChild(st);
 
 
 
3822
 
3823
  row.appendChild(chip); row.appendChild(para); row.appendChild(side);
3824
  doc.appendChild(row);
@@ -3886,6 +3912,18 @@ function abParaPaste(e, i) {
3886
  }
3887
  }
3888
 
 
 
 
 
 
 
 
 
 
 
 
 
3889
  window.abClearDoc = function() {
3890
  abSegments = [{ text: "", voiceId: "", status: "idle", url: null }];
3891
  renderAbRows();
 
284
  }
285
 
286
  .content-inner { width: 100%; max-width: 720px; }
287
+ .content-inner:has(#page-audiobook.active) { max-width: 960px; }
288
 
289
  .page { display: none; }
290
  .page.active { display: block; }
 
370
  padding: 8px 14px; border: 1px solid var(--border); border-top: none;
371
  border-radius: 0 0 12px 12px; background: var(--surface2); margin-bottom: 16px;
372
  }
373
+ .ab-row { display: flex; align-items: flex-start; gap: 10px; padding: 4px 0; position: relative; }
374
  .ab-chip {
375
+ flex: none; width: 56px; background: none; border: none; cursor: pointer; padding: 0;
376
+ display: flex; flex-direction: column; align-items: center; gap: 2px; margin-top: 1px;
377
+ }
378
+ .ab-chip-av {
379
+ width: 30px; height: 30px; border-radius: 50%; border: 2px solid var(--border);
380
+ color: #fff; font-size: 12px; font-weight: 700;
381
+ display: flex; align-items: center; justify-content: center; gap: 1px; position: relative;
382
+ }
383
+ .ab-chip-av svg { width: 9px; height: 9px; opacity: 0.85; }
384
+ .ab-chip.overridden .ab-chip-av { box-shadow: 0 0 0 2px var(--accent); }
385
+ .ab-chip-name {
386
+ font-size: 10px; font-weight: 600; color: var(--text-muted); max-width: 56px;
387
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.2;
388
  }
389
+ .ab-chip:hover .ab-chip-name { color: var(--text-secondary); }
390
  .ab-para {
391
+ flex: 1; font-size: 15px; line-height: 1.55; color: var(--text); padding: 4px 8px;
392
+ border-radius: 6px; background: transparent; outline: none; min-height: 1.55em;
393
  white-space: pre-wrap; word-break: break-word;
394
  }
395
+ .ab-para:hover { background: var(--surface2); }
396
+ .ab-para:focus { background: var(--surface2); }
397
  .ab-para:empty::before { content: "Type or paste a paragraph… (Enter starts a new line, each line is its own voice)"; color: var(--text-muted); pointer-events: none; }
398
  .ab-row-side { flex: none; display: flex; align-items: center; gap: 6px; margin-top: 2px; }
399
+ .ab-row-del {
400
+ width: 24px; height: 24px; border-radius: 6px; border: 1px solid transparent;
401
+ background: none; color: var(--text-muted); cursor: pointer; padding: 0;
402
+ display: flex; align-items: center; justify-content: center; font-size: 15px; line-height: 1;
403
+ }
404
+ .ab-row-del:hover { color: #dc2626; border-color: var(--border); background: var(--surface3); }
405
  .ab-play-one {
406
  width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--border);
407
  background: var(--surface3); color: var(--text-secondary); cursor: pointer; padding: 0;
 
3810
  chip.type = "button";
3811
  chip.className = "ab-chip" + (s.voiceId ? " overridden" : "");
3812
  const eff = abEffectiveVoice(s.voiceId);
3813
+ const av = document.createElement("span");
3814
+ av.className = "ab-chip-av";
3815
+ av.style.background = eff.color;
3816
+ av.innerHTML = `<span>${eff.initial}</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="6 9 12 15 18 9"/></svg>`;
3817
+ const nm = document.createElement("span");
3818
+ nm.className = "ab-chip-name";
3819
+ nm.textContent = eff.label;
3820
+ chip.appendChild(av); chip.appendChild(nm);
3821
  chip.title = `Voice: ${eff.label}${s.voiceId ? " (override)" : " (default)"} — click to change`;
3822
  chip.onmousedown = (e) => e.preventDefault();
3823
  chip.onclick = (e) => abOpenVoiceMenu(e, i);
 
3841
  const st = document.createElement("span");
3842
  st.className = "ab-row-status " + (s.status === "idle" ? "" : s.status);
3843
  st.textContent = s.status === "done" ? "✓" : s.status === "error" ? "✕" : s.status === "active" ? "…" : "";
3844
+ const del = document.createElement("button");
3845
+ del.type = "button"; del.className = "ab-row-del"; del.title = "Remove line"; del.textContent = "✕";
3846
+ del.onclick = () => abRemoveRow(i);
3847
+ side.appendChild(play); side.appendChild(st); side.appendChild(del);
3848
 
3849
  row.appendChild(chip); row.appendChild(para); row.appendChild(side);
3850
  doc.appendChild(row);
 
3912
  }
3913
  }
3914
 
3915
+ window.abRemoveRow = function(i) {
3916
+ if (abSegments.length <= 1) {
3917
+ abSegments = [{ text: "", voiceId: "", status: "idle", url: null }];
3918
+ renderAbRows();
3919
+ abFocusRow(0, 0);
3920
+ return;
3921
+ }
3922
+ abSegments.splice(i, 1);
3923
+ renderAbRows();
3924
+ abFocusRow(Math.max(0, i - 1), abSegments[Math.max(0, i - 1)].text.length);
3925
+ };
3926
+
3927
  window.abClearDoc = function() {
3928
  abSegments = [{ text: "", voiceId: "", status: "idle", url: null }];
3929
  renderAbRows();