import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/theme/colors.dart'; import '../../providers/navigation_provider.dart'; import '../common/mini_player.dart'; /// Desktop Navigation Sidebar class DesktopSidebar extends ConsumerWidget { final double width; const DesktopSidebar({ super.key, required this.width, }); @override Widget build(BuildContext context, WidgetRef ref) { final currentPage = ref.watch(currentPageProvider); final navigationNotifier = ref.read(navigationProvider.notifier); return Container( width: width, decoration: BoxDecoration( color: AppColors.surface, border: Border( right: BorderSide( color: AppColors.cyan.withOpacity(0.1), width: 1, ), ), ), child: Column( children: [ // Logo const Padding( padding: EdgeInsets.all(24), child: Text( 'Spotify Le 2', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, foreground: AppColors.primaryGradient, ), ), ), const Divider(height: 1, color: AppColors.surfaceVariant), // Navigation items Expanded( child: ListView( padding: const EdgeInsets.symmetric(vertical: 8), children: [ ..._navItems.map( (item) => _NavItemTile( icon: item.icon, label: item.label, isSelected: currentPage == item.page, onTap: () => navigationNotifier.navigateTo(item.page), ), ), ], ), ), // Mini player in sidebar const Padding( padding: EdgeInsets.all(16), child: MiniPlayer(compact: true), ), ], ), ); } } class _NavItem { final String page; final String label; final IconData icon; const _NavItem({ required this.page, required this.label, required this.icon, }); } final List<_NavItem> _navItems = const [ _NavItem(page: 'home', label: 'Home', icon: Icons.home_outlined), _NavItem(page: 'search', label: 'Search', icon: Icons.search_outlined), _NavItem(page: 'library', label: 'Library', icon: Icons.library_music_outlined), _NavItem(page: 'settings', label: 'Settings', icon: Icons.settings_outlined), ]; /// Navigation Item Tile class _NavItemTile extends StatefulWidget { final IconData icon; final String label; final bool isSelected; final VoidCallback onTap; const _NavItemTile({ required this.icon, required this.label, required this.isSelected, required this.onTap, }); @override State<_NavItemTile> createState() => _NavItemTileState(); } class _NavItemTileState extends State<_NavItemTile> with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _scaleAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this, ); _scaleAnimation = Tween(begin: 1.0, end: 1.02).animate( CurvedAnimation( parent: _animationController, curve: Curves.easeOut, ), ); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return MouseRegion( onEnter: (_) => _animationController.forward(), onExit: (_) => _animationController.reverse(), child: ScaleTransition( scale: _scaleAnimation, child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: widget.isSelected ? AppColors.cyan.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(8), border: Border.all( color: widget.isSelected ? AppColors.cyan.withOpacity(0.3) : Colors.transparent, width: 1, ), ), child: ListTile( leading: Icon( widget.icon, color: widget.isSelected ? AppColors.cyan : AppColors.onSurface, ), title: Text( widget.label, style: TextStyle( color: widget.isSelected ? AppColors.cyan : AppColors.onSurface, fontWeight: widget.isSelected ? FontWeight.w600 : FontWeight.w400, ), ), onTap: widget.onTap, ), ), ), ); } }