import 'package:flutter/material.dart'; import '../../theme/app_theme.dart'; import '../sojorn_rich_text.dart'; import 'markdown_post_body.dart'; import 'post_view_mode.dart'; /// Post body text with reading-optimized typography. /// /// Design Intent: /// - Post body is the hero - clear visual hierarchy /// - Line height adjusts based on content length /// - Typography communicates emotional tone, not just content /// - Supports both plain text and Markdown formatting /// - ViewMode controls truncation behavior class PostBody extends StatelessWidget { final String text; final String? bodyFormat; // 'plain' or 'markdown' final String? backgroundId; // theme id final bool isReflective; final PostViewMode mode; const PostBody({ super.key, required this.text, this.bodyFormat, this.backgroundId, this.isReflective = false, this.mode = PostViewMode.feed, }); /// Check if text contains Markdown syntax bool _hasMarkdownSyntax(String text) { // Check for common Markdown patterns return text.contains('**') || // Bold text.contains('_') || // Italic text.startsWith('#') || // Headers text.contains('[') && text.contains('](') || // Links text.contains('```') || // Code blocks text.contains('- ') || // Lists text.contains('> '); // Blockquotes } /// Determine max lines based on view mode int? get _maxLines { switch (mode) { case PostViewMode.feed: return 12; // Truncate in feed case PostViewMode.detail: return null; // Show all in detail case PostViewMode.compact: return 6; // More compact in profile lists } } @override Widget build(BuildContext context) { final cleanedText = text.replaceAll(RegExp(r'\s+$'), ''); // Detect if this is Markdown content final isMarkdown = bodyFormat == 'markdown' || _hasMarkdownSyntax(cleanedText); // Choose typography based on content length final TextStyle style; if (isReflective) { style = AppTheme.postBodyReflective; } else { final estimatedLines = (cleanedText.length / 45).ceil(); if (estimatedLines <= 3) { style = AppTheme.postBodyShort; } else if (estimatedLines >= 10) { style = AppTheme.postBodyLong; } else { style = AppTheme.postBody; } } if (isMarkdown) { return MarkdownPostBody( markdown: text, baseStyle: style, maxLines: _maxLines, ); } return sojornRichText( text: cleanedText, style: style, maxLines: _maxLines, ); } }