[feat](trx-frontend-http): add inline audio player to recorder history
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5914,10 +5914,11 @@ function renderRecorderFiles() {
|
|||||||
for (const f of page) {
|
for (const f of page) {
|
||||||
const safeName = escapeMapHtml(f.name);
|
const safeName = escapeMapHtml(f.name);
|
||||||
const encodedName = encodeURIComponent(f.name);
|
const encodedName = encodeURIComponent(f.name);
|
||||||
html += "<tr>"
|
html += '<tr data-name="' + safeName + '">'
|
||||||
+ "<td>" + safeName + "</td>"
|
+ "<td>" + safeName + "</td>"
|
||||||
+ "<td>" + recorderFormatSize(f.size) + "</td>"
|
+ "<td>" + recorderFormatSize(f.size) + "</td>"
|
||||||
+ '<td><div class="rec-file-actions">'
|
+ '<td><div class="rec-file-actions">'
|
||||||
|
+ '<button class="rec-file-btn rec-play-btn" data-name="' + safeName + '" data-url="/api/recorder/download/' + encodedName + '" type="button" aria-expanded="false">Play</button>'
|
||||||
+ '<a class="rec-file-btn" href="/api/recorder/download/' + encodedName + '" download="' + safeName + '">Download</a>'
|
+ '<a class="rec-file-btn" href="/api/recorder/download/' + encodedName + '" download="' + safeName + '">Download</a>'
|
||||||
+ '<button class="rec-file-btn rec-delete-btn" data-name="' + safeName + '" type="button">Remove</button>'
|
+ '<button class="rec-file-btn rec-delete-btn" data-name="' + safeName + '" type="button">Remove</button>'
|
||||||
+ "</div></td></tr>";
|
+ "</div></td></tr>";
|
||||||
@@ -5925,6 +5926,47 @@ function renderRecorderFiles() {
|
|||||||
html += "</tbody></table>";
|
html += "</tbody></table>";
|
||||||
el.innerHTML = html;
|
el.innerHTML = html;
|
||||||
|
|
||||||
|
el.querySelectorAll(".rec-play-btn").forEach(function (btn) {
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
const row = btn.closest("tr");
|
||||||
|
if (!row) return;
|
||||||
|
const next = row.nextElementSibling;
|
||||||
|
if (next && next.classList.contains("rec-player-row")) {
|
||||||
|
const audio = next.querySelector("audio");
|
||||||
|
if (audio) { try { audio.pause(); } catch (_) {} }
|
||||||
|
next.remove();
|
||||||
|
btn.setAttribute("aria-expanded", "false");
|
||||||
|
btn.textContent = "Play";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Close any other open player.
|
||||||
|
el.querySelectorAll(".rec-player-row").forEach(function (r) {
|
||||||
|
const a = r.querySelector("audio");
|
||||||
|
if (a) { try { a.pause(); } catch (_) {} }
|
||||||
|
r.remove();
|
||||||
|
});
|
||||||
|
el.querySelectorAll(".rec-play-btn").forEach(function (b) {
|
||||||
|
b.setAttribute("aria-expanded", "false");
|
||||||
|
b.textContent = "Play";
|
||||||
|
});
|
||||||
|
const playerRow = document.createElement("tr");
|
||||||
|
playerRow.className = "rec-player-row";
|
||||||
|
const cell = document.createElement("td");
|
||||||
|
cell.colSpan = 3;
|
||||||
|
const audio = document.createElement("audio");
|
||||||
|
audio.controls = true;
|
||||||
|
audio.preload = "metadata";
|
||||||
|
audio.src = btn.dataset.url;
|
||||||
|
audio.className = "rec-player-audio";
|
||||||
|
cell.appendChild(audio);
|
||||||
|
playerRow.appendChild(cell);
|
||||||
|
row.parentNode.insertBefore(playerRow, row.nextSibling);
|
||||||
|
btn.setAttribute("aria-expanded", "true");
|
||||||
|
btn.textContent = "Hide";
|
||||||
|
try { audio.play(); } catch (_) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
el.querySelectorAll(".rec-delete-btn").forEach(function (btn) {
|
el.querySelectorAll(".rec-delete-btn").forEach(function (btn) {
|
||||||
btn.addEventListener("click", async function () {
|
btn.addEventListener("click", async function () {
|
||||||
const name = btn.dataset.name;
|
const name = btn.dataset.name;
|
||||||
|
|||||||
@@ -1279,6 +1279,18 @@ small { color: var(--text-muted); }
|
|||||||
.recorder-table .rec-file-btn:active { background: color-mix(in srgb, var(--btn-bg) 55%, var(--accent-green)); border-color: var(--accent-green); box-shadow: none; transform: translateY(1px); }
|
.recorder-table .rec-file-btn:active { background: color-mix(in srgb, var(--btn-bg) 55%, var(--accent-green)); border-color: var(--accent-green); box-shadow: none; transform: translateY(1px); }
|
||||||
.recorder-table .rec-file-btn.rec-delete-btn { color: var(--accent-red); border-color: var(--accent-red); }
|
.recorder-table .rec-file-btn.rec-delete-btn { color: var(--accent-red); border-color: var(--accent-red); }
|
||||||
.recorder-table .rec-file-btn.rec-delete-btn:hover { background: color-mix(in srgb, var(--btn-bg) 75%, var(--accent-red)); border-color: var(--accent-red); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent-red) 18%, transparent); }
|
.recorder-table .rec-file-btn.rec-delete-btn:hover { background: color-mix(in srgb, var(--btn-bg) 75%, var(--accent-red)); border-color: var(--accent-red); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent-red) 18%, transparent); }
|
||||||
|
.recorder-table tr.rec-player-row > td {
|
||||||
|
padding: 0.4rem 0.6rem 0.6rem;
|
||||||
|
background: color-mix(in srgb, var(--btn-bg) 55%, transparent);
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
.recorder-table .rec-player-audio {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 2.1rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
.recorder-page-bar {
|
.recorder-page-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user