hi there, this is a test
dit is een quote van iemand
content
dat ging niet goed
huh
war
arara
a
rar
ar
a
r
ar
a
r
ara
| tabel | haha | en t werkt gewoon goed? |
| wow | huh | WOW |
function render_list_recursive($items, $tag) {
$html = "<$tag>";
foreach ($items as $item) {
if (is_array($item)) {
$content = $item['content'] ?? '';
$nested = !empty($item['items']) ? render_list_recursive($item['items'], $tag) : '';
$html .= "<li>{$content}{$nested}</li>";
} else {
$html .= "<li>{$item}</li>";
}
}
$html .= "</$tag>";
return $html;
}
function render_blocks($json_string) {
if (!str_starts_with(trim($json_string), '{')) {
return nl2br($json_string);
}
$data = json_decode($json_string, true);
if (!$data || !isset($data['blocks'])) return "";
$html = "";
$blocks = $data['blocks'];
$count = count($blocks);
// Timeline State Tracker
$in_timeline = false;
for ($i = 0; $i < $count; $i++) {
$block = $blocks[$i];
$type = $block['type'];
// Auto-wrap Timeline Items
if ($type === 'timeline_item') {
if (!$in_timeline) {
$html .= '<div class="terminal-timeline">';
$in_timeline = true;
}
} else {
if ($in_timeline) {
$html .= '</div>';
$in_timeline = false;
}
}
switch ($type) {
case 'header':
$level = $block['data']['level'];
$text = $block['data']['text'];
$html .= "<h{$level}>{$text}</h{$level}>";
break;
case 'paragraph':
$html .= "<p>{$block['data']['text']}</p>";
break;
case 'list':
$style = $block['data']['style'] ?? 'unordered';
$tag = ($style === 'ordered') ? 'ol' : 'ul';
$items = $block['data']['items'] ?? [];
$html .= render_list_recursive($items, $tag);
break;
case 'image':
$url = $block['data']['url'];
$caption = $block['data']['caption'] ?? '';
$html .= "<figure><img src='{$url}' alt='{$caption}'><figcaption>{$caption}</figcaption></figure>";
break;
case 'code':
$code = htmlspecialchars($block['data']['code']);
$html .= "<pre><code>{$code}</code></pre>";
break;
case 'quote':
$text = $block['data']['text'];
$caption = $block['data']['caption'] ?? '';
$html .= "<blockquote><p>{$text}</p><footer><cite>{$caption}</cite></footer></blockquote>";
break;
case 'table':
$content = $block['data']['content'] ?? [];
if (!empty($content)) {
$html .= "<table><tbody>";
foreach ($content as $row) {
$html .= "<tr>";
foreach ($row as $cell) {
$html .= "<td>{$cell}</td>";
}
$html .= "</tr>";
}
$html .= "</tbody></table>";
}
break;
// --- Custom Terminal Components ---
case 'alert':
$type = $block['data']['type'];
$msg = $block['data']['message'];
$class = 'terminal-alert';
if ($type === 'primary') $class .= ' terminal-alert-primary';
if ($type === 'error') $class .= ' terminal-alert-error';
$html .= "<div class='{$class}'>{$msg}</div>";
break;
case 'card':
$head = $block['data']['header'];
$body = $block['data']['body'];
$html .= "<div class='terminal-card'><header>{$head}</header><div>{$body}</div></div>";
break;
case 'timeline_item':
$head = $block['data']['header'];
$body = $block['data']['body'];
$html .= "<div class='terminal-card'><header>{$head}</header><div>{$body}</div></div>";
break;
case 'btn':
$text = $block['data']['text'];
$url = $block['data']['url'];
$style = $block['data']['style'];
$ghost = $block['data']['ghost'];
$isBlock = $block['data']['block'];
$class = 'btn';
if ($style === 'primary') $class .= ' btn-primary';
if ($style === 'error') $class .= ' btn-error';
if ($ghost) $class .= ' btn-ghost';
if ($isBlock) $class .= ' btn-block';
$html .= "<a href='{$url}' class='{$class}' role='button'>{$text}</a>";
break;
case 'progress':
$pct = $block['data']['percent'];
$showLabel = $block['data']['showLabel'];
$class = 'progress-bar';
if ($showLabel) $class .= ' progress-bar-show-percent';
$labelAttr = $showLabel ? "data-filled='{$pct}%'" : "";
$html .= "<div class='{$class}'><div class='progress-bar-filled' style='width:{$pct}%' {$labelAttr}></div></div>";
break;
case 'media':
$align = $block['data']['align'];
$img = $block['data']['image'];
$head = $block['data']['header'];
$body = $block['data']['body'];
$html .= "<div class='terminal-media'>";
if ($align === 'left') {
$html .= "<div class='terminal-media-left'><div class='terminal-avatarholder'><img src='{$img}'></div></div>";
}
$html .= "<div class='terminal-media-body'>
<div class='terminal-media-heading'>{$head}</div>
<div class='terminal-media-content'>{$body}</div>
</div>";
if ($align === 'right') {
$html .= "<div class='terminal-media-right'><div class='terminal-avatarholder'><img src='{$img}'></div></div>";
}
$html .= "</div>";
break;
case 'dl':
$items = $block['data']['items'];
if (!empty($items)) {
$html .= "<dl>";
foreach ($items as $item) {
$html .= "<dt>{$item['term']}</dt><dd>{$item['desc']}</dd>";
}
$html .= "</dl>";
}
break;
}
}
// Close timeline if still open
if ($in_timeline) {
$html .= '</div>';
}
return $html;
}Event details...
Event details...

Heading
- term
- description
- more terms
- more description?