/// Featured News Card Widget /// /// Large featured article card with full-width image. /// Used at the top of news list page for the main featured article. library; import 'package:cached_network_image/cached_network_image.dart'; import 'package:worker/core/widgets/loading_indicator.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/features/news/domain/entities/news_article.dart'; /// Featured News Card /// /// Large card with: /// - Full-width 200px height image /// - Title (1.125rem, bold) /// - Excerpt/description (truncated) /// - Metadata: date, views, reading time /// - Category badge (primary blue) /// - Shadow and rounded corners class FeaturedNewsCard extends StatelessWidget { /// Constructor const FeaturedNewsCard({super.key, required this.article, this.onTap}); /// News article to display final NewsArticle article; /// Callback when card is tapped final VoidCallback? onTap; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: colorScheme.outlineVariant), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.08), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Featured image (200px height) ClipRRect( borderRadius: const BorderRadius.vertical( top: Radius.circular(AppRadius.xl), ), child: CachedNetworkImage( imageUrl: article.imageUrl, width: double.infinity, height: 200, fit: BoxFit.cover, placeholder: (context, url) => Container( height: 200, color: colorScheme.surfaceContainerHighest, child: const const CustomLoadingIndicator(), ), errorWidget: (context, url, error) => Container( height: 200, color: colorScheme.surfaceContainerHighest, child: FaIcon( FontAwesomeIcons.image, size: 48, color: colorScheme.onSurfaceVariant, ), ), ), ), // Content section Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text( article.title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: colorScheme.onSurface, height: 1.4, ), ), const SizedBox(height: 12), // Excerpt Text( article.excerpt, style: TextStyle( fontSize: 14, color: colorScheme.onSurfaceVariant, height: 1.5, ), maxLines: 3, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 16), // Metadata row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Left metadata (date, views, reading time) Expanded( child: Wrap( spacing: 16, runSpacing: 4, children: [ // Date _buildMetaItem( context, icon: FontAwesomeIcons.calendar, text: article.formattedDate, ), // // Views // _buildMetaItem( // context, // icon: Icons.visibility, // text: '${article.formattedViewCount} lượt xem', // ), // // // Reading time // _buildMetaItem( // context, // icon: Icons.schedule, // text: article.readingTimeText, // ), ], ), ), // Category badge Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4, ), decoration: BoxDecoration( color: colorScheme.primary, borderRadius: BorderRadius.circular(16), ), child: Text( article.category.displayName, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: colorScheme.onPrimary, ), ), ), ], ), ], ), ), ], ), ), ); } /// Build metadata item Widget _buildMetaItem(BuildContext context, {required IconData icon, required String text}) { final colorScheme = Theme.of(context).colorScheme; return Row( mainAxisSize: MainAxisSize.min, children: [ FaIcon(icon, size: 12, color: colorScheme.onSurfaceVariant), const SizedBox(width: 4), Text( text, style: TextStyle(fontSize: 12, color: colorScheme.onSurfaceVariant), ), ], ); } }