From 275f66fb8f2f24173ec1f2677c821352fbd232b6 Mon Sep 17 00:00:00 2001 From: Peter Meier Date: Sun, 12 Jul 2026 23:12:44 +0200 Subject: [PATCH] =?UTF-8?q?CalendarBlock:=20ruhigere,=20editorialere=20UI-?= =?UTF-8?q?=C3=9Cberarbeitung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Kopfleiste zusammengefasst: Suche-Pill + Themenfilter-Icon + Heute-Chip - Monats-Grid neutralisiert: weisser Grund, Punkt-Marker statt Zahl-Badge - Terminliste als Karten statt Zebra-Rows; Urgency in getönte Datums-Kachel - Aktionsleiste ans Card-Ende verschoben, ruhige Text+Icon-Links Enthält zusätzlich bestehende lokale Änderungen (Card, Header, ContactCard, InfoCard, PostCardCompact, FilesBlock, app.css, Storybook-Fixtures). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app.css | 5 + src/lib/components/Card.svelte | 2 +- src/lib/components/ContactCard.svelte | 2 +- src/lib/components/Header.svelte | 12 +- src/lib/components/InfoCard.svelte | 4 +- src/lib/components/PostCardCompact.svelte | 2 +- .../blocks/CalendarBlock.stories.ts | 6 +- .../components/blocks/CalendarBlock.svelte | 429 ++++++++---------- .../blocks/CalendarCompactBlock.stories.ts | 3 + .../components/blocks/FilesBlock.stories.ts | 5 + src/lib/components/blocks/FilesBlock.svelte | 83 +--- 11 files changed, 242 insertions(+), 311 deletions(-) diff --git a/src/app.css b/src/app.css index 16cf153..51715fe 100644 --- a/src/app.css +++ b/src/app.css @@ -20,6 +20,11 @@ @apply rounded-lg border border-stein-200 bg-white shadow-sm; } + /* Shared card hover: lift + shadow + wald border, used by all clickable card/tile/list-row components */ + .card-hover-lift { + @apply transition-[transform,box-shadow,border-color] duration-200 hover:-translate-y-0.5 hover:border-wald-300 hover:shadow-md; + } + /* Diagonal strikethrough for past calendar days */ .day-past::after { content: ''; diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte index 707aef3..9d0310d 100644 --- a/src/lib/components/Card.svelte +++ b/src/lib/components/Card.svelte @@ -44,7 +44,7 @@ variants: { variant: { callout: "cursor-pointer transition-colors no-underline text-inherit hover:bg-wald-100", - tile: "transition-[transform,box-shadow,border-color] duration-200 no-underline hover:-translate-y-0.5 hover:shadow-md hover:border-wald-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wald-500 focus-visible:ring-offset-2", + tile: "card-hover-lift no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wald-500 focus-visible:ring-offset-2", }, }, defaultVariants: { variant: "tile" }, diff --git a/src/lib/components/ContactCard.svelte b/src/lib/components/ContactCard.svelte index 2cbc5b2..ec4fb83 100644 --- a/src/lib/components/ContactCard.svelte +++ b/src/lib/components/ContactCard.svelte @@ -16,7 +16,7 @@

{contact.name ?? ""}

diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte index f0c3ba0..fd5e917 100644 --- a/src/lib/components/Header.svelte +++ b/src/lib/components/Header.svelte @@ -145,26 +145,26 @@ {#each links as link} {@const active = isActiveTree(link, $page.url.pathname)} {#if link.children && link.children.length > 0} -
+
{#if link.href && link.href !== "#"} {:else} {/if}
{link.label} diff --git a/src/lib/components/InfoCard.svelte b/src/lib/components/InfoCard.svelte index cddbba2..23b3044 100644 --- a/src/lib/components/InfoCard.svelte +++ b/src/lib/components/InfoCard.svelte @@ -63,9 +63,9 @@ tone === "green" ? "border-wald-100 bg-wald-50" : "border-stein-200 bg-white" }`, ); - /* Klickbare Karte: Tile-Hover identisch zu Card.svelte (variant=tile). */ + /* Klickbare Karte: Tile-Hover identisch zu Card.svelte (variant=tile), s. card-hover-lift in app.css. */ const linkCls = - "transition-[transform,box-shadow,border-color] duration-200 no-underline text-inherit hover:-translate-y-0.5 hover:shadow-md hover:border-wald-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wald-500 focus-visible:ring-offset-2"; + "card-hover-lift no-underline text-inherit focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wald-500 focus-visible:ring-offset-2"; {#snippet iconBadge(sizeClass: string, iconSize: string)} diff --git a/src/lib/components/PostCardCompact.svelte b/src/lib/components/PostCardCompact.svelte index 22f976e..a24627b 100644 --- a/src/lib/components/PostCardCompact.svelte +++ b/src/lib/components/PostCardCompact.svelte @@ -38,7 +38,7 @@
{#if rawImg} diff --git a/src/lib/components/blocks/CalendarBlock.stories.ts b/src/lib/components/blocks/CalendarBlock.stories.ts index 6af7dbb..35fec59 100644 --- a/src/lib/components/blocks/CalendarBlock.stories.ts +++ b/src/lib/components/blocks/CalendarBlock.stories.ts @@ -1,5 +1,9 @@ import type { Meta, StoryObj } from '@storybook/sveltekit'; import CalendarBlock from './CalendarBlock.svelte'; +// CalendarBlock liest Übersetzungen über die `translations`-Prop (nicht den +// Context/WithTranslations-Decorator) → Fixture explizit reinreichen, sonst +// rohe Keys (calendar_weekday_mo, calendar_all_upcoming, …). +import translations from './_fixtures/translations.json'; const meta = { title: 'CMS-Blocks/Calendar', @@ -39,5 +43,5 @@ const items = [ ]; export const Standard: Story = { - args: { block: { title: 'Termine', variant: 'default', fromPost: false, items } }, + args: { block: { title: 'Termine', variant: 'default', fromPost: false, items }, translations }, }; diff --git a/src/lib/components/blocks/CalendarBlock.svelte b/src/lib/components/blocks/CalendarBlock.svelte index 96f74e9..0cb6b4b 100644 --- a/src/lib/components/blocks/CalendarBlock.svelte +++ b/src/lib/components/blocks/CalendarBlock.svelte @@ -21,7 +21,6 @@ import ImageModal from "$lib/components/ImageModal.svelte"; import SocialImageModal from "$lib/components/SocialImageModal.svelte"; import QrModal from "$lib/components/QrModal.svelte"; - import EventDateBox from "./EventDateBox.svelte"; type EventCardItem = CalendarItemData & { start: Date; @@ -56,6 +55,8 @@ let search = $state(""); let currentMonth = $state(new Date()); let selectedDay = $state(null); + /** Themenfilter-Popover unter der Kopfleiste (Icon-Button toggelt). */ + let tagFilterOpen = $state(false); function parseDate(iso: string | undefined | null): Date | null { if (!iso) return null; @@ -289,6 +290,12 @@ month: "short", }); } + /** Kurzer Wochentag ohne Punkt für die Datums-Kachel der Karte. */ + function fmtWd(d: Date): string { + return d + .toLocaleDateString("de-DE", { weekday: "short" }) + .replace(/\.$/, ""); + } function fmtGroupHeader(d: Date): string { return d.toLocaleDateString("de-DE", { weekday: "long", @@ -412,6 +419,20 @@ return "later"; } + /** Getönte Datums-Kachel je Urgency (ersetzt den früheren farbigen + * Left-Border-Strich der Event-Rows). */ + function urgencyTile(u: Urgency): string { + return ( + { + now: "bg-fire-50 text-fire-700", + today: "bg-fire-50 text-fire-600", + tomorrow: "bg-erde-50 text-erde-700", + week: "bg-himmel-50 text-himmel-700", + later: "bg-stein-100 text-stein-600", + }[u] ?? "bg-stein-100 text-stein-600" + ); + } + function toICS(ev: EventCardItem): CalendarItemICS { return { title: ev.title || t(T.calendar_untitled), @@ -634,40 +655,58 @@ locText || item.isMultiDay )} -
  • +
  • - - -
    -
    + +
    + + {#if item.isMultiDay && item.end}{fmtWd( + item.start, + )}–{fmtWd(item.end)}{:else}{fmtWd( + item.start, + )}{/if} + + + {#if item.isMultiDay && item.end}{item.start.getDate()}–{item.end.getDate()}{:else}{item.start.getDate()}{/if} + +
    +
    +
    {title} {#if live} - + {live} + {:else if relativeDays(item.start)} + + {relativeDays(item.start)} + {/if}
    {#if item.timeStr && !item.isMultiDay} {locText} {/if} - {#if item.tags && item.tags.length > 0} - {#each item.tags.slice(0, 2) as tg} - {tg} - {/each} - {#if item.tags.length > 2} - +{item.tags.length - 2} - {/if} - {/if}
    @@ -959,154 +988,98 @@ {/if} - -
    + +
    + {#if allTags.length > 0} + + {/if}
    - {#if allTags.length > 0} - -
    - 0 && tagFilterOpen} + +
    +
    -
    + {t(T.calendar_all_tags)} + + {#each allTags as tag} - {#each allTags as tag} - - {/each} -
    -
    - {/if} - - - {#if feedHost} -
    - - {#if isApplePlatform} - - {:else} - - {/if} - {#if items.length > 0} - - {/if} + {/each}
    {/if} -
    +
    {monthLabel}
    -
    - {#each weekdays as w, i} +
    + {#each weekdays as w}
    {w}
    {/each} +
    +
    {#if modalImage} @@ -1436,10 +1437,6 @@ transparent ); } - /* Event-Rows visuell trennen: Card-Optik mit Urgency-Akzent links, - Zebra-Stripe ab dem zweiten Eintrag, deutlicher Separator - zwischen Tagesgruppen. So lassen sich Termine optisch klar - auseinanderhalten ohne komplette Kacheloptik. */ /* iOS Safari zeigt trotz list-style:none noch den Disclosure-Marker (dunkler Punkt oben-links der Kachel) → explizit ausblenden. */ .calendar-block summary { @@ -1448,59 +1445,27 @@ .calendar-block summary::-webkit-details-marker { display: none; } - .calendar-block .event-item { - position: relative; + /* Event-Karten: eigenständige gerundete Karten mit Abstand statt + Zebra + Left-Border. Urgency wandert in die getönte Datums-Kachel + (urgencyTile), hier nur ruhige Card-Kante + Hover. */ + .calendar-block .event-card { list-style: none; - border-left: 4px solid transparent; + margin: 8px 12px; + border: 1px solid var(--color-stein-200, #e0dcd5); + border-radius: 10px; background: var(--color-stein-0, #fff); - transition: background-color 150ms ease; + transition: + border-color 150ms ease, + box-shadow 150ms ease; } /* iOS/WebKit zeigt sonst den
  • -Disc-Marker (dunkler Punkt links der Kachel) — list-none am