diff --git a/CHANGELOG.md b/CHANGELOG.md index 8061133..75b8f79 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.26.10] — 2026-09-10 + +### Fixed +- **Instant Dropzone Upload & Active Progress Card.** Dropping a PDF (or picking a file) now automatically initiates upload and ingestion immediately. The dropzone transforms into an active progress card with a spinning loader, animated progress bar, status note (`Uploading "filename.pdf" (X MB)`), and disabled input controls so users get un-missable, immediate feedback. + +--- + ## [1.26.9] — 2026-09-10 ### Fixed @@ -3905,7 +3912,8 @@ Initial feature-complete release. --- -[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.26.9...HEAD +[Unreleased]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.26.10...HEAD +[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 [1.26.1]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.26.0...v1.26.1 [1.26.0]: https://github.com/mARTin-B78/tts-voice-creator-clone-and-design-2/compare/v1.25.3...v1.26.0 diff --git a/VERSION b/VERSION index 3cd33cd..63d92c7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.26.9 +1.26.10 diff --git a/static/css/audiobook.css b/static/css/audiobook.css index 797e122..cddf5da 100644 --- a/static/css/audiobook.css +++ b/static/css/audiobook.css @@ -352,6 +352,47 @@ .reader-extract-info p { margin: 2px 0 0; color: var(--subtext); font-size: 12.5px; } .reader-dropzone.dragover { border-color: var(--accent); background: rgba(37,99,235,.06); color: var(--accent); } .reader-dropzone.dragover .reader-dropzone-icon { opacity: 1; } +.reader-dropzone.is-selected { + border-style: solid; + border-color: var(--accent); + background: rgba(37, 99, 235, 0.04); +} +.reader-dropzone.is-selected .reader-dropzone-icon { + opacity: 1; + color: var(--accent); +} +.reader-dropzone.is-uploading { + border-style: solid; + border-color: var(--accent); + background: rgba(37, 99, 235, 0.08); + box-shadow: 0 0 16px rgba(37, 99, 235, 0.2); + padding: 26px 16px; +} +.reader-dropzone.is-uploading .reader-dropzone-icon { + opacity: 1; + color: var(--accent); +} +.mag-dropzone-progress { + width: 100%; + max-width: 420px; + height: 6px; + background: rgba(37, 99, 235, 0.2); + border-radius: 999px; + overflow: hidden; + margin-top: 8px; +} +.mag-dropzone-progress-bar { + height: 100%; + width: 40%; + background: var(--accent); + border-radius: 999px; + animation: magIndeterminateProgress 1.4s infinite ease-in-out; +} +@keyframes magIndeterminateProgress { + 0% { transform: translateX(-100%); width: 30%; } + 50% { transform: translateX(100%); width: 50%; } + 100% { transform: translateX(300%); width: 30%; } +} #s-reader .reader-file-pick { margin-top: 4px; cursor: pointer; diff --git a/static/index.html b/static/index.html index 7464c9b..489d706 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 382f8ab..b499eab 100644 --- a/static/js/magazine.js +++ b/static/js/magazine.js @@ -189,11 +189,13 @@ function magShowDroppedFile(file) { const titleEl = $('mag-dropzone-title'); const iconEl = $('mag-dropzone-icon'); const titleInput = $('mag-new-title'); + const dropzone = $('mag-dropzone'); if (file) { const sizeMb = (file.size / (1024 * 1024)).toFixed(1); + if (dropzone) dropzone.classList.add('is-selected'); if (noteEl) noteEl.textContent = `Selected: ${file.name} (${sizeMb} MB)`; - if (titleEl) titleEl.textContent = 'PDF file selected'; + if (titleEl) titleEl.textContent = 'PDF file selected — uploading...'; if (iconEl) iconEl.className = 'mdi mdi-file-check-outline reader-dropzone-icon'; // Auto-fill title from filename if title input is empty @@ -201,6 +203,7 @@ function magShowDroppedFile(file) { titleInput.value = magFormatFilenameAsTitle(file.name); } } else { + if (dropzone) dropzone.classList.remove('is-selected', 'is-uploading'); if (noteEl) noteEl.textContent = MAG_DROPZONE_DEFAULT_NOTE; if (titleEl) titleEl.textContent = 'Drop a PDF or click to browse'; if (iconEl) iconEl.className = 'mdi mdi-cloud-upload-outline reader-dropzone-icon'; @@ -257,8 +260,15 @@ function setupMagDropzone() { dt.items.add(file); input.files = dt.files; magShowDroppedFile(file); + magCreate(); + }); + input.addEventListener('change', () => { + const file = input.files?.[0]; + if (file) { + magShowDroppedFile(file); + magCreate(); + } }); - input.addEventListener('change', () => magShowDroppedFile(input.files?.[0])); } async function magCreate() { @@ -276,29 +286,57 @@ async function magCreate() { const dropzone = $('mag-dropzone'); const titleInp = $('mag-new-title'); const issueInp = $('mag-new-issue'); + const progress = $('mag-dropzone-progress'); + const pickBtn = $('mag-dropzone-pick-btn'); + const titleEl = $('mag-dropzone-title'); + const noteEl = $('mag-dropzone-note'); + const iconEl = $('mag-dropzone-icon'); const origBtnText = addBtn ? addBtn.innerHTML : ''; const setUploadingState = (uploading) => { - if (addBtn) { - addBtn.disabled = uploading; - addBtn.innerHTML = uploading - ? ' Uploading PDF...' - : origBtnText; + const sizeMb = file ? (file.size / (1024 * 1024)).toFixed(1) : 0; + if (uploading) { + if (dropzone) { + dropzone.classList.add('is-uploading'); + dropzone.style.pointerEvents = 'none'; + } + if (progress) progress.hidden = false; + if (pickBtn) pickBtn.hidden = true; + if (iconEl) iconEl.className = 'mdi mdi-loading mdi-spin reader-dropzone-icon'; + if (titleEl) titleEl.textContent = 'Uploading & Ingesting PDF...'; + if (noteEl) noteEl.textContent = `Processing "${file.name}" (${sizeMb} MB). Transferring source file and extracting layout...`; + if (addBtn) { + addBtn.disabled = true; + addBtn.innerHTML = ' Uploading PDF...'; + } + if (titleInp) titleInp.disabled = true; + if (issueInp) issueInp.disabled = true; + } else { + if (dropzone) { + dropzone.classList.remove('is-uploading'); + dropzone.style.pointerEvents = 'auto'; + } + if (progress) progress.hidden = true; + if (pickBtn) pickBtn.hidden = false; + if (addBtn) { + addBtn.disabled = false; + addBtn.innerHTML = origBtnText; + } + if (titleInp) titleInp.disabled = false; + if (issueInp) issueInp.disabled = false; } - if (titleInp) titleInp.disabled = uploading; - if (issueInp) issueInp.disabled = uploading; - if (dropzone) dropzone.style.pointerEvents = uploading ? 'none' : 'auto'; }; try { setUploadingState(true); + say(`Uploading ${file.name} (${(file.size / (1024 * 1024)).toFixed(1)} MB)...`, 'ok'); const { id } = await api('/api/magazine/docs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, issue }), }); await api('/api/reader/docs/' + id + '/source?ext=pdf', { method: 'PUT', body: file }); - say('Magazine added — starting ingestion', 'ok'); + say('Magazine uploaded — starting ingestion', 'ok'); if ($('mag-new-title')) $('mag-new-title').value = ''; if ($('mag-new-issue')) $('mag-new-issue').value = ''; diff --git a/static/sections/s-magazine.html b/static/sections/s-magazine.html index d8aaaef..21e0cfb 100644 --- a/static/sections/s-magazine.html +++ b/static/sections/s-magazine.html @@ -22,7 +22,10 @@ Drop a PDF or click to browse Scanned issues work too — pages without selectable text are read with OCR. -