feat(youtube): playlist support + URL parsing in youtube_video block
Deploy / verify (push) Successful in 42s
Deploy / deploy (push) Successful in 1m5s

YoutubeVideoBlockData gains an optional `playlistId`. The block now
accepts either a video, a playlist, or both, and either field can be
filled with a raw ID *or* a full youtube.com / youtu.be URL — a
helper extracts the ?v= and ?list= parameters automatically.

Embed routing:
- video only           → /embed/<id>?rel=0
- playlist only        → /embed/videoseries?list=<plid>&rel=0
- video + playlist     → /embed/<id>?list=<plid>&rel=0
- block.params merged  via URLSearchParams

Also tweaks ImageGalleryBlock (grid variant): green padding/contain
fit, darker caption gradient, smaller left-aligned label that expands
on hover. Hides post_overview block when no posts and no intro text
(prevents a bare heading on /mediathek).
This commit is contained in:
Peter Meier
2026-04-25 13:15:11 +02:00
parent 942b9feefa
commit 354d3f09d3
3 changed files with 87 additions and 11 deletions
@@ -176,7 +176,7 @@
<li class="m-0 p-0">
<button
type="button"
class="group relative block w-full aspect-square overflow-hidden rounded-sm bg-stein-100 cursor-zoom-in focus:outline-none focus:ring-2 focus:ring-wald-500"
class="group relative block w-full aspect-square overflow-hidden rounded-sm bg-wald-100 p-2 cursor-zoom-in focus:outline-none focus:ring-2 focus:ring-wald-500"
onclick={() => openModal(i)}
aria-label={label || t(T.image_gallery_open_aria)}
>
@@ -185,15 +185,15 @@
focal={item.focal}
width={400}
aspect="1/1"
fit="cover"
quality={75}
fit="contain"
quality={80}
alt={label}
class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
class="w-full h-full object-contain transition-transform duration-300 group-hover:scale-105"
loading={i < 4 ? "eager" : "lazy"}
/>
{#if label}
<span
class="absolute inset-x-0 bottom-0 px-2 py-1.5 text-xs text-white bg-gradient-to-t from-black/70 via-black/40 to-transparent opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus:opacity-100 line-clamp-2"
class="absolute inset-x-0 bottom-0 max-h-full overflow-y-auto px-2 py-1.5 text-left text-[10px] leading-tight text-white bg-gradient-to-t from-black/95 via-black/80 to-black/30 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus:opacity-100 line-clamp-2 group-hover:line-clamp-none group-focus:line-clamp-none"
>
{label}
</span>