diff --git a/lib/main.dart b/lib/main.dart index 513d905..9e3fd83 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,7 +17,6 @@ class MyApp extends StatelessWidget { useMaterial3: true, ), home: const MyHomePage(), - // Named routes for clean navigation routes: { '/shop': (context) => const ShopLandingPage(), '/shop/grid-right': (context) => const ShopGridRightSidebarPage(), @@ -26,7 +25,6 @@ class MyApp extends StatelessWidget { } } - // REUSABLE HEADER WIDGET class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final String title; @@ -687,7 +685,6 @@ class BreadcrumbsBar extends StatelessWidget { } } - // MAIN HOME PAGE class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @@ -732,7 +729,91 @@ class ShopLandingPage extends StatelessWidget { } } -// SHOP GRID - RIGHT SIDEBAR PAGE +// PRODUCT CARD WIDGET +class ProductCard extends StatelessWidget { + final String imageUrl; + final String category; + final String title; + final double rating; + final String brand; + final double currentPrice; + final double originalPrice; + final VoidCallback? onAdd; + + const ProductCard({ + super.key, + required this.imageUrl, + required this.category, + required this.title, + required this.rating, + required this.brand, + required this.currentPrice, + required this.originalPrice, + this.onAdd, + }); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey[200]!), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + imageUrl.trim(), // ✅ Trim spaces + height: 200, + width: double.infinity, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) => Container( + height: 200, + color: Colors.grey[200], + child: const Center(child: Text('Image')), + ), + ), + ), + const SizedBox(height: 12), + Text(category, style: const TextStyle(color: Colors.grey, fontSize: 12)), + const SizedBox(height: 4), + Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), + const SizedBox(height: 8), + Text('By $brand', style: const TextStyle(color: Colors.green, fontSize: 12)), + const SizedBox(height: 8), + Row( + children: [ + Text('\$${currentPrice.toStringAsFixed(2)}', + style: const TextStyle(color: Colors.green, fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(width: 8), + Text('\$${originalPrice.toStringAsFixed(2)}', + style: const TextStyle( + color: Colors.grey, + decoration: TextDecoration.lineThrough, + )), + ], + ), + const SizedBox(height: 12), + ElevatedButton( + onPressed: onAdd, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green[100], + foregroundColor: Colors.green[800], + ), + child: const Text('Add'), + ), + ], + ), + ); + } +} + +// SHOP GRID - RIGHT SIDEBAR PAGE ✅ FIXED class ShopGridRightSidebarPage extends StatelessWidget { const ShopGridRightSidebarPage({super.key}); @@ -741,18 +822,167 @@ class ShopGridRightSidebarPage extends StatelessWidget { return Scaffold( appBar: const CustomAppBar(title: 'Shop Grid - Right Sidebar'), drawer: const AppDrawer(), - body: Column( - children: [ - BreadcrumbsBar(currentPage: 'Snack'), - Expanded( - child: Center( + // ✅ FIXED: Wrap Column in SingleChildScrollView + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BreadcrumbsBar(currentPage: 'Snack'), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Text( - 'Hello from Shop Grid - Right Sidebar!', - style: const TextStyle(fontSize: 24), + 'We found 29 items for you!', + style: const TextStyle(fontSize: 14), ), ), - ), - ], + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Row( + children: [ + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 160), + child: Container( + decoration: BoxDecoration( + color: Colors.grey[100], + border: Border.all(color: Colors.grey[300]!), + borderRadius: BorderRadius.circular(8), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: '50', + onChanged: (String? newValue) {}, + items: ['50', '100', '150', '200', 'All'].map((String value) { + return DropdownMenuItem( + value: value, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + if (value == '50') ...[ + Icon(Icons.check, size: 16, color: Colors.green), + const SizedBox(width: 8), + ] else + const SizedBox(width: 24), + Text(value), + ], + ), + ), + ); + }).toList(), + isExpanded: true, + icon: const Icon(Icons.arrow_drop_down, color: Colors.grey, size: 18), + style: const TextStyle(fontSize: 13, color: Colors.black), + selectedItemBuilder: (context) { + return [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + Icon(Icons.view_agenda, size: 16, color: Colors.grey), + const SizedBox(width: 6), + Text('Show: 50', style: const TextStyle(fontSize: 13)), + ], + ), + ), + ]; + }, + ), + ), + ), + ), + const SizedBox(width: 12), + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 180), + child: Container( + decoration: BoxDecoration( + color: Colors.grey[100], + border: Border.all(color: Colors.grey[300]!), + borderRadius: BorderRadius.circular(8), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: 'Featured', + onChanged: (String? newValue) {}, + items: [ + 'Featured', + 'Price: Low to High', + 'Price: High to Low', + 'Release Date', + 'Avg. Rating' + ].map((String value) { + return DropdownMenuItem( + value: value, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + if (value == 'Featured') ...[ + Icon(Icons.check, size: 16, color: Colors.green), + const SizedBox(width: 8), + ] else + const SizedBox(width: 24), + Text(value), + ], + ), + ), + ); + }).toList(), + isExpanded: true, + icon: const Icon(Icons.arrow_drop_down, color: Colors.grey, size: 18), + style: const TextStyle(fontSize: 13, color: Colors.black), + selectedItemBuilder: (context) { + return [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + Icon(Icons.sort, size: 16, color: Colors.grey), + const SizedBox(width: 6), + Text('Sort by: Featured', style: const TextStyle(fontSize: 13)), + ], + ), + ), + ]; + }, + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + ProductCard( + imageUrl: 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-16-1.jpg', + category: 'Snack', + title: 'Seeds of Change Organic Quinoa', + rating: 4.0, + brand: 'NestFood', + currentPrice: 28.85, + originalPrice: 32.8, + onAdd: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Added to cart!')), + ); + }, + ), + ProductCard( + imageUrl: 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-1-1.jpg', + category: 'Snack', + title: 'Seeds of Change Organic Quinoa', + rating: 4.0, + brand: 'NestFood', + currentPrice: 28.85, + originalPrice: 32.8, + onAdd: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Added to cart!')), + ); + }, + ), + const SizedBox(height: 24), + ], + ), ), ); }