diff --git a/lib/shared/widgets/markdown/code_block_header.dart b/lib/shared/widgets/markdown/code_block_header.dart index 1e0116b..000d306 100644 --- a/lib/shared/widgets/markdown/code_block_header.dart +++ b/lib/shared/widgets/markdown/code_block_header.dart @@ -14,16 +14,30 @@ class CodeBlockHeader extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.conduitTheme; - final label = language.isEmpty ? 'code' : language; + final materialTheme = Theme.of(context); + final isDark = materialTheme.brightness == Brightness.dark; + final label = language.isEmpty ? 'plaintext' : language; + + // Match GitHub/Atom theme colors + final backgroundColor = isDark + ? const Color(0xFF282c34) // Atom One Dark header + : const Color(0xFFf6f8fa); // GitHub light header + final textColor = isDark + ? const Color(0xFF9da5b4) // Muted text for dark + : const Color(0xFF57606a); // GitHub gray for light + return Container( padding: const EdgeInsets.symmetric( - horizontal: Spacing.sm, + horizontal: Spacing.md, vertical: Spacing.xs, ), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.35), - borderRadius: const BorderRadius.vertical( - top: Radius.circular(AppBorderRadius.sm), + color: backgroundColor, + border: Border( + bottom: BorderSide( + color: theme.cardBorder.withValues(alpha: 0.15), + width: 1, + ), ), ), child: Row( @@ -31,16 +45,26 @@ class CodeBlockHeader extends StatelessWidget { Text( label, style: AppTypography.codeStyle.copyWith( - color: theme.textSecondary, - fontWeight: FontWeight.w600, + color: textColor, + fontSize: 12, + fontWeight: FontWeight.w500, ), ), const Spacer(), - IconButton( - icon: const Icon(Icons.copy_rounded, size: 18), - color: theme.iconPrimary, - tooltip: 'Copy code', - onPressed: onCopy, + Material( + color: Colors.transparent, + child: InkWell( + onTap: onCopy, + borderRadius: BorderRadius.circular(4), + child: Padding( + padding: const EdgeInsets.all(6), + child: Icon( + Icons.content_copy_rounded, + size: 16, + color: textColor, + ), + ), + ), ), ], ), diff --git a/lib/shared/widgets/markdown/markdown_config.dart b/lib/shared/widgets/markdown/markdown_config.dart index 3a601ab..9885b68 100644 --- a/lib/shared/widgets/markdown/markdown_config.dart +++ b/lib/shared/widgets/markdown/markdown_config.dart @@ -6,9 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_highlight/flutter_highlight.dart'; -import 'package:flutter_highlight/themes/a11y-dark.dart'; -import 'package:flutter_highlight/themes/a11y-light.dart'; import 'package:flutter_markdown_plus/flutter_markdown_plus.dart'; import 'package:flutter_math_fork/flutter_math.dart'; import 'package:markdown/markdown.dart' as md; @@ -283,91 +280,54 @@ class _CodeBlockBuilder extends MarkdownElementBuilder { final isDark = Theme.of(context).brightness == Brightness.dark; final code = element.textContent; final language = element.attributes['class']?.replaceFirst('language-', '') ?? 'plaintext'; - - final highlightTheme = _getCodeHighlightTheme(theme, isDark: isDark); final normalizedLanguage = language.trim().isEmpty ? 'plaintext' : language.trim(); - final highlight = HighlightView( - code, - language: normalizedLanguage == 'plaintext' ? null : normalizedLanguage, - theme: highlightTheme, - textStyle: AppTypography.codeStyle.copyWith(color: theme.codeText), - padding: EdgeInsets.zero, - ); + // Match GitHub/Atom theme colors for code block container + final codeBackground = isDark + ? const Color(0xFF282c34) // Atom One Dark background + : const Color(0xFFfafbfc); // GitHub light background - final codeBackground = theme.surfaceContainer.withValues(alpha: 0.55); - final borderColor = theme.cardBorder.withValues(alpha: 0.25); - - return LayoutBuilder( - builder: (context, constraints) { - final width = constraints.maxWidth.isFinite - ? constraints.maxWidth - : MediaQuery.sizeOf(context).width; - - return Container( - margin: const EdgeInsets.symmetric(vertical: Spacing.xs), - decoration: BoxDecoration( - color: codeBackground, - borderRadius: BorderRadius.circular(AppBorderRadius.sm), - border: Border.all(color: borderColor, width: BorderWidth.micro), + return Container( + margin: const EdgeInsets.symmetric(vertical: Spacing.sm), + decoration: BoxDecoration( + color: codeBackground, + borderRadius: BorderRadius.circular(6), + ), + clipBehavior: Clip.antiAlias, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + CodeBlockHeader( + language: normalizedLanguage, + onCopy: () async { + await Clipboard.setData(ClipboardData(text: code)); + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Code copied to clipboard.'), + ), + ); + }, ), - child: ClipRect( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - CodeBlockHeader( - language: normalizedLanguage, - onCopy: () async { - await Clipboard.setData(ClipboardData(text: code)); - if (!context.mounted) { - return; - } - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Code copied to clipboard.'), - ), - ); - }, - ), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: IntrinsicWidth( - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: width), - child: Padding( - padding: const EdgeInsets.all(Spacing.sm), - child: highlight, - ), - ), - ), - ), - ], + SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.all(Spacing.md), + child: SelectableText( + code, + style: AppTypography.codeStyle.copyWith( + color: theme.codeText, + fontFamily: AppTypography.monospaceFontFamily, + ), ), ), - ); - }, + ], + ), ); } - - Map _getCodeHighlightTheme( - ConduitThemeExtension theme, { - required bool isDark, - }) { - final baseTheme = isDark ? a11yDarkTheme : a11yLightTheme; - final codeStyle = AppTypography.codeStyle.copyWith(color: theme.codeText); - - return { - for (final entry in baseTheme.entries) - entry.key: entry.value.copyWith( - color: entry.value.color ?? theme.codeText, - fontFamily: AppTypography.monospaceFontFamily, - fontSize: codeStyle.fontSize, - height: codeStyle.height, - ), - }; - } } // Custom image builder diff --git a/lib/shared/widgets/markdown/markdown_preprocessor.dart b/lib/shared/widgets/markdown/markdown_preprocessor.dart index 0e61a71..64bb6f5 100644 --- a/lib/shared/widgets/markdown/markdown_preprocessor.dart +++ b/lib/shared/widgets/markdown/markdown_preprocessor.dart @@ -1,5 +1,5 @@ /// Utility helpers for normalising markdown content before handing it to -/// [GptMarkdown]. The goal is to keep streaming responsive while smoothing +/// [ConduitMarkdown]. The goal is to keep streaming responsive while smoothing /// out troublesome edge-cases (e.g. nested fences inside lists). class ConduitMarkdownPreprocessor { const ConduitMarkdownPreprocessor._(); diff --git a/pubspec.lock b/pubspec.lock index 210e332..efa8c68 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -430,14 +430,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" - flutter_highlight: - dependency: "direct main" - description: - name: flutter_highlight - sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" - url: "https://pub.dev" - source: hosted - version: "0.7.0" flutter_lints: dependency: "direct dev" description: @@ -621,14 +613,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" - highlight: - dependency: transitive - description: - name: highlight - sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" - url: "https://pub.dev" - source: hosted - version: "0.7.0" hive_ce: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 689cc14..35dd369 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,6 @@ dependencies: # UI Components - Markdown Rendering cached_network_image: ^3.3.1 - flutter_highlight: ^0.7.0 flutter_markdown_plus: ^1.0.5 markdown: ^7.3.0 webview_flutter: ^4.7.0