diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a410ee..f8f763d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.44.0] — 2026-09-22 + +### Added +- **Magazine: Draw region stays armed after adding a box.** Previously every box meant clicking the toolbar button again; it's now a toggle (with an on/off switch icon on the button itself, since the background colour alone was easy to miss after a few boxes in a row) that stays active until you turn it off. +- **Magazine: a freshly drawn region is ticked in automatically** when its type is one that's actually narrated (Paragraph, Headline, Subheading, Standfirst, Author) — drawing a region already means it belongs in the article. Furniture-like kinds (Page number, Source/footer, Advertisement, Table, Duplicate, OCR noise, Caption, Pull quote, Sidenote, Text in picture) stay unticked, since those are excluded from narration on purpose. +- **Magazine: the region type list is now searchable, with an icon per type.** Filter any of the 16 kinds by typing instead of scrolling a plain dropdown. + ## [1.43.1] — 2026-09-22 ### Fixed @@ -4321,7 +4328,8 @@ Initial feature-complete release. --- -[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.43.1...HEAD +[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.44.0...HEAD +[1.44.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.43.1...v1.44.0 [1.43.1]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.43.0...v1.43.1 [1.26.10]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.26.9...v1.26.10 [1.26.9]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.26.8...v1.26.9 diff --git a/VERSION b/VERSION index 3987c47..372cf40 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.43.1 +1.44.0 diff --git a/static/index.html b/static/index.html index a2088d0..18588db 100644 --- a/static/index.html +++ b/static/index.html @@ -10,7 +10,7 @@ - + @@ -27,12 +27,12 @@ - - - - - - + + + + + + @@ -403,7 +403,7 @@ window.toggleNavTree = function(treeId, chevronId) { - + diff --git a/static/js/magazine.js b/static/js/magazine.js index 038c3ab..d3154a7 100644 --- a/static/js/magazine.js +++ b/static/js/magazine.js @@ -919,12 +919,26 @@ function magReviewGoMagazinePage(page) { // read" without reading the label. No table detection exists yet (P2), so a // table currently reads as its own text region like any other paragraph. // What a region can be changed into from the review list. Values match the server's REGION_TYPES. +// Mirrors core/magazine.py's NARRATABLE -- the kinds that are actually read +// aloud. A freshly drawn region of one of these is ticked in automatically +// (see magReviewSubmitDraw); everything else (page number, source, ad, +// table, duplicate, OCR noise, caption, pull quote, sidenote) is furniture +// or reference material excluded from narration on purpose and stays unticked. +const MAG_NARRATABLE_KINDS = new Set(['title', 'heading', 'deck', 'byline', 'body']); const MAG_REGION_TYPES = [ ['body', 'Paragraph'], ['title', 'Headline'], ['heading', 'Subheading'], ['deck', 'Standfirst'], ['byline', 'Author'], ['caption', 'Caption'], ['pullquote', 'Pull quote'], ['sidebar', 'Sidenote'], ['page_number', 'Page number'], ['source', 'Source / footer'], ['ad', 'Advertisement'], ['in_picture', 'Text in picture'], ['ocr_noise', 'OCR noise'], ['duplicate', 'Duplicate'], ['table', 'Table'], ['image', 'Image'], ]; +const MAG_REGION_TYPE_ICONS = { + body: 'mdi-text-box-outline', title: 'mdi-format-title', heading: 'mdi-format-header-2', + deck: 'mdi-text-short', byline: 'mdi-account-edit-outline', caption: 'mdi-image-text', + pullquote: 'mdi-format-quote-close', sidebar: 'mdi-note-text-outline', page_number: 'mdi-numeric', + source: 'mdi-book-open-page-variant-outline', ad: 'mdi-advertisements-outline', + in_picture: 'mdi-text-recognition', ocr_noise: 'mdi-alert-circle-outline', + duplicate: 'mdi-content-duplicate', table: 'mdi-table', image: 'mdi-image-outline', +}; // Furniture kinds that the picker shows under their own name (everything else is a page number). const MAG_FURNITURE_KINDS = ['source', 'in_picture', 'ocr_noise', 'duplicate']; @@ -1172,8 +1186,9 @@ function renderReview() { 'onclick="magReviewToggleSpread()"> ' + (state.reviewSpread ? 'Single page' : 'Two-page spread') + '' + '
' + - '' + + '' + '' + @@ -1675,19 +1690,36 @@ function magReviewHighlightBox(blockId) { // cover that). Percent-of-image coordinates while dragging, converted to // PDF-point page coordinates (matching every other bbox in the layout) only // once the user commits the region. -function magReviewToggleDraw(kind = 'text') { - state.drawMode = state.drawMode && state.drawKind === kind ? false : true; - state.drawKind = kind; - if (state.drawMode && state.editMode) magReviewToggleEdit(); +// Applies state.drawMode/drawKind to the DOM -- pulled out of +// magReviewToggleDraw so magReviewSubmitDraw can re-assert the same "still +// drawing" visuals after renderReview() rebuilds the toolbar from scratch +// (which has no memory of drawMode, since that class was only ever applied +// imperatively, never baked into the template). +function _magSyncDrawUi() { const hint = $('mag-draw-hint'); - const field = kind === 'title' ? 'title' : kind === 'author' ? 'author' : ''; + const field = state.drawKind === 'title' ? 'title' : state.drawKind === 'author' ? 'author' : ''; if (hint) hint.textContent = state.drawMode ? (field ? ` Drag around the ${field} text to OCR it into this field. Press Escape to cancel.` : ' Drag around the region, then say what it is. Press Escape to cancel.') : ''; const wrap = $('mag-review-page-wrap'); if (wrap) wrap.classList.toggle('is-drawing', state.drawMode); const btn = $('mag-draw-toggle'); - if (btn) { btn.classList.toggle('active', state.drawMode && kind === 'text'); btn.setAttribute('aria-pressed', String(state.drawMode && kind === 'text')); } + if (btn) { btn.classList.toggle('active', state.drawMode); btn.setAttribute('aria-pressed', String(state.drawMode)); } + // A background-colour change alone was easy to miss once several regions + // in a row had been added -- confirmed live. An explicit on/off switch + // icon is a second, unambiguous cue for the same state. + const switchIcon = $('mag-draw-toggle-switch'); + if (switchIcon) { + switchIcon.classList.toggle('mdi-toggle-switch', state.drawMode); + switchIcon.classList.toggle('mdi-toggle-switch-off-outline', !state.drawMode); + } +} + +function magReviewToggleDraw(kind = 'text') { + state.drawMode = state.drawMode && state.drawKind === kind ? false : true; + state.drawKind = kind; + if (state.drawMode && state.editMode) magReviewToggleEdit(); + _magSyncDrawUi(); magReviewCancelDrawPanel(); } @@ -2163,9 +2195,13 @@ function magReviewOpenDrawPanel(box) { '
' : '
' + - '' + + '
' + + '' + + '' + + '' + + '' + + '
' + '
' + '' + '' + @@ -2178,15 +2214,78 @@ wrap.appendChild(panel); const top = parseFloat(box.style.top) || 0, left = parseFloat(box.style.left) || 0, height = parseFloat(box.style.height) || 0; panel.style.top = Math.min(85, top + height + 1) + '%'; panel.style.left = Math.min(60, left) + '%'; - const kindSelect = $('mag-draw-kind'); - if (kindSelect) { - kindSelect.addEventListener('change', () => { - const isImage = kindSelect.value === 'image'; - const ta = $('mag-draw-text'); - if (ta) ta.hidden = isImage; - $('mag-draw-exclude').hidden = !isImage; - }); - } + if ($('mag-draw-kind-picker')) _magSetupDrawKindPicker(drawKindOptions); +} + +// A 16-option is slow to scan and slow to reach by scrolling; this filters by + typing and shows an icon per type instead. */ +.mag-type-picker { position: relative; display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; } +.mag-type-picker label { flex-shrink: 0; } +.mag-type-picker-input { flex: 1; min-width: 0; font: inherit; font-size: 12px; padding: 4px 6px; + border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--text); } +.mag-type-picker-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,.18); } +.mag-type-picker-list { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; margin: 2px 0 0; + padding: 4px; list-style: none; max-height: 240px; overflow-y: auto; background: var(--surface); + border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 6px 18px rgba(0,0,0,.25); } +.mag-type-picker-option { display: flex; align-items: center; gap: 8px; padding: 6px 8px; font-size: 13px; + border-radius: 5px; cursor: pointer; color: var(--text); } +.mag-type-picker-option .mdi { color: var(--subtext); font-size: 16px; flex-shrink: 0; } +.mag-type-picker-option:hover { background: var(--panel); } +.mag-type-picker-option.is-selected { background: var(--accent); color: var(--on-accent); } +.mag-type-picker-option.is-selected .mdi { color: inherit; } +.mag-type-picker-empty { padding: 6px 8px; font-size: 13px; } + /* Editing an already-detected region: move by dragging the box body, resize from its corner handle, delete with its ×. Handles and the delete button only render usably in edit mode -- kept in the DOM at all times (rather