Files
pangolin/client/lib/widgets/nav_sidebar.dart
T
wangjia 322d806876 fix+build(client/windows): 复查修缮——一键构建脚本 + 修 README dart-define 漏项 + 清 lint
- 新增 client/windows/build.ps1:拉内核→带 --dart-define 构建→出安装包一键串联,
  规避 Release 漏 --dart-define 导致默认连 localhost、登录「网络请求失败」的坑。
- README:Release 命令补回 --dart-define 并加显式警告,指向一键脚本。
- 清 4 个 lint warning:desktop_vpn_bridge 多余 cast→pattern match、去多余非空断言;
  nav_sidebar 删未用 import;vpn_bridge_mock 加 killSwitchEnabled getter。
- 同步 window_manager/tray_manager/screen_retriever 插件注册生成文件(win+macos)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:17:13 +08:00

111 lines
3.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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<NavSidebarItem> 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)),
]),
),
),
),
);
}
}