diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f7c1e7..fa494cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.53.0] — 2026-09-23 + +### Added +- **Magazine: the "All pages" grid is colour-coded by review status** — blank (no article yet, the normal mid-review state), red (has content, not reviewed), yellow (reviewed), green (reviewed and MP3 generated), grey (reviewed, nothing to narrate — a blank page or an ad). A small legend explains the colours. + +### Fixed +- **Magazine: "Review this page" on a page-coverage gap failed with "Method Not Allowed."** The endpoint it needs (`POST /api/magazine/{doc_id}/articles`, added alongside the gap-jump feature itself) had never actually been deployed with a container restart. + +--- + ## [1.52.1] — 2026-09-22 ### Fixed @@ -4419,7 +4429,8 @@ Initial feature-complete release. --- -[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.1...HEAD +[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.53.0...HEAD +[1.53.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.1...v1.53.0 [1.52.1]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.52.0...v1.52.1 [1.52.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.51.0...v1.52.0 [1.51.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.50.0...v1.51.0 diff --git a/VERSION b/VERSION index 154cb93..3f48301 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.52.1 +1.53.0 diff --git a/static/index.html b/static/index.html index 524a149..f007015 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 0507999..9c86fd8 100644 --- a/static/js/magazine.js +++ b/static/js/magazine.js @@ -779,6 +779,25 @@ const MAG_PAGES_COLS_KEY = 'ttsvc_mag_pages_cols'; // magUncoveredPageRanges). This is the complete picture: a page can belong // to zero articles (never reviewed), one, or several (a page shared by two // short pieces), and this shows all three cases rather than picking one. +// One of five states per page, cheap to compute from data already loaded +// (no extra layout/OCR fetch just to colour an overview grid): +// blank -- no article touches this page at all yet +// detected -- an article does, but it's still sitting at its +// just-detected status -- OCR ran, a human hasn't looked +// approved -- reviewed and approved, no audio rendered yet +// audio -- reviewed, approved, and has a generated MP3 +// empty -- reviewed and rejected ("Not an article") on every article +// that touches it -- a blank page or an ad, not a gap +// A page touched by several articles takes the most-attention-needed state +// among them (audio beats approved beats detected beats empty). +function magPageState(arts) { + if (!arts.length) return 'blank'; + if (arts.some((a) => a.has_audio)) return 'audio'; + if (arts.some((a) => a.status === 'detected')) return 'detected'; + if (arts.some((a) => a.status === 'approved')) return 'approved'; + return 'empty'; +} + function renderPagesView(host) { const pageCount = state.doc?.pageCount || 0; if (!pageCount) { host.innerHTML = '

Page count unknown yet.

'; return; } @@ -787,10 +806,17 @@ function renderPagesView(host) { if (!byPage.has(p)) byPage.set(p, []); byPage.get(p).push(a); })); - let html = '
'; + const legend = [ + ['blank', 'not reviewed yet'], ['detected', 'has content, not reviewed'], + ['approved', 'reviewed'], ['audio', 'reviewed + audio generated'], ['empty', 'reviewed, nothing to narrate'], + ]; + let html = '

' + + legend.map(([cls, label]) => '' + label + '').join('') + + '

'; + html += '
'; for (let p = 1; p <= pageCount; p++) { const arts = byPage.get(p) || []; - html += '
' + + html += '
' + 'Page ' + p + '' + 'Page ' + p + '' + (arts.length diff --git a/static/style.css b/static/style.css index 9503f5d..fd5c075 100644 --- a/static/style.css +++ b/static/style.css @@ -4945,8 +4945,22 @@ input[list="lang-codes"] { #mag-cols-value { min-width: 16px; text-align: right; } @media (max-width: 900px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 4), 1fr); } } @media (max-width: 560px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 2), 1fr); } } -.mag-card.is-uncovered { border-color: var(--yellow, #d97706); - background: color-mix(in srgb, var(--yellow, #d97706) 6%, var(--surface)); } +/* Page-state colours in the "All pages" grid -- blank (no article yet) is + deliberately the plain default look, not a warning: an untouched page is + normal mid-review, unlike a page that already has content sitting + unreviewed (detected, red) or with nothing worth narrating (empty, grey, + which is a completed decision, not a problem). */ +.mag-card.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, var(--surface)); } +.mag-card.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 8%, var(--surface)); } +.mag-card.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, var(--surface)); } +.mag-card.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 8%, var(--surface)); } +.mag-pages-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--subtext); margin: 0 0 12px; } +.mag-pages-legend-item { display: inline-flex; align-items: center; gap: 5px; } +.mag-pages-legend-swatch { width: 12px; height: 12px; border-radius: 3px; border: 2px solid var(--border); } +.mag-pages-legend-swatch.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 20%, var(--surface)); } +.mag-pages-legend-swatch.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 20%, var(--surface)); } +.mag-pages-legend-swatch.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 20%, var(--surface)); } +.mag-pages-legend-swatch.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 20%, var(--surface)); } .mag-audio-export { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 14px; margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius);