diff --git a/css/style.css b/css/style.css index bd9cdd74..208e5552 100644 --- a/css/style.css +++ b/css/style.css @@ -74,44 +74,6 @@ header img { box-shadow: var(--shadow-md); } -.video-card .stream-health { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 2rem; - font-size: 1.1rem; - line-height: 1; - transition: transform 150ms ease, filter 150ms ease, opacity 150ms ease; -} - -.video-card .stream-health[data-stream-health-state="good"] { - filter: drop-shadow(0 0 6px rgba(34, 197, 94, 0.45)); -} - -.video-card .stream-health[data-stream-health-state="none"] { - opacity: 0.85; -} - -.video-card .stream-health[data-stream-health-state="noresp"], -.video-card .stream-health[data-stream-health-state="unknown"] { - opacity: 0.6; -} - -.video-card .stream-health[data-stream-health-state="checking"] { - animation: stream-health-pulse 1.2s ease-in-out infinite alternate; -} - -@keyframes stream-health-pulse { - from { - transform: scale(0.95); - opacity: 0.65; - } - to { - transform: scale(1.05); - opacity: 1; - } -} - .video-card--enter { opacity: 0; animation: video-card-fade-in 220ms ease-out forwards; diff --git a/js/app.js b/js/app.js index 552b9c3b..ffbe72ba 100644 --- a/js/app.js +++ b/js/app.js @@ -2167,34 +2167,31 @@ class bitvidApp { const includeMargin = options?.includeMargin !== false; const classes = [ "torrent-health-badge", - "inline-flex", - "items-center", - "gap-2", + "text-xs", + "font-semibold", "px-2", "py-1", "rounded", + "inline-flex", + "items-center", + "gap-1", "bg-gray-800", "text-gray-300", - "text-xs", - "font-semibold", + "transition-colors", + "duration-200", ]; if (includeMargin) { classes.unshift("mt-3"); } return ` -
- - 🟦 - - - WebTorrent - +
+ ⏳ Torrent
`; } diff --git a/js/gridHealth.js b/js/gridHealth.js index c05ba294..be1f976d 100644 --- a/js/gridHealth.js +++ b/js/gridHealth.js @@ -54,46 +54,82 @@ function toVisual(health) { return "noresp"; } -function formatCount(health) { - if (!health || !Number.isFinite(health.seeders) || health.seeders <= 0) { - return ""; - } - return ` (${health.seeders})`; -} - function setBadge(card, visual, health) { - const el = card.querySelector(".stream-health"); - if (!el) { + const badge = card.querySelector(".torrent-health-badge"); + if (!badge) { return; } + const hadMargin = badge.classList.contains("mt-3"); + + const baseClasses = [ + "torrent-health-badge", + "text-xs", + "font-semibold", + "px-2", + "py-1", + "rounded", + "inline-flex", + "items-center", + "gap-1", + "transition-colors", + "duration-200", + ]; + if (hadMargin) { + baseClasses.unshift("mt-3"); + } + badge.className = baseClasses.join(" "); + const map = { good: { - text: "🟢", - aria: "Streamable: seeders available", + icon: "✅", + aria: "WebTorrent fallback ready", + classes: ["bg-green-900", "text-green-200"], + role: "status", }, none: { - text: "🟡", + icon: "⚠️", aria: "No seeders reported by trackers", + classes: ["bg-amber-900", "text-amber-200"], + role: "status", }, noresp: { - text: "⚫", + icon: "❌", aria: "No tracker response", + classes: ["bg-red-900", "text-red-200"], + role: "alert", }, checking: { - text: "🟦", - aria: "Checking stream availability", + icon: "⏳", + aria: "Checking Torrent availability", + classes: ["bg-gray-800", "text-gray-300"], + role: "status", }, unknown: { - text: "⚪", - aria: "Unknown stream availability", + icon: "⚠️", + aria: "Torrent availability unknown", + classes: ["bg-amber-900", "text-amber-200"], + role: "status", }, }; + const entry = map[visual] || map.unknown; - const countText = formatCount(health); - el.textContent = `${entry.text}${countText}`; - el.setAttribute("aria-label", countText ? `${entry.aria}${countText}` : entry.aria); - el.setAttribute("title", countText ? `${entry.aria}${countText}` : entry.aria); - el.dataset.streamHealthState = visual; + entry.classes.forEach((cls) => badge.classList.add(cls)); + + const seederCount = + health && Number.isFinite(health.seeders) && health.seeders > 0 + ? health.seeders + : null; + const countText = seederCount ? ` (${seederCount})` : ""; + const ariaCount = seederCount ? ` with ${seederCount} seeders` : ""; + + const iconPrefix = entry.icon ? `${entry.icon} ` : ""; + badge.textContent = `${iconPrefix}Torrent${countText}`; + const ariaLabel = `${entry.aria}${ariaCount}`; + badge.setAttribute("aria-label", ariaLabel); + badge.setAttribute("title", ariaLabel); + badge.setAttribute("aria-live", "polite"); + badge.setAttribute("role", entry.role); + badge.dataset.streamHealthState = visual; } function applyHealth(card, health) {