4 Commits

Author SHA1 Message Date
6b6b2b8ece fix(blog): auto-play LoadTimeSimulator, fix Carousel data, filter TableOfContents text, extend CarouselBlock schema
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🏗️ Build (push) Successful in 21m19s
Build & Deploy / 🚀 Deploy (push) Successful in 14s
Build & Deploy / 🧪 QA (push) Successful in 1m28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m59s
Build & Deploy / 🔔 Notify (push) Successful in 9s
Nightly QA / 🔗 Links & Deps (push) Successful in 3m40s
Nightly QA / 🎭 Lighthouse (push) Successful in 4m18s
Nightly QA / 🔍 Static Analysis (push) Successful in 4m34s
Nightly QA / 📝 E2E (push) Successful in 4m45s
Nightly QA / 🔔 Notify (push) Has been skipped
2026-03-06 00:54:45 +01:00
9f412d81a8 chore: release v1.9.9 to trigger prod deploy
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🏗️ Build (push) Successful in 10m35s
Build & Deploy / 🚀 Deploy (push) Successful in 15s
Build & Deploy / 🧪 QA (push) Successful in 50s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m44s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-03-05 23:54:12 +01:00
9c401f13de chore: trigger CI build after clearing infra registry space
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 23s
Build & Deploy / 🏗️ Build (push) Successful in 16m49s
Build & Deploy / 🚀 Deploy (push) Successful in 15s
Build & Deploy / 🧪 QA (push) Successful in 56s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 4m0s
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-05 23:22:45 +01:00
5857404ac1 fix(blog): merge defaultJSXConverters to prevent 'unknown node' on standard Lexical nodes
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🏗️ Build (push) Failing after 20m40s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 QA (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-05 22:53:19 +01:00
3 changed files with 63 additions and 13 deletions

View File

@@ -1,4 +1,7 @@
import { RichText } from "@payloadcms/richtext-lexical/react";
import {
RichText,
defaultJSXConverters,
} from "@payloadcms/richtext-lexical/react";
import type { JSXConverters } from "@payloadcms/richtext-lexical/react";
import { MemeCard } from "@/src/components/MemeCard";
import { Mermaid } from "@/src/components/Mermaid";
@@ -40,6 +43,20 @@ function renderInlineMarkdown(text: string): React.ReactNode {
}
const jsxConverters: JSXConverters = {
...defaultJSXConverters,
// Override paragraph to filter out leftover <TableOfContents /> 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 <TableOfContents />
}
return <p>{nodesToJSX({ nodes: children })}</p>;
},
blocks: {
memeCard: ({ node }: any) => (
<div className="my-8">
@@ -220,8 +237,8 @@ const jsxConverters: JSXConverters = {
<mdxComponents.Carousel
items={
node.fields.slides?.map((s: any) => ({
title: s.caption || "Image",
content: "",
title: s.title || s.caption || "Slide",
content: s.content || s.caption || "",
icon: undefined,
})) || []
}

View File

@@ -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<HTMLDivElement>(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 (
<Reveal direction="up" delay={0.1}>
<div className={`not-prose max-w-4xl mx-auto my-12 relative group ${className}`}>
<div ref={containerRef} className={`not-prose max-w-4xl mx-auto my-12 relative group ${className}`}>
<div className="absolute -inset-1 bg-gradient-to-r from-red-100 to-emerald-100 rounded-3xl blur opacity-30" />
<div id="sim-load-time" className="relative bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden flex flex-col">
@@ -63,13 +84,15 @@ export function LoadTimeSimulator({ className = '' }: { className?: string }) {
Simulieren Sie den Unterschied zwischen dynamischem Server-Rendering (PHP/MySQL) und statischer Edge-Auslieferung (<span className="font-mono bg-slate-200 px-1 rounded text-[10px]">TTV &lt; 500ms</span>).
</p>
</div>
<button
onClick={startRace}
className="shrink-0 flex items-center gap-2 px-6 py-2.5 bg-slate-900 !text-white rounded-full font-bold text-sm hover:hover:bg-black hover:scale-105 active:scale-95 transition-all shadow-md"
>
{timeElapsed > 0 ? <RotateCcw size={16} /> : <Play size={16} />}
{timeElapsed > 0 ? "Neustart" : "Rennen Starten"}
</button>
{timeElapsed > 0 && !isRunning && (
<button
onClick={startRace}
className="shrink-0 flex items-center gap-2 px-6 py-2.5 bg-slate-900 !text-white rounded-full font-bold text-sm hover:hover:bg-black hover:scale-105 active:scale-95 transition-all shadow-md"
>
<RotateCcw size={16} />
Neustart
</button>
)}
</div>
<div className="grid md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-slate-100 bg-slate-50/50">

View File

@@ -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",