/** * Layout für Content-Blöcke (z. B. Markdown): Grid-Spalten (1–12) und Abstand. * Entspricht component_layout im CMS (desktop/tablet/mobile = Breite in 12tel, spaceBottom = rem). */ export type BlockLayout = { /** Breite auf Desktop (1–12), z. B. "8" = 8/12. */ desktop?: | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; /** Breite auf Tablet (1–12). */ tablet?: | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; /** Breite auf Mobile (1–12), Default 12. */ mobile?: | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; /** Abstand nach unten (rem): 0, 0.5, 1, 1.5, 2. */ spaceBottom?: 0 | 0.5 | 1 | 1.5 | 2; /** true = Block fullwidth aus dem Grid ausbrechen (viewport-breit). */ breakout?: boolean; }; const COL_SPAN: Record = { "1": "col-span-1", "2": "col-span-2", "3": "col-span-3", "4": "col-span-4", "5": "col-span-5", "6": "col-span-6", "7": "col-span-7", "8": "col-span-8", "9": "col-span-9", "10": "col-span-10", "11": "col-span-11", "12": "col-span-12", }; const MD_COL_SPAN: Record = { "1": "md:col-span-1", "2": "md:col-span-2", "3": "md:col-span-3", "4": "md:col-span-4", "5": "md:col-span-5", "6": "md:col-span-6", "7": "md:col-span-7", "8": "md:col-span-8", "9": "md:col-span-9", "10": "md:col-span-10", "11": "md:col-span-11", "12": "md:col-span-12", }; const LG_COL_SPAN: Record = { "1": "lg:col-span-1", "2": "lg:col-span-2", "3": "lg:col-span-3", "4": "lg:col-span-4", "5": "lg:col-span-5", "6": "lg:col-span-6", "7": "lg:col-span-7", "8": "lg:col-span-8", "9": "lg:col-span-9", "10": "lg:col-span-10", "11": "lg:col-span-11", "12": "lg:col-span-12", }; const SPACE_BOTTOM: Record = { 0: "mb-0", 0.5: "mb-2", // 0.5rem 1: "mb-4", // 1rem 1.5: "mb-6", // 1.5rem 2: "mb-8", // 2rem }; /** * Gibt Tailwind-Klassen für das Block-Layout zurück (12-Spalten-Grid + Abstand). * Parent muss grid grid-cols-12 haben. */ /** * Gibt Tailwind-Klassen für den Block-Inhalt zurück. * Bei breakout: true nur w-full + Abstand (Spalten/Wrapper kommen von außen). */ export function getBlockLayoutClasses( layout: BlockLayout | undefined | null, ): string { if (!layout || typeof layout !== "object") { return "col-span-12 mb-4"; } const breakout = layout.breakout === true; const sb = typeof layout.spaceBottom === "number" ? layout.spaceBottom : Number(layout.spaceBottom); const spaceClass = SPACE_BOTTOM[sb as keyof typeof SPACE_BOTTOM] ?? "mb-4"; if (breakout) { return "w-full"; } const mobile = String(layout.mobile ?? "12"); const tablet = layout.tablet != null ? String(layout.tablet) : undefined; const desktop = layout.desktop != null ? String(layout.desktop) : undefined; const parts: string[] = [ COL_SPAN[mobile] ?? "col-span-12", tablet ? (MD_COL_SPAN[tablet] ?? "") : "", desktop ? (LG_COL_SPAN[desktop] ?? "") : "", spaceClass, ]; return parts.filter(Boolean).join(" "); } /** Tailwind-Klasse für spaceBottom (z. B. am Breakout-Wrapper). */ export function getSpaceBottomClass( layout: BlockLayout | undefined | null, ): string { if (!layout || typeof layout !== "object") return "mb-4"; const sb = typeof layout.spaceBottom === "number" ? layout.spaceBottom : Number(layout.spaceBottom); return SPACE_BOTTOM[sb as keyof typeof SPACE_BOTTOM] ?? "mb-4"; } /** Prüft, ob das Layout breakout (fullwidth) haben soll. */ export function isBlockLayoutBreakout( layout: BlockLayout | undefined | null, ): boolean { return !!(layout && typeof layout === "object" && layout.breakout === true); }