/// 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:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/theme/colors.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) { return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: const Color(0xFFE2E8F0)), 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: AppColors.grey100, child: const Center(child: CircularProgressIndicator()), ), errorWidget: (context, url, error) => Container( height: 200, color: AppColors.grey100, child: const FaIcon( FontAwesomeIcons.image, size: 48, color: AppColors.grey500, ), ), ), ), // Content section Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text( article.title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF1E293B), height: 1.4, ), ), const SizedBox(height: 12), // Excerpt Text( article.excerpt, style: const TextStyle( fontSize: 14, color: Color(0xFF64748B), 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( icon: FontAwesomeIcons.calendar, text: article.formattedDate, ), // // Views // _buildMetaItem( // icon: Icons.visibility, // text: '${article.formattedViewCount} lượt xem', // ), // // // Reading time // _buildMetaItem( // icon: Icons.schedule, // text: article.readingTimeText, // ), ], ), ), // Category badge Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4, ), decoration: BoxDecoration( color: AppColors.primaryBlue, borderRadius: BorderRadius.circular(16), ), child: Text( article.category.displayName, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.white, ), ), ), ], ), ], ), ), ], ), ), ); } /// Build metadata item Widget _buildMetaItem({required IconData icon, required String text}) { return Row( mainAxisSize: MainAxisSize.min, children: [ FaIcon(icon, size: 12, color: const Color(0xFF64748B)), const SizedBox(width: 4), Text( text, style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)), ), ], ); } }