render markdown hard breaks and image placeholders (T-379)

Both node types fell through the inline-span switch to an empty
textContent span: words on either side of a hard break glued
together, and images vanished with no trace. A br now emits a
newline; an img renders a muted italic "[image: alt]" placeholder
(falling back to the src) — no inline network loading in the owned
renderer; live-pane images keep going through clide image show.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 01:18:41 +02:00
co-authored by Claude Fable 5
parent e413380ea9
commit 01c3de37e1
5 changed files with 55 additions and 0 deletions
+16
View File
@@ -405,6 +405,22 @@ class ClideMarkdown extends StatelessWidget {
text: _unescapeHtml(el.textContent),
style: TextStyle(decoration: TextDecoration.lineThrough, color: tokens.globalTextMuted),
);
case 'br':
// A hard break has no textContent — the default branch rendered it
// as an empty span and glued the surrounding words together (T-379).
return const TextSpan(text: '\n');
case 'img':
// No inline image loading (network fetch in a text span is not the
// owned-renderer way; live-pane images go through `clide image
// show`) — render a visible alt-text placeholder instead of
// disappearing (T-379).
final alt = _unescapeHtml(el.attributes['alt'] ?? '');
final src = el.attributes['src'] ?? '';
final label = alt.isNotEmpty ? alt : src;
return TextSpan(
text: label.isEmpty ? '[image]' : '[image: $label]',
style: TextStyle(color: tokens.globalTextMuted, fontStyle: FontStyle.italic),
);
default:
return TextSpan(text: _unescapeHtml(el.textContent));
}