feat(carousel): 2 cols tablet, 3 cols desktop; equal-height cards
- PostOverviewBlock carousel: md:2 cols, lg:3 cols via snap-scroll - PostCard: add class prop for external styling - Carousel cards: h-full for equal height Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,12 +22,14 @@
|
||||
href,
|
||||
tagBase = "/posts/tag",
|
||||
commentCount = null,
|
||||
class: className = "",
|
||||
}: {
|
||||
post: PostWithImage;
|
||||
href: string;
|
||||
tagBase?: string;
|
||||
/** Approved comment count. `null` = unknown/loading, hide badge. `0` = also hide. */
|
||||
commentCount?: number | null;
|
||||
class?: string;
|
||||
} = $props();
|
||||
|
||||
const rawImg = $derived(post._rawImageUrl);
|
||||
@@ -52,7 +54,7 @@
|
||||
<Card
|
||||
{href}
|
||||
layout="post"
|
||||
class={isPastEvent ? "opacity-70 grayscale" : ""}
|
||||
class="{isPastEvent ? 'opacity-70 grayscale' : ''} {className}"
|
||||
>
|
||||
<div class="relative aspect-3/2 w-full overflow-hidden bg-stein-100">
|
||||
{#if rawImg}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { marked } from "$lib/markdown-safe";
|
||||
import PostCard from "../PostCard.svelte";
|
||||
import Carousel from "$lib/components/Carousel.svelte";
|
||||
import Icon from "@iconify/svelte";
|
||||
import "$lib/iconify-offline";
|
||||
import { getBlockLayoutClasses } from "$lib/block-layout";
|
||||
import type { PostOverviewBlockData } from "$lib/block-types";
|
||||
import type { PostEntry } from "$lib/cms";
|
||||
@@ -21,6 +22,13 @@
|
||||
const posts = $derived((block.postsResolved ?? []) as (PostEntry & { _resolvedImageUrl?: string })[]);
|
||||
const design = $derived(block.design || "cards");
|
||||
const tagBase = "/posts/tag";
|
||||
|
||||
let scroller: HTMLDivElement | undefined = $state();
|
||||
function scrollByPage(dir: 1 | -1) {
|
||||
if (!scroller) return;
|
||||
scroller.scrollBy({ left: scroller.clientWidth * dir * 0.9, behavior: "smooth" });
|
||||
}
|
||||
|
||||
// Hide the entire block (headline, intro, footer link) when there are no
|
||||
// posts and no intro text — otherwise an empty section with just a heading
|
||||
// sits on the page.
|
||||
@@ -74,16 +82,42 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else if design === "carousel" && posts.length > 0}
|
||||
<Carousel count={posts.length} ariaLabel={block.headline ?? "Beiträge"}>
|
||||
{#snippet item(i)}
|
||||
<PostCard
|
||||
post={posts[i]}
|
||||
href={postHref(posts[i])}
|
||||
tagBase={tagBase}
|
||||
commentCount={commentCounts[postSlugForComments(posts[i])] ?? null}
|
||||
/>
|
||||
{/snippet}
|
||||
</Carousel>
|
||||
<div class="relative">
|
||||
<div
|
||||
bind:this={scroller}
|
||||
class="flex gap-4 overflow-x-auto scroll-smooth snap-x snap-mandatory pb-2 [scrollbar-width:thin]"
|
||||
>
|
||||
{#each posts as post}
|
||||
<div class="shrink-0 snap-start flex flex-col w-full md:w-[calc((100%-1rem)/2)] lg:w-[calc((100%-2rem)/3)]">
|
||||
<PostCard
|
||||
post={post}
|
||||
href={postHref(post)}
|
||||
tagBase={tagBase}
|
||||
commentCount={commentCounts[postSlugForComments(post)] ?? null}
|
||||
class="h-full"
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if posts.length > 1}
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => scrollByPage(-1)}
|
||||
aria-label="Zurück"
|
||||
class="hidden md:flex absolute -left-3 top-1/2 -translate-y-1/2 -translate-x-1/2 size-7 items-center justify-center rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
|
||||
>
|
||||
<Icon icon="mdi:chevron-left" class="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => scrollByPage(1)}
|
||||
aria-label="Weiter"
|
||||
class="hidden md:flex absolute -right-3 top-1/2 -translate-y-1/2 translate-x-1/2 size-7 items-center justify-center rounded-full bg-white/90 border border-stein-200 shadow-sm hover:bg-white hover:border-wald-700 transition"
|
||||
>
|
||||
<Icon icon="mdi:chevron-right" class="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if posts.length > 0}
|
||||
|
||||
Reference in New Issue
Block a user