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) {