Fix Recast-selected running on the full roster, improve dropdown positioning (v1.13.7)
csForReaderSelective passed the ENTIRE roster to csGenerate as the target list, so the "N cast characters queued" progress dialog showed every character regardless of what was actually checked in the picker - only the final save step was correctly filtered, making the whole run look like it ignored the selection. Now only the picked name(s) go in as the target roster. Also fixed the "Recast options" dropdown opening off-screen: its anchor sits in the bottom action bar, so opening downward (the default) routinely pushed it past the viewport edge. Opens upward when there isn't enough room below, with more prominent styling. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
95a4c95b90
commit
07eadeff1e
@ -9,6 +9,14 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
|
||||
|
||||
---
|
||||
|
||||
## [1.13.7] — 2026-07-06
|
||||
|
||||
### Fixed
|
||||
- **"Recast selected" showed every character as queued, not just the ones picked** — the progress dialog looked exactly like a full recast because it was passed the entire roster as the target list; the selection only actually took effect at the final save step. Now only the picked character(s) go in as the target roster, so the dialog accurately shows just those as queued.
|
||||
- **"Recast options" dropdown routinely opened off-screen** — its anchor button sits in the bottom action bar, so the menu opening downward (the default) was often pushed past the viewport edge, barely visible. It now opens upward when there isn't enough room below, and is styled more prominently.
|
||||
|
||||
---
|
||||
|
||||
## [1.13.6] — 2026-07-06
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="theme-color" content="#2563EB">
|
||||
<meta name="app-version" content="1.13.6">
|
||||
<meta name="app-version" content="1.13.7">
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||
@ -27,7 +27,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.13.6">
|
||||
<link rel="stylesheet" href="/static/style.css?v=1.13.7">
|
||||
|
||||
|
||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||
@ -365,7 +365,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
||||
</script>
|
||||
|
||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||
<script src="/static/loader.js?v=1.13.6"></script>
|
||||
<script src="/static/loader.js?v=1.13.7"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1048,7 +1048,14 @@ function _abOpenRecastCharsMenu(anchorEl, bookTitle, existingChars) {
|
||||
'<button type="button" data-action="selected"><span class="mdi mdi-checkbox-multiple-marked-outline"></span> Recast selected…</button>';
|
||||
document.body.appendChild(menu);
|
||||
const rect = anchorEl.getBoundingClientRect();
|
||||
menu.style.top = (rect.bottom + 4) + 'px';
|
||||
// The anchor button sits in the panel's bottom action bar, so opening
|
||||
// downward (the default) routinely pushed this near/past the viewport's
|
||||
// bottom edge — barely visible, overlapping the page footer. Open upward
|
||||
// instead whenever there isn't comfortably enough room below.
|
||||
const menuH = 90; // ~2 rows, enough for this fixed 2-item menu
|
||||
const openUp = rect.bottom + menuH + 12 > window.innerHeight;
|
||||
menu.style.top = openUp ? '' : (rect.bottom + 4) + 'px';
|
||||
menu.style.bottom = openUp ? (window.innerHeight - rect.top + 4) + 'px' : '';
|
||||
menu.style.left = Math.max(10, rect.right - 190) + 'px';
|
||||
const close = () => { menu.remove(); document.removeEventListener('mousedown', onDoc); };
|
||||
const onDoc = (e) => { if (!menu.contains(e.target) && e.target !== anchorEl) close(); };
|
||||
|
||||
@ -788,8 +788,12 @@ async function csForReaderSelective(selectedNames) {
|
||||
if (!wanted.size) { toast('No characters selected', 'error'); return; }
|
||||
const text = csReaderText();
|
||||
const book = readerState.title || 'Untitled book';
|
||||
const knownRoster = csKnownReaderRoster();
|
||||
const sheets = await csGenerate(text, null, knownRoster);
|
||||
// Only the picked names go in as the target roster — passing the FULL
|
||||
// roster here (like csForReader does) made the progress dialog show every
|
||||
// character as "queued" even though just one or two were selected, which
|
||||
// read as "it's recasting everyone" even though the save step at the end
|
||||
// was already correctly filtered down to the picks.
|
||||
const sheets = await csGenerate(text, null, selectedNames);
|
||||
if (!sheets) return;
|
||||
const filtered = sheets.filter(s => wanted.has(String(s.name || '').trim().toLowerCase()));
|
||||
if (!filtered.length) { toast('None of the selected characters turned up in this pass — try again or pick different ones', 'error'); return; }
|
||||
|
||||
@ -5658,13 +5658,14 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami
|
||||
.ab-cv-castchars-group .ab-cv-castchars-menu { border-radius: 0 6px 6px 0; border-left: 0; padding: 0 8px; }
|
||||
.ab-recast-menu {
|
||||
position: fixed; z-index: 2001; background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,.3); padding: 4px; min-width: 180px;
|
||||
display: flex; flex-direction: column; gap: 1px;
|
||||
border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,.4); padding: 5px; min-width: 200px;
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
}
|
||||
.ab-recast-menu button {
|
||||
display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 12.5px;
|
||||
border: none; background: none; color: var(--text); border-radius: 5px; cursor: pointer; text-align: left;
|
||||
display: flex; align-items: center; gap: 9px; padding: 9px 11px; font-size: 13px; font-weight: 600;
|
||||
border: none; background: none; color: var(--text); border-radius: 6px; cursor: pointer; text-align: left;
|
||||
}
|
||||
.ab-recast-menu button .mdi { font-size: 16px; color: var(--accent); }
|
||||
.ab-recast-menu button:hover { background: var(--panel); }
|
||||
.ab-recast-select-list { max-height: 280px; overflow-y: auto; margin: 10px 0; text-align: left; border: 1px solid var(--border); border-radius: 6px; padding: 4px; }
|
||||
.ab-recast-select-list label { display: flex; align-items: center; gap: 8px; padding: 5px 6px; cursor: pointer; font-size: 13px; border-radius: 4px; }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user