// nav_sidebar.dart — desktop/tablet 左侧栏导航 // // 对照 ui_kits/desktop/dapp.jsx:宽 204、bgSubtle 底 + 右边框; // 品牌区(mark28 + 穿山甲 + PANGOLIN) → NavItem 列表 → Spacer → 套餐卡。 import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../pangolin_theme.dart'; import '../state/app_providers.dart'; import '../state/navigation_provider.dart'; import 'pangolin_icons.dart'; import 'pangolin_logo.dart'; import 'plan_badge_card.dart'; typedef NavSidebarItem = ({IconData icon, String label, NavView view}); class NavSidebar extends ConsumerWidget { const NavSidebar({super.key, required this.items, this.width = 204}); final List items; final double width; @override Widget build(BuildContext context, WidgetRef ref) { final c = context.pangolin; final t = ref.watch(appTextProvider); final current = ref.watch(navViewProvider); return Container( width: width, decoration: BoxDecoration( color: c.bgSubtle, border: Border(right: BorderSide(color: c.border)), ), padding: const EdgeInsets.fromLTRB(12, 14, 12, 14), child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 品牌区 Padding( padding: const EdgeInsets.fromLTRB(6, 2, 6, 16), child: Row(children: [ const PangolinMark(size: 28), const SizedBox(width: 9), Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text(t.brand, style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700, fontSize: 16, height: 1)), const SizedBox(height: 3), Text('PANGOLIN', style: PangolinText.caption.copyWith( color: c.accent, fontWeight: FontWeight.w600, fontSize: 9, letterSpacing: 1.6)), ]), ]), ), // Nav 列表 for (final item in items) Padding( padding: const EdgeInsets.only(bottom: 3), child: _NavItem( icon: item.icon, label: item.label, active: current == item.view, onTap: () => ref.read(navViewProvider.notifier).state = item.view, ), ), const Spacer(), const PlanBadgeCard(), ]), ); } } class _NavItem extends StatelessWidget { const _NavItem({required this.icon, required this.label, required this.active, required this.onTap}); final IconData icon; final String label; final bool active; final VoidCallback onTap; @override Widget build(BuildContext context) { final c = context.pangolin; return Material( color: active ? c.accentSubtle : Colors.transparent, borderRadius: BorderRadius.circular(PangolinRadius.md), clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9), child: Row(children: [ Icon(icon, size: 18, color: active ? c.accent : c.fg3), const SizedBox(width: 11), Text(label, style: PangolinText.sm.copyWith( color: active ? c.accent : c.fg2, fontSize: 13.5, fontWeight: active ? FontWeight.w600 : FontWeight.w500)), ]), ), ), ); } }