Animate episode thumbnails on hover

This commit is contained in:
Dymas
2026-09-15 16:25:18 +02:00
parent 2597aeaf1d
commit b19eb7b958
7 changed files with 98 additions and 20 deletions
+28 -2
View File
@@ -130,7 +130,6 @@ function renderDetails(title) {
<button id="editMetaBtn" type="button">Edit</button>
<button id="fetchMetadataBtn" type="button">Metadata</button>
<button id="makeThumbBtn" type="button">Thumbnail</button>
<button id="playAllBtn" class="primary" type="button">Play all</button>
</div>
</div>
<div id="metaView" class="meta-view">
@@ -142,6 +141,9 @@ function renderDetails(title) {
<div id="metaEditMount"></div>
</div>
</div>
<div class="episode-toolbar">
<button id="playAllBtn" class="primary" type="button">Play all</button>
</div>
<div class="seasons">
${title.seasons.map(renderSeason).join("")}
</div>
@@ -236,7 +238,14 @@ function renderSeason(season) {
${season.videos.map((video) => `
<button class="episode" type="button" data-video-id="${escapeAttr(video.id)}">
<span class="episode__thumb">
<img src="${escapeAttr(video.thumbnail)}" alt="" loading="lazy" onerror="this.hidden=true">
<img
src="${escapeAttr(video.thumbnail)}"
data-still="${escapeAttr(video.thumbnail)}"
data-animated="${escapeAttr(video.animatedThumbnail)}"
alt=""
loading="lazy"
onerror="this.hidden=true"
>
<span class="episode__play">Play</span>
</span>
<span class="episode__name">${escapeHtml(video.name)}</span>
@@ -255,6 +264,23 @@ function flattenVideos(title) {
function wireEpisodeCards(title) {
const videos = flattenVideos(title);
document.querySelectorAll("[data-video-id]").forEach((node) => {
const image = node.querySelector("img");
const showAnimated = () => {
if (image?.dataset.animated && image.src !== new URL(image.dataset.animated, window.location.href).href) {
image.hidden = false;
image.src = image.dataset.animated;
}
};
const showStill = () => {
if (image?.dataset.still && image.src !== new URL(image.dataset.still, window.location.href).href) {
image.hidden = false;
image.src = image.dataset.still;
}
};
node.addEventListener("mouseenter", showAnimated);
node.addEventListener("focus", showAnimated);
node.addEventListener("mouseleave", showStill);
node.addEventListener("blur", showStill);
node.addEventListener("click", () => {
const index = videos.findIndex((video) => video.id === node.dataset.videoId);
startPlaylist(videos, Math.max(index, 0));
+21 -5
View File
@@ -483,6 +483,12 @@ label {
.seasons {
display: grid;
gap: 1rem;
margin-top: 1rem;
}
.episode-toolbar {
display: flex;
justify-content: flex-start;
margin-top: 1.5rem;
}
@@ -502,16 +508,16 @@ label {
.episodes {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 12px;
gap: 8px;
}
.episode {
display: grid;
gap: 10px;
align-items: start;
grid-template-columns: 168px minmax(0, 1fr);
gap: 14px;
align-items: center;
min-height: auto;
padding: 12px;
padding: 10px;
text-align: left;
box-shadow: none;
}
@@ -555,11 +561,13 @@ label {
.episode__name {
color: var(--text);
font-weight: 800;
align-self: end;
}
.episode__meta {
color: var(--muted);
font-size: 13px;
align-self: start;
}
.episode__name,
@@ -624,6 +632,10 @@ label {
align-items: flex-start;
flex-direction: column;
}
.episode {
grid-template-columns: 132px minmax(0, 1fr);
}
}
@media (max-width: 560px) {
@@ -649,4 +661,8 @@ label {
.collection-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.episode {
grid-template-columns: 1fr;
}
}