Release v1.47.0
Some checks are pending
Test and SonarQube / quality (push) Waiting to run

This commit is contained in:
mARTin-B78 2026-09-22 22:15:11 +02:00
parent bc3f82d975
commit e00103dfb9
5 changed files with 65 additions and 18 deletions

View File

@ -9,6 +9,14 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
---
## [1.47.0] — 2026-09-22
### Added
- **Magazine: click a region's text to edit it, no pencil icon needed.** The pencil-icon editor (with its Save/Split-here/Cancel actions) still opens exactly the same way — this just adds the text itself as a faster path to it, since the row is a checkbox `<label>` and a plain click would otherwise just toggle the tick.
- **Magazine: review boxes are colour-coded by region type**, reusing the exact palette the live ingest preview already used — a headline, an author line, an advertisement now each have a distinct colour on the page itself, not only while detection is running. A small legend explains the colours; excluded/unticked and cross-article-linked boxes keep their own distinct look regardless of type.
---
## [1.46.0] — 2026-09-22
### Added
@ -4343,7 +4351,8 @@ Initial feature-complete release.
---
[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.46.0...HEAD
[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.47.0...HEAD
[1.47.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.46.0...v1.47.0
[1.46.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.45.0...v1.46.0
[1.45.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.44.0...v1.45.0
[1.44.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.43.1...v1.44.0

View File

@ -1 +1 @@
1.46.0
1.47.0

View File

@ -10,7 +10,7 @@
<meta name="format-detection" content="telephone=no">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#2563EB">
<meta name="app-version" content="1.46.0">
<meta name="app-version" content="1.47.0">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/static/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/static/icon.svg">
@ -27,12 +27,12 @@
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/style.css?v=1.46.0">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.46.0">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.46.0">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.46.0">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.46.0">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.46.0">
<link rel="stylesheet" href="/static/style.css?v=1.47.0">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.47.0">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.47.0">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.47.0">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.47.0">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.47.0">
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
@ -403,7 +403,7 @@ window.toggleNavTree = function(treeId, chevronId) {
</script>
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
<script src="/static/loader.js?v=1.46.0"></script>
<script src="/static/loader.js?v=1.47.0"></script>
</body>
</html>

View File

@ -933,6 +933,25 @@ const MAG_REGION_TYPES = [
['page_number', 'Page number'], ['source', 'Source / footer'], ['ad', 'Advertisement'],
['in_picture', 'Text in picture'], ['ocr_noise', 'OCR noise'], ['duplicate', 'Duplicate'], ['table', 'Table'], ['image', 'Image'],
];
// A compact subset of MAG_REGION_TYPES for the review page's colour legend
// -- the full 16-entry list would be noisy here, and several of those kinds
// (source/in_picture/ocr_noise/duplicate) already render as plain grey
// "furniture" on the page itself, so listing them separately would promise
// a colour distinction the boxes don't actually make.
const MAG_LEGEND_TYPES = [
['title', 'Headline'], ['heading', 'Subheading'], ['deck', 'Standfirst'], ['byline', 'Author'],
['body', 'Paragraph'], ['caption', 'Caption'], ['pullquote', 'Pull quote'], ['sidebar', 'Sidenote'],
['ad', 'Advertisement'], ['furniture', 'Page number / footer'],
['image', 'Image'], ['chart', 'Chart'], ['table', 'Table'], ['code', 'Code'],
];
function magReviewLegendHtml() {
return '<p class="mag-review-legend">' +
MAG_LEGEND_TYPES.map(([key, label]) =>
'<span class="mag-preview-legend-item"><span class="mag-preview-swatch mpt-' + key + '"></span>' + label + '</span>'
).join('') + '</p>';
}
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',
@ -1059,8 +1078,9 @@ function magReviewPageColumn(page, wrapId, interactive) {
const isImage = r.kind === 'image';
const on = isImage ? ownImages.has(r.id) : included.has(r.id);
const owner = magBlockOwner(r.id);
const icon = magBlockIcon(isImage ? r.data.type || 'image' : r.data.region_label === 'page_number' ? 'page_number' : r.data.type);
pageHtml += '<div class="mag-review-box' + (on ? '' : ' is-excluded') + (owner ? ' has-owner' : '') + (r.data.type === 'ad' ? ' is-advertisement' : '') +
const typeKey = isImage ? r.data.type || 'image' : r.data.region_label === 'page_number' ? 'page_number' : r.data.type;
const icon = magBlockIcon(typeKey);
pageHtml += '<div class="mag-review-box mpt-' + typeKey + (on ? '' : ' is-excluded') + (owner ? ' has-owner' : '') + (r.data.type === 'ad' ? ' is-advertisement' : '') +
'" data-block="' + esc(r.id) + '" data-kind="' + (isImage ? 'image' : 'text') +
'" style="left:' + left + '%;top:' + top + '%;width:' + w + '%;height:' + h +
'%" onclick="magReviewFocusBlock(\'' + esc(r.id) + '\')" title="' + esc(isImage ? 'figure' : r.data.type) + '">' +
@ -1081,7 +1101,8 @@ function magReviewPageColumn(page, wrapId, interactive) {
let listHtml = '<div class="mag-blocks"' + (interactive
? ' onkeydown="magListKey(event)" onfocusin="magListFocus(event)" aria-describedby="mag-list-keys"' : '') + '>' +
(interactive ? '<p id="mag-list-keys" class="muted mag-list-keys">Keys: ↑/↓ move between regions · Space tick · X select · Enter edit text · R read again · M merge with the next region · Delete delete (Undo appears above)</p>' : '');
(interactive ? '<p id="mag-list-keys" class="muted mag-list-keys">Keys: ↑/↓ move between regions · Space tick · X select · Enter edit text · R read again · M merge with the next region · Delete delete (Undo appears above)</p>' : '') +
(interactive ? magReviewLegendHtml() : '');
regions.forEach((r, i) => {
const isImage = r.kind === 'image';
const owner = magBlockOwner(r.id);
@ -1118,7 +1139,13 @@ function magReviewPageColumn(page, wrapId, interactive) {
magOrderNumber(b.id, i + 1, regions.length, interactive) +
'<input type="checkbox" ' + (on ? 'checked' : '') + ' data-block="' + esc(b.id) + '" onchange="magReviewToggleBox(this)">' +
'<span class="mag-block-type"><span class="mdi ' + icon + '" aria-hidden="true"></span>' + magRegionControls(r, i + 1) + '</span>' +
'<span class="mag-block-text">' +
'<span class="mag-block-text' + (interactive ? ' is-editable' : '') + '"' +
// The whole row is a <label> wrapping the tick checkbox -- a plain
// click anywhere in it toggles that checkbox by default, so a click
// meant for editing must stop that before it fires. Bypasses the
// pencil-icon click magRowActions already offers; this is just a
// faster path to the exact same editor, not a replacement for it.
(interactive ? ' onclick="event.preventDefault();event.stopPropagation();magRowEdit(\'' + b.id + '\')" title="Click to edit"' : '') + '>' +
(owner ? '<span class="mag-block-owner">Article ' + owner.index + ': ' + esc(owner.title) + '</span> ' : '') +
(b.continues_from_previous_page ? '<span class="mag-block-owner">Continued from previous page</span> ' : '') +
esc(b.text.slice(0, 220)) + (b.text.length > 220 ? '…' : '') + '</span>' +

View File

@ -5007,21 +5007,29 @@ input[list="lang-codes"] {
.mag-review-page-wrap { position: relative; border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; background: var(--panel); }
.mag-review-page-wrap img { width: 100%; height: auto; display: block; }
.mag-review-box { position: absolute; border: 2px solid var(--accent); background: rgba(37,99,235,.10);
/* Colour-coded by region type using the same --c custom property and
mpt-<type> classes as the live ingest preview (see .mpt-title etc.
below) -- a headline or byline should be just as easy to spot on an
already-reviewed page as while it's still being detected. State classes
below (.is-excluded, .is-linked) override the type colour, since knowing
a region is unticked or claimed by another article matters more in the
moment than what kind it is. */
.mag-review-box { position: absolute; border: 2px solid var(--c, var(--accent));
background: color-mix(in srgb, var(--c, var(--accent)) 12%, transparent);
cursor: pointer; transition: background .12s, border-color .12s; }
.mag-review-box:hover { background: rgba(37,99,235,.22); }
.mag-review-box:hover { background: color-mix(in srgb, var(--c, var(--accent)) 24%, transparent); }
.mag-review-box.is-excluded { border-color: var(--subtext); background: rgba(120,120,120,.10); }
.mag-review-box.is-excluded:hover { background: rgba(120,120,120,.22); }
.mag-review-box.is-linked { border-color: var(--yellow); background: rgba(217,119,6,.22); z-index: 2; }
.mag-review-box-num { position: absolute; top: -1px; left: -1px; min-width: 16px; padding: 0 3px;
background: var(--accent); color: var(--on-accent); font-size: 10px; font-weight: 700;
background: var(--c, var(--accent)); color: #fff; font-size: 10px; font-weight: 700;
line-height: 16px; text-align: center; border-radius: 0 0 4px 0; }
.mag-review-box.is-excluded .mag-review-box-num { background: var(--subtext); }
/* Centred glyph identifying the region kind (text/figure/furniture) at a
glance -- see magBlockIcon. Sized against the box, not fixed, so it stays
legible on both a full-page figure and a two-line caption. */
.mag-review-box-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
font-size: clamp(12px, 40%, 22px); color: var(--accent); opacity: .55; pointer-events: none; }
font-size: clamp(12px, 40%, 22px); color: var(--c, var(--accent)); opacity: .7; pointer-events: none; }
.mag-review-box.is-excluded .mag-review-box-icon { color: var(--subtext); }
/* A region already claimed by a DIFFERENT article sharing this page --
easy to mistake for stray unclaimed text without this. */
@ -5111,6 +5119,8 @@ input[list="lang-codes"] {
background: var(--mauve); color: #fff; font-size: 10px; font-weight: 700; }
.mag-block-image { cursor: default; grid-template-columns: auto auto max-content 1fr; }
.mag-block-text { font-size: 14px; line-height: 1.45; }
.mag-block-text.is-editable { cursor: text; border-radius: 4px; }
.mag-block-text.is-editable:hover { background: var(--panel); box-shadow: 0 0 0 4px var(--panel); }
/* A 5th grid child in the 4-column .mag-block-image row -- span the whole
row below the thumbnail rather than being squeezed into column 1 alone. */
.mag-describe { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
@ -5291,6 +5301,7 @@ input[list="lang-codes"] {
.mag-preview-legend-item { display: inline-flex; align-items: center; gap: 4px; }
.mag-preview-swatch { width: 10px; height: 10px; border-radius: 2px; background: var(--c); }
.mag-preview-legend-count { margin-left: auto; color: #8a8f98; }
.mag-review-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 12px; color: var(--subtext); margin: 6px 0 10px; }
.mpt-title { --c: #a855f7; } .mpt-heading { --c: #d8b4fe; } .mpt-deck { --c: #06b6d4; } .mpt-byline { --c: #10b981; } .mpt-body { --c: #3b82f6; }
.mpt-caption { --c: #14b8a6; } .mpt-pullquote { --c: #ec4899; } .mpt-sidebar { --c: #f59e0b; } .mpt-ad { --c: #ef4444; }
.mpt-furniture, .mpt-page_number { --c: #9ca3af; }