// 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_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, this.dense = true}); final List items; final double width; /// dense=true 桌面紧凑(行高~36);dense=false 平板触控(行高≥48, 字号更大)。 final bool dense; @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: EdgeInsets.fromLTRB(dense ? 12 : 14, dense ? 14 : 18, dense ? 12 : 14, dense ? 14 : 16), child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 品牌区(静态) Padding( padding: EdgeInsets.fromLTRB(6, 2, 6, dense ? 16 : 20), child: Row(children: [ PangolinMark(size: dense ? 28 : 30), SizedBox(width: dense ? 9 : 10), Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text(t.brand, style: PangolinText.h3.copyWith( color: c.fg1, fontWeight: FontWeight.w700, fontSize: dense ? 16 : 17, 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: EdgeInsets.only(bottom: dense ? 3 : 4), child: _NavItem( icon: item.icon, label: item.label, active: current == item.view, dense: dense, 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, this.dense = true}); final IconData icon; final String label; final bool active; final VoidCallback onTap; final bool dense; @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: ConstrainedBox( constraints: BoxConstraints(minHeight: dense ? 0 : 48), child: Padding( padding: EdgeInsets.symmetric(horizontal: dense ? 12 : 14, vertical: dense ? 9 : 13), child: Row(children: [ Icon(icon, size: dense ? 18 : 20, color: active ? c.accent : c.fg3), SizedBox(width: dense ? 11 : 12), Text(label, style: PangolinText.sm.copyWith( color: active ? c.accent : c.fg2, fontSize: dense ? 13.5 : 15, fontWeight: active ? (dense ? FontWeight.w600 : FontWeight.w700) : FontWeight.w500)), ]), ), ), ), ); } }