refactor: integrate Mermaid diagram support in markdown rendering

- Added functionality to render Mermaid diagrams within markdown content, enhancing visual representation of diagrams.
- Implemented a new method to build Mermaid blocks, handling both supported and unsupported platforms gracefully.
- Updated the streaming markdown widget to parse and display Mermaid code blocks, ensuring a cohesive user experience.
- Improved overall maintainability of the markdown configuration by centralizing Mermaid-related logic and enhancing code clarity.
This commit is contained in:
cogwheel0
2025-10-03 16:29:21 +05:30
parent 141ee80097
commit 399b44bc74
2 changed files with 303 additions and 3 deletions

View File

@@ -27,8 +27,11 @@ class StreamingMarkdownWidget extends StatelessWidget {
final normalized = ConduitMarkdownPreprocessor.normalize(content);
final markdownTheme = ConduitMarkdownConfig.resolve(context);
final markdownBody = MarkdownBody(
data: normalized,
final mermaidRegex = RegExp(r'```mermaid\s*([\s\S]*?)```', multiLine: true);
final matches = mermaidRegex.allMatches(normalized).toList();
Widget buildMarkdown(String data) => MarkdownBody(
data: data,
styleSheet: markdownTheme.styleSheet,
selectable: false,
imageBuilder: markdownTheme.imageBuilder,
@@ -42,6 +45,40 @@ class StreamingMarkdownWidget extends StatelessWidget {
},
);
if (matches.isEmpty) {
return SelectionArea(
child: Theme(
data: Theme.of(context).copyWith(
textSelectionTheme: TextSelectionThemeData(
cursorColor: context.conduitTheme.buttonPrimary,
),
),
child: buildMarkdown(normalized),
),
);
}
final children = <Widget>[];
var currentIndex = 0;
for (final match in matches) {
final before = normalized.substring(currentIndex, match.start);
if (before.trim().isNotEmpty) {
children.add(buildMarkdown(before));
}
final code = match.group(1)?.trim() ?? '';
if (code.isNotEmpty) {
children.add(ConduitMarkdownConfig.buildMermaidBlock(context, code));
}
currentIndex = match.end;
}
final tail = normalized.substring(currentIndex);
if (tail.trim().isNotEmpty) {
children.add(buildMarkdown(tail));
}
return SelectionArea(
child: Theme(
data: Theme.of(context).copyWith(
@@ -49,7 +86,10 @@ class StreamingMarkdownWidget extends StatelessWidget {
cursorColor: context.conduitTheme.buttonPrimary,
),
),
child: markdownBody,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children,
),
),
);
}