diff --git a/BACKLOG.md b/BACKLOG.md
index 5c58653..09d68f7 100644
--- a/BACKLOG.md
+++ b/BACKLOG.md
@@ -20,7 +20,7 @@ bottom as they come up.
- [x] Keyboard-shortcut help overlay (press `?`), listing space / arrows / f / m.
- [x] Download/preload progress indicator on cards (percent or a bar, not just a pulse).
- [x] Remember and restore the last playback position per video.
-- [ ] Toast queue (stack multiple toasts instead of replacing).
+- [x] Toast queue (stack multiple toasts instead of replacing).
## Features
- [ ] Drag-to-reorder videos within a playlist.
diff --git a/frontend/app.js b/frontend/app.js
index 1baa0e6..7e042c1 100644
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -109,12 +109,29 @@ function fmtTime(sec) {
const mm = h ? String(m).padStart(2, '0') : String(m);
return (h ? h + ':' : '') + mm + ':' + String(s).padStart(2, '0');
}
-function toast(msg) {
- const t = $('toast');
+function toast(msg, { duration = 2200 } = {}) {
+ const t = document.createElement('div');
+ t.className = 'toast';
t.textContent = msg;
- t.classList.remove('hidden');
- clearTimeout(toast._t);
- toast._t = setTimeout(() => t.classList.add('hidden'), 2200);
+ const container = $('toastContainer');
+ container.appendChild(t);
+ // Trigger layout for animation
+ t.style.animation = 'none';
+ t.offsetHeight; // force reflow
+ t.style.animation = '';
+
+ // Auto-remove after duration
+ setTimeout(() => {
+ t.classList.add('toast-exit');
+ setTimeout(() => t.remove(), 280);
+ }, duration);
+
+ // Cap at 3 toasts — remove oldest
+ while (container.children.length > 3) {
+ const first = container.firstChild;
+ first.classList.add('toast-exit');
+ setTimeout(() => first.remove(), 280);
+ }
}
function uid() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 7); }
function fmtBytes(n) {
diff --git a/frontend/index.html b/frontend/index.html
index 20a8b5a..d047b80 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -162,7 +162,7 @@
-
+
diff --git a/frontend/styles.css b/frontend/styles.css
index 2426a50..802d60f 100644
--- a/frontend/styles.css
+++ b/frontend/styles.css
@@ -922,19 +922,42 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
.btn.danger:hover { background: rgba(255,75,50,0.12); }
/* ===================== Toast ===================== */
+.toast-container {
+ position: fixed;
+ bottom: 26px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 200;
+ display: flex;
+ flex-direction: column-reverse;
+ align-items: center;
+ gap: 8px;
+ pointer-events: none;
+}
.toast {
- position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%);
background: var(--bg-3);
border: 1px solid var(--line);
color: var(--text);
padding: 13px 20px;
border-radius: 11px;
box-shadow: var(--shadow);
- z-index: 200;
- font-size: 13.5px; font-weight: 500;
+ font-size: 13.5px;
+ font-weight: 500;
+ white-space: nowrap;
animation: toastIn 0.3s var(--ease);
+ pointer-events: auto;
+}
+@keyframes toastIn {
+ from { opacity: 0; transform: translateY(12px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+.toast-exit {
+ animation: toastOut 0.25s var(--ease) forwards;
+}
+@keyframes toastOut {
+ from { opacity: 1; transform: translateY(0); }
+ to { opacity: 0; transform: translateY(-8px); }
}
-@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translate(-50%, 0); } }
/* ===================== Keyboard shortcut overlay ===================== */
.shortcut-overlay {
diff --git a/releases/YT Player_1.0.0_x64-setup.exe b/releases/YT Player_1.0.0_x64-setup.exe
index 8342eb3..efa4f3d 100755
Binary files a/releases/YT Player_1.0.0_x64-setup.exe and b/releases/YT Player_1.0.0_x64-setup.exe differ
diff --git a/releases/YT Player_1.0.0_x64_en-US.msi b/releases/YT Player_1.0.0_x64_en-US.msi
index bd549cb..78bfa3c 100755
Binary files a/releases/YT Player_1.0.0_x64_en-US.msi and b/releases/YT Player_1.0.0_x64_en-US.msi differ
diff --git a/releases/ytplayer.exe b/releases/ytplayer.exe
index 0ce7116..6ed967c 100644
Binary files a/releases/ytplayer.exe and b/releases/ytplayer.exe differ