- 添加导航条目和分类数据模型 - 实现导航卡片网格展示 - 支持点击卡片打开链接 - 添加主题样式(渐变色、卡片阴影) - 区分系统默认和自定义条目 - 添加分类统计信息"
94 lines
2.8 KiB
Dart
94 lines
2.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../../core/constants/app_breakpoints.dart';
|
|
import '../../../../core/constants/app_sizes.dart';
|
|
import '../../../../core/theme/app_colors.dart';
|
|
import '../../../../core/theme/app_text_styles.dart';
|
|
import '../../domain/models/link_item.dart';
|
|
import '../../domain/models/link_section.dart';
|
|
import 'link_card.dart';
|
|
|
|
/// 一个分组:标题 + 自适应网格。
|
|
class LinkSectionView extends StatelessWidget {
|
|
const LinkSectionView({
|
|
super.key,
|
|
required this.section,
|
|
required this.onOpen,
|
|
});
|
|
|
|
/// 分组数据。
|
|
final LinkSection section;
|
|
|
|
/// 打开某个站点。
|
|
final ValueChanged<LinkItem> onOpen;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: <Widget>[
|
|
_SectionTitle(title: section.title),
|
|
const SizedBox(height: AppSizes.sectionTitleGap),
|
|
LayoutBuilder(
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
final int columns = AppBreakpoints.gridColumnsFor(
|
|
constraints.maxWidth,
|
|
minItemWidth: AppSizes.gridMinItemWidth,
|
|
gap: AppSizes.gridGap,
|
|
);
|
|
final double itemWidth =
|
|
(constraints.maxWidth - AppSizes.gridGap * (columns - 1)) /
|
|
columns;
|
|
|
|
return Wrap(
|
|
spacing: AppSizes.gridGap,
|
|
runSpacing: AppSizes.gridGap,
|
|
children: <Widget>[
|
|
for (final LinkItem item in section.items)
|
|
SizedBox(
|
|
width: itemWidth,
|
|
child: LinkCard(item: item, onOpen: () => onOpen(item)),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 分组标题:左侧一条 4×16 的主色竖条 + 文字(`.section-title::before`)。
|
|
class _SectionTitle extends StatelessWidget {
|
|
const _SectionTitle({required this.title});
|
|
|
|
final String title;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
children: <Widget>[
|
|
Container(
|
|
width: AppSizes.sectionAccentWidth,
|
|
height: AppSizes.sectionAccentHeight,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.primary,
|
|
borderRadius: BorderRadius.circular(AppSizes.sectionAccentRadius),
|
|
),
|
|
),
|
|
const SizedBox(width: AppSizes.sectionAccentGap),
|
|
// 用 Flexible 包住:窄屏(侧栏展开后主内容只剩一百多像素)时
|
|
// 「素材资源 - UI 设计」这类长标题会溢出,这里退化成省略号。
|
|
Flexible(
|
|
child: Text(
|
|
title,
|
|
style: AppTextStyles.sectionTitle,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|