/// 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: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'; /// 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) { final colorScheme = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.only(bottom: AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.card), border: Border.all(color: colorScheme.outlineVariant), ), 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: colorScheme.surfaceContainerHighest, child: const Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ), ), ), errorWidget: (context, url, error) => Container( width: 80, height: 80, color: colorScheme.surfaceContainerHighest, child: FaIcon( FontAwesomeIcons.image, size: 24, color: colorScheme.onSurfaceVariant, ), ), ), ), 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: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: colorScheme.onSurface, height: 1.3, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), // Excerpt (max 2 lines) Text( article.excerpt, style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, height: 1.4, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), // Metadata row (date and views) Row( children: [ // Date FaIcon( FontAwesomeIcons.calendar, size: 12, color: colorScheme.onSurfaceVariant, ), const SizedBox(width: 4), Text( article.formattedDate, style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), ), const SizedBox(width: 16), // Views // Icon( // Icons.visibility, // size: 12, // color: colorScheme.onSurfaceVariant, // ), // const SizedBox(width: 4), // Text( // '${article.formattedViewCount} lượt xem', // style: TextStyle( // fontSize: 12, // color: colorScheme.onSurfaceVariant, // ), // ), ], ), ], ), ), ], ), ), ); } }