/// News Card Widget /// /// Compact news article card for list display. /// Horizontal layout with thumbnail and content. library; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.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'; /// News Card /// /// Compact card with horizontal layout: /// - 80x80 thumbnail (left) /// - Title (max 2 lines, 0.875rem, bold) /// - Excerpt (max 2 lines, 0.75rem, grey) /// - Metadata: date and views /// - Hover/tap effect (border color change) class NewsCard extends StatelessWidget { /// News article to display final NewsArticle article; /// Callback when card is tapped final VoidCallback? onTap; /// Constructor const NewsCard({super.key, required this.article, this.onTap}); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.only(bottom: AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.card), border: Border.all(color: const Color(0xFFE2E8F0)), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Thumbnail (80x80) ClipRRect( borderRadius: BorderRadius.circular(AppRadius.md), child: CachedNetworkImage( imageUrl: article.imageUrl, width: 80, height: 80, fit: BoxFit.cover, placeholder: (context, url) => Container( width: 80, height: 80, color: AppColors.grey100, child: const Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ), ), ), errorWidget: (context, url, error) => Container( width: 80, height: 80, color: AppColors.grey100, child: const Icon( Icons.image_outlined, size: 24, color: AppColors.grey500, ), ), ), ), const SizedBox(width: AppSpacing.md), // Content (flexible to fill remaining space) Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title (max 2 lines) Text( article.title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF1E293B), height: 1.3, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), // Excerpt (max 2 lines) Text( article.excerpt, style: const TextStyle( fontSize: 12, color: Color(0xFF64748B), height: 1.4, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), // Metadata row (date and views) Row( children: [ // Date Icon( Icons.calendar_today, size: 12, color: const Color(0xFF64748B), ), const SizedBox(width: 4), Text( article.formattedDate, style: const TextStyle( fontSize: 12, color: Color(0xFF64748B), ), ), const SizedBox(width: 16), // Views // Icon( // Icons.visibility, // size: 12, // color: const Color(0xFF64748B), // ), // const SizedBox(width: 4), // Text( // '${article.formattedViewCount} lượt xem', // style: const TextStyle( // fontSize: 12, // color: Color(0xFF64748B), // ), // ), ], ), ], ), ), ], ), ), ); } }