refactor: remove flutter_highlight dependency and enhance code block styling

- Removed flutter_highlight as a dependency to streamline the codebase.
- Updated CodeBlockHeader to improve styling based on the current theme, enhancing visual consistency.
- Adjusted code block background and text colors to match GitHub/Atom themes for better readability.
- Refactored markdown processing logic to eliminate reliance on deprecated highlight features, improving maintainability.
This commit is contained in:
cogwheel0
2025-10-04 23:31:42 +05:30
parent a4319a1d9e
commit f4e4e86c38
5 changed files with 77 additions and 110 deletions

View File

@@ -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,
),
),
),
),
],
),

View File

@@ -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<String, TextStyle> _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

View File

@@ -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._();

View File

@@ -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:

View File

@@ -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