/// 메인 셸 - 툴바 + 바텀 네비게이션 library; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../core/constants.dart'; /// 메인 앱 셸 (툴바 + 바텀 네비게이션 + 콘텐츠) class MainShell extends StatelessWidget { final Widget child; const MainShell({super.key, required this.child}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, // 앱바 (툴바) appBar: AppBar( backgroundColor: Colors.white, elevation: 0, scrolledUnderElevation: 1, centerTitle: true, title: Text( _getTitle(context), style: const TextStyle( color: AppColors.primary, fontSize: 20, fontWeight: FontWeight.bold, ), ), ), // 콘텐츠 body: child, // 바텀 네비게이션 bottomNavigationBar: const _BottomNavBar(), ); } /// 현재 경로에 따른 타이틀 반환 String _getTitle(BuildContext context) { final location = GoRouterState.of(context).uri.path; switch (location) { case '/': return 'fromis_9'; case '/members': return '멤버'; case '/album': return '앨범'; case '/schedule': return '일정'; default: return 'fromis_9'; } } } /// 바텀 네비게이션 바 class _BottomNavBar extends StatelessWidget { const _BottomNavBar(); @override Widget build(BuildContext context) { final location = GoRouterState.of(context).uri.path; return Container( decoration: const BoxDecoration( color: Colors.white, border: Border( top: BorderSide(color: AppColors.border, width: 1), ), ), child: SafeArea( child: SizedBox( height: 64, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _NavItem( icon: LucideIcons.home, label: '홈', isActive: location == '/', onTap: () => context.go('/'), ), _NavItem( icon: LucideIcons.users, label: '멤버', isActive: location == '/members', onTap: () => context.go('/members'), ), _NavItem( icon: LucideIcons.disc3, label: '앨범', isActive: location.startsWith('/album'), onTap: () => context.go('/album'), ), _NavItem( icon: LucideIcons.calendar, label: '일정', isActive: location.startsWith('/schedule'), onTap: () => context.go('/schedule'), ), ], ), ), ), ); } } /// 네비게이션 아이템 class _NavItem extends StatelessWidget { final IconData icon; final String label; final bool isActive; final VoidCallback onTap; const _NavItem({ required this.icon, required this.label, required this.isActive, required this.onTap, }); @override Widget build(BuildContext context) { final color = isActive ? AppColors.primary : AppColors.textTertiary; return Expanded( child: InkWell( onTap: onTap, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 22, color: color, ), const SizedBox(height: 4), Text( label, style: TextStyle( fontSize: 12, fontWeight: isActive ? FontWeight.w600 : FontWeight.w500, color: color, ), ), ], ), ), ); } }