feat(deadline-banner): auto mode pulls all calendar_items globally
Auto-mode deadline_banner now resolves to the next future event across all calendar_items in the CMS instead of requiring a manually-curated items[] pool. Server load hooks (+page.server.ts for /, /[...slug], /post/[slug]) call resolveDeadlineBannerBlocks which fetches the global calendar_item list once and attaches it as items[] when mode is "auto" and items[] is not already resolved. Component logic unchanged — it still picks the soonest future entry. Also: - cms.ts: getCalendarItems() bulk list fetcher - PostOverviewBlock.svelte: design defaults to "cards" when value is empty string (not just null/undefined) so existing entries with design: "" render Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
getTextFragmentBySlug,
|
||||
getCalendarBySlug,
|
||||
getCalendarItemBySlug,
|
||||
getCalendarItems,
|
||||
} from "./cms";
|
||||
import type { RowContentLayout } from "./block-types";
|
||||
import type { CalendarItemData } from "./block-types";
|
||||
@@ -528,6 +529,60 @@ export async function resolveCalendarBlocks(
|
||||
}
|
||||
}
|
||||
|
||||
function isDeadlineBannerBlock(
|
||||
item: unknown,
|
||||
): item is {
|
||||
_type?: string;
|
||||
mode?: string;
|
||||
items?: unknown[];
|
||||
} {
|
||||
return (
|
||||
typeof item === "object" &&
|
||||
item !== null &&
|
||||
(item as { _type?: string })._type === "deadline_banner"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löst deadline_banner-Blöcke im auto-Modus auf: Lädt alle calendar_items
|
||||
* global und setzt sie als Pool in block.items, sofern dort noch keine
|
||||
* aufgelösten Einträge liegen. Die Komponente wählt daraus den nächsten
|
||||
* zukünftigen Termin.
|
||||
*/
|
||||
export async function resolveDeadlineBannerBlocks(
|
||||
layout: RowContentLayout,
|
||||
): Promise<void> {
|
||||
const rows = [
|
||||
layout.row1Content ?? [],
|
||||
layout.row2Content ?? [],
|
||||
layout.row3Content ?? [],
|
||||
];
|
||||
let pool: CalendarItemData[] | null = null;
|
||||
const loadPool = async (): Promise<CalendarItemData[]> => {
|
||||
if (pool === null) {
|
||||
const items = await getCalendarItems({ locale: "de" });
|
||||
pool = items as unknown as CalendarItemData[];
|
||||
}
|
||||
return pool;
|
||||
};
|
||||
for (const content of rows) {
|
||||
if (!Array.isArray(content)) continue;
|
||||
for (const item of content) {
|
||||
if (!isDeadlineBannerBlock(item)) continue;
|
||||
if (item.mode !== "auto") continue;
|
||||
const existing = item.items ?? [];
|
||||
const first = existing[0];
|
||||
const alreadyResolved =
|
||||
typeof first === "object" &&
|
||||
first !== null &&
|
||||
"terminZeit" in first &&
|
||||
"title" in first;
|
||||
if (alreadyResolved) continue;
|
||||
(item as { items?: CalendarItemData[] }).items = await loadPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isSearchableTextBlock(
|
||||
item: unknown,
|
||||
): item is { _type?: string; textFragments?: unknown[] } {
|
||||
|
||||
Reference in New Issue
Block a user