From 3f5d244a8e4dc512497866b2f93e3f7bf006c8a9 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:40:01 -0400 Subject: [PATCH] fix(book): Edit cover now actually shows the cover scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/index.html | 131 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 11 deletions(-) diff --git a/src/index.html b/src/index.html index c2cf372..8512a6d 100644 --- a/src/index.html +++ b/src/index.html @@ -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();