fix: stop casting feed from hijacking scroll and deleting visible rows
- Auto-scroll to bottom is now gated on the user being within 80px of the bottom. Scrolling up to review or edit a line freezes the feed in place — new rows are still added, but the viewport doesn't move. - Row-trimming is likewise suppressed while the user is scrolled up, so old lines stay visible as long as they're being read/edited. Trim limit raised from 80 → 600 rows so almost nothing is evicted. - A floating "↓ Live" pill button appears at the bottom of the feed whenever the user has scrolled up. Clicking it returns to the live bottom and re-enables auto-scroll. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a978e39e49
commit
6b52a346d5
11
CHANGELOG.md
11
CHANGELOG.md
@ -9,6 +9,17 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
||||
|
||||
---
|
||||
|
||||
## [1.9.6] — 2026-06-26
|
||||
|
||||
### Fixed
|
||||
- **Casting feed — scroll hijacking**: the feed no longer forces the view to the bottom while you are scrolled up reviewing or editing earlier lines. Auto-scroll only fires when you are already within 80px of the bottom.
|
||||
- **Casting feed — vanishing text**: the trimming limit was raised from 80 to 600 rows, and trimming is now suppressed while you're scrolled up, so older lines stay visible as long as you're looking at them.
|
||||
|
||||
### Added
|
||||
- **Casting feed — "↓ Live" jump button**: a floating pill button appears at the bottom of the feed whenever you've scrolled up. Click it to immediately return to the live bottom of the feed and re-enable auto-scroll.
|
||||
|
||||
---
|
||||
|
||||
## [1.9.5] — 2026-06-26
|
||||
|
||||
### Added
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.9.5">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.9.6">
|
||||
|
||||
|
||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||
@ -308,7 +308,7 @@
|
||||
<script src="/static/vendor/wavesurfer-regions.min.js"></script>
|
||||
|
||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||
<script src="/static/loader.js?v=1.9.5"></script>
|
||||
<script src="/static/loader.js?v=1.9.6"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -226,7 +226,10 @@ function audiobookCastView(total, llmUrl, defaultModel, isIdle = false) {
|
||||
<div id="ab-cv-fill-text" style="position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:600; color:var(--text); text-shadow: 0px 1px 2px var(--bg), 0px -1px 2px var(--bg); pointer-events:none;">0%</div>
|
||||
</div>
|
||||
<div class="ab-cv-body">
|
||||
<div class="ab-cv-feed-wrap">
|
||||
<div class="ab-cv-feed" id="ab-cv-feed"></div>
|
||||
<button class="ab-cv-jump-btn" id="ab-cv-jump-btn" hidden title="Jump to latest"><span class="mdi mdi-chevron-double-down"></span> Live</button>
|
||||
</div>
|
||||
<div class="ab-cv-side">
|
||||
<div class="ab-cv-side-head">Characters found</div>
|
||||
<div class="ab-cv-chars" id="ab-cv-chars"><span class="ab-cv-empty">reading…</span></div>
|
||||
@ -463,8 +466,29 @@ STRIKTE FORMAT- UND TEXTREGELN:
|
||||
? items.map(([n, info]) => `<span class="ab-chip" style="--c:${info.color}"><span class="ab-chip-dot"></span>${escHtml(n)}<b>${info.count}</b></span>`).join('')
|
||||
: '<span class="ab-cv-empty">reading…</span>';
|
||||
};
|
||||
const MAXROWS = 80;
|
||||
const trim = () => { while (feed.childElementCount > MAXROWS) feed.removeChild(feed.firstChild); feed.scrollTop = feed.scrollHeight; };
|
||||
const MAXROWS = 600; // keep most of the book visible; only trim when user is at bottom
|
||||
// Whether the user has scrolled up to review/edit earlier content.
|
||||
// While true: auto-scroll and trim are suppressed so their position is preserved.
|
||||
let _userScrolled = false;
|
||||
const jumpBtn = panel.querySelector('#ab-cv-jump-btn');
|
||||
feed.addEventListener('scroll', () => {
|
||||
const atBottom = feed.scrollTop + feed.clientHeight >= feed.scrollHeight - 80;
|
||||
_userScrolled = !atBottom;
|
||||
if (jumpBtn) jumpBtn.hidden = atBottom;
|
||||
}, { passive: true });
|
||||
const _scrollToBottom = () => { feed.scrollTop = feed.scrollHeight; };
|
||||
if (jumpBtn) {
|
||||
jumpBtn.addEventListener('click', () => {
|
||||
_userScrolled = false;
|
||||
jumpBtn.hidden = true;
|
||||
_scrollToBottom();
|
||||
});
|
||||
}
|
||||
const trim = () => {
|
||||
if (_userScrolled) return; // don't touch the feed while user is reading/editing
|
||||
while (feed.childElementCount > MAXROWS) feed.removeChild(feed.firstChild);
|
||||
_scrollToBottom();
|
||||
};
|
||||
|
||||
// Manual character assignment logic
|
||||
let assignModeSeg = null;
|
||||
|
||||
@ -4153,7 +4153,17 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami
|
||||
}
|
||||
|
||||
.ab-cv-body { display: grid; grid-template-columns: 1fr 220px; gap: 12px; padding: 12px; flex: 1; min-height: 0; }
|
||||
.ab-cv-feed { min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; background: var(--panel); display: flex; flex-direction: column; gap: 3px; }
|
||||
.ab-cv-feed-wrap { position: relative; min-height: 0; display: flex; flex-direction: column; }
|
||||
.ab-cv-feed { flex: 1; min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; background: var(--panel); display: flex; flex-direction: column; gap: 3px; }
|
||||
.ab-cv-jump-btn {
|
||||
position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);
|
||||
display: flex; align-items: center; gap: 4px;
|
||||
padding: 5px 14px; font-size: 12px; font-weight: 700;
|
||||
background: var(--accent); color: #fff; border: none; border-radius: 20px;
|
||||
cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.25); z-index: 5;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ab-cv-jump-btn:hover { filter: brightness(1.1); }
|
||||
.ab-cv-row {
|
||||
display: block;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user