import 'package:flutter/material.dart'; import '../models/tab_data.dart'; class ItemCard extends StatelessWidget { final TabData item; final String icon; final VoidCallback onTap; final VoidCallback onDelete; final VoidCallback onTogglePin; final bool extensionMode; const ItemCard({ super.key, required this.item, required this.icon, required this.onTap, required this.onDelete, required this.onTogglePin, this.extensionMode = false, }); @override Widget build(BuildContext context) { return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 60, color: Theme.of(context).colorScheme.primaryContainer, child: Center( child: item.favicon.isNotEmpty && item.favicon.startsWith('http') ? Image.network( item.favicon, width: 32, height: 32, errorBuilder: (context, error, stackTrace) { return Text(icon, style: const TextStyle(fontSize: 32)); }, ) : Text(icon, style: const TextStyle(fontSize: 32)), ), ), Expanded( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ if (item.isPinned) Icon( Icons.push_pin, size: 14, color: Theme.of(context).colorScheme.primary, ), if (item.isPinned) const SizedBox(width: 4), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: _getTypeColor(context), borderRadius: BorderRadius.circular(4), ), child: Text( item.type.toUpperCase(), style: TextStyle( fontSize: 10, color: Theme.of(context).colorScheme.onPrimary, ), ), ), ], ), const SizedBox(height: 6), Expanded( child: Text( item.title, style: Theme.of(context).textTheme.titleSmall, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 4), Text( item.url, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.secondary, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), if (item.visitCount != null) ...[ const SizedBox(height: 4), Text( '${item.visitCount} visits', style: Theme.of(context).textTheme.bodySmall, ), ], ], ), ), ), if (!extensionMode) ButtonBar( alignment: MainAxisAlignment.end, buttonPadding: EdgeInsets.zero, children: [ if (item.type == 'tab') IconButton( icon: Icon( item.isPinned ? Icons.push_pin : Icons.push_pin_outlined, size: 18, ), onPressed: onTogglePin, tooltip: item.isPinned ? 'Unpin' : 'Pin', ), if (item.type != 'history') IconButton( icon: const Icon(Icons.delete_outline, size: 18), onPressed: onDelete, tooltip: 'Delete', ), ], ), ], ), ), ); } Color _getTypeColor(BuildContext context) { switch (item.type) { case 'tab': return Colors.blue; case 'bookmark': return Colors.orange; case 'history': return Colors.purple; default: return Theme.of(context).colorScheme.primary; } } } // This widget displays a single tab, bookmark, or history item as a card in the grid view. // // It is a stateless widget that receives all its data from the parent component. // // The card shows a favicon or emoji icon at the top in a colored header section. // // Below that it displays a type badge, the item title, URL, and optional visit count. // // If the item is pinned, a pin icon appears next to the type badge. // // The card is tappable and triggers the onTap callback to open the item. // // Action buttons at the bottom allow pinning tabs and deleting tabs or bookmarks. // // These action buttons are hidden in extension mode since you cannot modify tracked tabs. // // History items do not show a delete button since browser history cannot be removed this way. // // The getTypeColor method assigns different colors to the type badge based on item type. // // This card design provides a clean visual representation of browser items in grid layout.