diff --git a/apps/web/src/components/PayloadRichText.tsx b/apps/web/src/components/PayloadRichText.tsx index f62b2d8..f9f28db 100644 --- a/apps/web/src/components/PayloadRichText.tsx +++ b/apps/web/src/components/PayloadRichText.tsx @@ -44,6 +44,19 @@ function renderInlineMarkdown(text: string): React.ReactNode { const jsxConverters: JSXConverters = { ...defaultJSXConverters, + // Override paragraph to filter out leftover raw text + paragraph: ({ node, nodesToJSX }: any) => { + const children = node?.children; + if ( + children?.length === 1 && + children[0]?.type === "text" && + children[0]?.text?.trim()?.startsWith("<") && + children[0]?.text?.trim()?.endsWith("/>") + ) { + return null; // suppress raw JSX component text like + } + return

{nodesToJSX({ nodes: children })}

; + }, blocks: { memeCard: ({ node }: any) => (
@@ -224,8 +237,8 @@ const jsxConverters: JSXConverters = { ({ - title: s.caption || "Image", - content: "", + title: s.title || s.caption || "Slide", + content: s.content || s.caption || "", icon: undefined, })) || [] } diff --git a/apps/web/src/components/simulations/LoadTimeSimulator.tsx b/apps/web/src/components/simulations/LoadTimeSimulator.tsx index 5f0a478..fb44cbc 100644 --- a/apps/web/src/components/simulations/LoadTimeSimulator.tsx +++ b/apps/web/src/components/simulations/LoadTimeSimulator.tsx @@ -1,14 +1,16 @@ "use client"; -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { ComponentShareButton } from '../ComponentShareButton'; import { Reveal } from '../Reveal'; -import { Play, RotateCcw } from 'lucide-react'; +import { RotateCcw } from 'lucide-react'; export function LoadTimeSimulator({ className = '' }: { className?: string }) { const [isRunning, setIsRunning] = useState(false); const [timeElapsed, setTimeElapsed] = useState(0); const [legacyState, setLegacyState] = useState(0); + const [hasAutoStarted, setHasAutoStarted] = useState(false); + const containerRef = useRef(null); const [mintelState, setMintelState] = useState(0); useEffect(() => { @@ -36,6 +38,25 @@ export function LoadTimeSimulator({ className = '' }: { className?: string }) { return () => clearInterval(interval); }, [isRunning, timeElapsed]); + // Auto-start the race when scrolled into viewport + useEffect(() => { + if (hasAutoStarted) return; + const el = containerRef.current; + if (!el) return; + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setHasAutoStarted(true); + setIsRunning(true); + observer.disconnect(); + } + }, + { threshold: 0.4 } + ); + observer.observe(el); + return () => observer.disconnect(); + }, [hasAutoStarted]); + const startRace = () => { setTimeElapsed(0); setLegacyState(0); @@ -45,7 +66,7 @@ export function LoadTimeSimulator({ className = '' }: { className?: string }) { return ( -
+
@@ -63,13 +84,15 @@ export function LoadTimeSimulator({ className = '' }: { className?: string }) { Simulieren Sie den Unterschied zwischen dynamischem Server-Rendering (PHP/MySQL) und statischer Edge-Auslieferung (TTV < 500ms).

- + {timeElapsed > 0 && !isRunning && ( + + )}
diff --git a/apps/web/src/payload/blocks/CarouselBlock.ts b/apps/web/src/payload/blocks/CarouselBlock.ts index 3ba97f8..29230a1 100644 --- a/apps/web/src/payload/blocks/CarouselBlock.ts +++ b/apps/web/src/payload/blocks/CarouselBlock.ts @@ -16,6 +16,16 @@ export const CarouselBlock: MintelBlock = { name: "slides", type: "array", fields: [ + { + name: "title", + type: "text", + admin: { description: "Titel der Slide-Karte." }, + }, + { + name: "content", + type: "textarea", + admin: { description: "Beschreibungstext der Slide-Karte." }, + }, { name: "image", type: "upload",