This commit is contained in:
parent
ab5fce10bf
commit
ba3b374246
13
CHANGELOG.md
13
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
|
## [1.52.1] — 2026-09-22
|
||||||
|
|
||||||
### Fixed
|
### 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.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.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
|
[1.51.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.50.0...v1.51.0
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
<meta name="theme-color" content="#2563EB">
|
<meta name="theme-color" content="#2563EB">
|
||||||
<meta name="app-version" content="1.52.1">
|
<meta name="app-version" content="1.53.0">
|
||||||
<link rel="manifest" href="/manifest.webmanifest">
|
<link rel="manifest" href="/manifest.webmanifest">
|
||||||
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||||
@ -27,12 +27,12 @@
|
|||||||
|
|
||||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||||
<link rel="stylesheet" href="/static/style.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/style.css?v=1.53.0">
|
||||||
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.53.0">
|
||||||
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.53.0">
|
||||||
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.53.0">
|
||||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.53.0">
|
||||||
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.52.1">
|
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.53.0">
|
||||||
|
|
||||||
|
|
||||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||||
@ -403,7 +403,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||||
<script src="/static/loader.js?v=1.52.1"></script>
|
<script src="/static/loader.js?v=1.53.0"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -779,6 +779,25 @@ const MAG_PAGES_COLS_KEY = 'ttsvc_mag_pages_cols';
|
|||||||
// magUncoveredPageRanges). This is the complete picture: a page can belong
|
// magUncoveredPageRanges). This is the complete picture: a page can belong
|
||||||
// to zero articles (never reviewed), one, or several (a page shared by two
|
// 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.
|
// 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) {
|
function renderPagesView(host) {
|
||||||
const pageCount = state.doc?.pageCount || 0;
|
const pageCount = state.doc?.pageCount || 0;
|
||||||
if (!pageCount) { host.innerHTML = '<p class="muted">Page count unknown yet.</p>'; return; }
|
if (!pageCount) { host.innerHTML = '<p class="muted">Page count unknown yet.</p>'; return; }
|
||||||
@ -787,10 +806,17 @@ function renderPagesView(host) {
|
|||||||
if (!byPage.has(p)) byPage.set(p, []);
|
if (!byPage.has(p)) byPage.set(p, []);
|
||||||
byPage.get(p).push(a);
|
byPage.get(p).push(a);
|
||||||
}));
|
}));
|
||||||
let html = '<div class="mag-pages-grid" style="--cols:' + state.pagesCols + '">';
|
const legend = [
|
||||||
|
['blank', 'not reviewed yet'], ['detected', 'has content, not reviewed'],
|
||||||
|
['approved', 'reviewed'], ['audio', 'reviewed + audio generated'], ['empty', 'reviewed, nothing to narrate'],
|
||||||
|
];
|
||||||
|
let html = '<p class="mag-pages-legend">' +
|
||||||
|
legend.map(([cls, label]) => '<span class="mag-pages-legend-item"><span class="mag-pages-legend-swatch is-page-' + cls + '"></span>' + label + '</span>').join('') +
|
||||||
|
'</p>';
|
||||||
|
html += '<div class="mag-pages-grid" style="--cols:' + state.pagesCols + '">';
|
||||||
for (let p = 1; p <= pageCount; p++) {
|
for (let p = 1; p <= pageCount; p++) {
|
||||||
const arts = byPage.get(p) || [];
|
const arts = byPage.get(p) || [];
|
||||||
html += '<div class="mag-card-wrap"><div class="mag-card' + (arts.length ? '' : ' is-uncovered') + '">' +
|
html += '<div class="mag-card-wrap"><div class="mag-card is-page-' + magPageState(arts) + '">' +
|
||||||
'<img class="mag-card-thumb" loading="lazy" alt="Page ' + p + '" src="/api/magazine/' + esc(state.doc.id) + '/pages/' + p + '">' +
|
'<img class="mag-card-thumb" loading="lazy" alt="Page ' + p + '" src="/api/magazine/' + esc(state.doc.id) + '/pages/' + p + '">' +
|
||||||
'<span class="mag-card-title">Page ' + p + '</span>' +
|
'<span class="mag-card-title">Page ' + p + '</span>' +
|
||||||
(arts.length
|
(arts.length
|
||||||
|
|||||||
@ -4945,8 +4945,22 @@ input[list="lang-codes"] {
|
|||||||
#mag-cols-value { min-width: 16px; text-align: right; }
|
#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: 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); } }
|
@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);
|
/* Page-state colours in the "All pages" grid -- blank (no article yet) is
|
||||||
background: color-mix(in srgb, var(--yellow, #d97706) 6%, var(--surface)); }
|
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;
|
.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);
|
padding: 10px 14px; margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user