fix(book): Edit cover now actually shows the cover scaffolding

Two bugs prevented the book cover editor from rendering anything
visible:

1. body.template-book had an unconditional 'display:none !important'
   on .coverOnly (and on .bleedFill, .trimArea, .foldLine, .spineText),
   so when editing-book-cover was set the slot boxes, fold lines, crop
   marks, and trim guides stayed hidden. The hide rule now uses
   :not(.editing-book-cover) for the cover scaffolding while still
   unconditionally hiding the disc/jewel scaffolding (which never
   belongs on a book cover).

2. The .slot positions are driven by --panel-w, --spine-w, --trim-h,
   --bleed, --safe CSS custom properties. renderDimensions() was
   writing DVD-cover state.* values into those for every render,
   including in book cover mode — so even if the slots were visible
   they would have been sized for the last DVD preset, not the book
   spec. renderDimensions now writes book-spec values into the CSS
   vars whenever state.book.editingCover is true, so the back / spine
   / front panels lay out at the book's trim with the spine derived
   from page count × paper thickness.

For the asymmetric cases (coverHasBack=false or coverHasSpine=false),
a new applyBookCoverSlotLayout() helper writes inline left / width
overrides for the slot, trim, fold line, and crop-mark elements so
they sit in the right places. clearBookCoverSlotLayout() drops those
overrides whenever we leave cover edit mode so the CSS defaults take
back over. New body classes no-cover-back / no-cover-spine hide the
slot box for the missing panel.

Slot placeholders ('Enter back image URL' etc.) are hidden in book
cover edit mode — those belong to the DVD URL flow, not the book
cover layer system.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.7 committed 2026-06-04 14:40:01 -04:00
1 parent 549d6a61d9
commit 3f5d244a8e
1 file changed
+120 -11
+120 -11
View File
@@ -1683,15 +1683,36 @@
body.template-book:not(.editing-book-page):not(.editing-book-cover) #layersFieldset,
body.template-book:not(.editing-book-page):not(.editing-book-cover) #printExportRow,
body.template-book:not(.editing-book-page):not(.editing-book-cover) .toolPalette,
body.template-book .coverOnly,
/* Hide DVD/disc/jewel-specific scaffolding in book mode, *except*
when we're actively editing the book's cover spread — then we
want the back/spine/front slot boxes, fold lines, crop marks,
bleed fill and trim guide back, so the canvas looks like the
DVD cover designer scaled to the book's spec. */
body.template-book:not(.editing-book-cover) .coverOnly,
body.template-book:not(.editing-book-cover) .bleedFill,
body.template-book:not(.editing-book-cover) .trimArea,
body.template-book:not(.editing-book-cover) .foldLine,
body.template-book:not(.editing-book-cover) .spineText { display: none !important; }
/* Disc + jewel scaffolding never belongs on a book cover. */
body.template-book .diskLayer,
body.template-book .jewelLayer,
body.template-book .bleedFill,
body.template-book .trimArea,
body.template-book .foldLine,
body.template-book .discSpineStrip,
body.template-book .jewelSpineGuide,
body.template-book .spineText { display: none !important; }
body.template-book .jewelSpineGuide { display: none !important; }
/* When the book has no back panel / no spine, hide those slot
boxes so the front sits alone (JS in renderDimensions positions
it correctly via inline left/width overrides). */
body.template-book.editing-book-cover.no-cover-back .slot.back { display: none !important; }
body.template-book.editing-book-cover.no-cover-spine .slot.spine { display: none !important; }
body.template-book.editing-book-cover.no-cover-spine .spineText { display: none !important; }
body.template-book.editing-book-cover.no-cover-spine .foldLine { display: none !important; }
/* Slot placeholders ("Enter back image URL" etc.) belong to the
DVD cover URL flow; book covers use the layer system instead.
Replace the text in book-cover edit mode via data-label hints
on the slot itself. */
body.template-book.editing-book-cover .slot .placeholder { display: none !important; }
/* When editing the cover, hide the Pages-overview / Cover-summary
panels so the wider canvas takes the room. */
body.template-book.editing-book-cover #bookView { display: none; }
@@ -14092,6 +14113,67 @@
syncBookSidebarSummary();
}
// Book cover edit mode reuses the DVD-style .slot.back / .slot.spine
// / .slot.front scaffolding (positioned via --panel-w / --spine-w
// CSS vars). The canonical book wrap (hasBack && hasSpine) lays out
// correctly via the default CSS rules once those vars hold the
// book's trim + spine. The asymmetric cases (no back, no spine)
// need inline `left` / `width` overrides because the default rules
// assume both panels are present.
function applyBookCoverSlotLayout({ trimW, trimH, spineW, bleed, hasBack, hasSpine }) {
const back = document.getElementById('slot-back');
const spine = document.getElementById('slot-spine');
const front = document.getElementById('slot-front');
const trim = document.querySelector('.trimArea');
const foldL = document.querySelector('.foldLine.left');
const foldR = document.querySelector('.foldLine.right');
const backW = hasBack ? trimW : 0;
const sW = hasSpine ? spineW : 0;
const totalTrimW = backW + sW + trimW;
if (back) { back.style.left = inches(bleed); back.style.width = inches(trimW); }
if (spine) { spine.style.left = inches(bleed + backW); spine.style.width = inches(spineW); }
if (front) { front.style.left = inches(bleed + backW + sW); front.style.width = inches(trimW); }
if (trim) { trim.style.left = inches(bleed); trim.style.width = inches(totalTrimW); }
if (foldL) foldL.style.left = inches(bleed + backW);
if (foldR) foldR.style.left = inches(bleed + backW + sW);
// Crop marks anchor to the four outer corners of the trim.
_setCropMark('.cm-tl-h', bleed - 0.24, bleed);
_setCropMark('.cm-tl-v', bleed, bleed - 0.24);
_setCropMark('.cm-tr-h', bleed + totalTrimW + 0.06, bleed);
_setCropMark('.cm-tr-v', bleed + totalTrimW, bleed - 0.24);
_setCropMark('.cm-bl-h', bleed - 0.24, bleed + trimH);
_setCropMark('.cm-bl-v', bleed, bleed + trimH + 0.06);
_setCropMark('.cm-br-h', bleed + totalTrimW + 0.06, bleed + trimH);
_setCropMark('.cm-br-v', bleed + totalTrimW, bleed + trimH + 0.06);
}
function _setCropMark(sel, leftIn, topIn) {
const el = document.querySelector(sel);
if (!el) return;
el.style.left = inches(leftIn);
el.style.top = inches(topIn);
}
function clearBookCoverSlotLayout() {
// Drop all inline overrides so the CSS defaults take over again
// (used when leaving cover edit mode or switching to a non-book
// template). Idempotent — safe to call on every render.
const ids = ['slot-back', 'slot-spine', 'slot-front'];
for (const id of ids) {
const el = document.getElementById(id);
if (!el) continue;
el.style.left = '';
el.style.width = '';
}
for (const sel of ['.trimArea', '.foldLine.left', '.foldLine.right',
'.cm-tl-h', '.cm-tl-v', '.cm-tr-h', '.cm-tr-v',
'.cm-bl-h', '.cm-bl-v', '.cm-br-h', '.cm-br-v']) {
const el = document.querySelector(sel);
if (!el) continue;
el.style.left = '';
el.style.top = '';
el.style.width = '';
}
}
function renderDimensions() {
if (state.appMode === 'designer') {
const design = state.discDesign;
@@ -14105,11 +14187,38 @@
const root = document.documentElement;
root.style.setProperty('--sheet-w', inches(sheetW()));
root.style.setProperty('--sheet-h', inches(sheetH()));
root.style.setProperty('--panel-w', inches(state.panelW));
root.style.setProperty('--trim-h', inches(state.trimH));
root.style.setProperty('--spine-w', inches(state.spineW));
root.style.setProperty('--bleed', inches(state.bleed));
root.style.setProperty('--safe', inches(state.safe));
// Book cover edit mode reuses the DVD-cover slot scaffolding
// (.slot.back / .slot.spine / .slot.front + bleed + trim + crop
// marks), so the CSS custom properties need to be book-spec
// values rather than the DVD-cover state.* values. Spine width
// re-derives from page count × paper thickness via
// bookSpineWidthInches().
if (state.templateMode === 'book' && state.book?.editingCover) {
const s = state.book.spec || {};
const trimW = Number(s.trimW) || 0;
const trimH = Number(s.trimH) || 0;
const bleed = Number(s.bleed) || 0;
const safe = Number(s.safe) || 0.125;
const hasBack = !!s.coverHasBack;
const hasSpine = !!s.coverHasSpine;
const spineW = hasSpine ? bookSpineWidthInches() : 0;
root.style.setProperty('--panel-w', inches(trimW));
root.style.setProperty('--trim-h', inches(trimH));
root.style.setProperty('--spine-w', inches(spineW));
root.style.setProperty('--bleed', inches(bleed));
root.style.setProperty('--safe', inches(safe));
document.body.classList.toggle('no-cover-back', !hasBack);
document.body.classList.toggle('no-cover-spine', !hasSpine);
applyBookCoverSlotLayout({ trimW, trimH, spineW, bleed, hasBack, hasSpine });
} else {
root.style.setProperty('--panel-w', inches(state.panelW));
root.style.setProperty('--trim-h', inches(state.trimH));
root.style.setProperty('--spine-w', inches(state.spineW));
root.style.setProperty('--bleed', inches(state.bleed));
root.style.setProperty('--safe', inches(state.safe));
document.body.classList.remove('no-cover-back', 'no-cover-spine');
clearBookCoverSlotLayout();
}
const pageW = state.templateMode === 'cover' ? 11 : sheetW();
const pageH = state.templateMode === 'cover' ? 8.5 : sheetH();