feat: 进行功能分区方便后期维护

- 添加导航条目和分类数据模型
- 实现导航卡片网格展示
- 支持点击卡片打开链接
- 添加主题样式(渐变色、卡片阴影)
- 区分系统默认和自定义条目
- 添加分类统计信息"
This commit is contained in:
2026-09-13 22:49:02 +08:00
parent 4075519075
commit e2cc3ac30f
40 changed files with 3379 additions and 515 deletions
@@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import '../../../../core/constants/app_sizes.dart';
import '../../../../core/theme/app_colors.dart';
import 'link_search_field.dart';
/// 顶部控制栏:折叠按钮 + 搜索框。
///
/// 对应 `index3.html` 的 `.top-bar`:整体宽 750px 并且**水平居中**
/// (`margin: 0 auto 36px auto`),下方与第一组卡片留 36px。
class TopBar extends StatelessWidget {
const TopBar({
super.key,
required this.searchController,
required this.searchHint,
required this.sidebarCollapsed,
required this.onToggleSidebar,
});
/// 搜索框控制器。
final TextEditingController searchController;
/// 搜索框占位文案。
final String searchHint;
/// 侧栏当前是否折叠,用于按钮的提示文案。
final bool sidebarCollapsed;
/// 折叠 / 展开侧栏。
final VoidCallback onToggleSidebar;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: AppSizes.topBarMarginBottom),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: AppSizes.topBarMaxWidth,
),
child: Row(
children: <Widget>[
_ToggleButton(
collapsed: sidebarCollapsed,
onTap: onToggleSidebar,
),
const SizedBox(width: AppSizes.topBarGap),
Expanded(
child: LinkSearchField(
controller: searchController,
hintText: searchHint,
),
),
],
),
),
),
);
}
}
/// 折叠按钮(`.toggle-btn`)。
class _ToggleButton extends StatefulWidget {
const _ToggleButton({required this.collapsed, required this.onTap});
final bool collapsed;
final VoidCallback onTap;
@override
State<_ToggleButton> createState() => _ToggleButtonState();
}
class _ToggleButtonState extends State<_ToggleButton> {
bool _hovered = false;
@override
Widget build(BuildContext context) {
final Color foreground = _hovered
? AppColors.primary
: AppColors.textSecondary;
return Tooltip(
// 原型写的是 title="展开/折叠侧边栏",文案固定。
message: '展开/折叠侧边栏',
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) => setState(() => _hovered = true),
onExit: (_) => setState(() => _hovered = false),
child: GestureDetector(
onTap: widget.onTap,
child: AnimatedContainer(
duration: AppSizes.transition,
// `.toggle-btn { transition: all 0.2s }`。
curve: Curves.ease,
width: AppSizes.toggleButtonSize,
height: AppSizes.toggleButtonSize,
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColors.surface,
border: Border.all(
color: _hovered ? AppColors.primary : AppColors.border,
),
borderRadius: BorderRadius.circular(AppSizes.toggleButtonRadius),
boxShadow: AppColors.cardShadow,
),
// 原型这里就是一个 ☰ 字符(font-size: 18px)。
child: Text(
'☰',
style: TextStyle(fontSize: 18, color: foreground),
),
),
),
),
);
}
}