feat: 进行功能分区方便后期维护
- 添加导航条目和分类数据模型 - 实现导航卡片网格展示 - 支持点击卡片打开链接 - 添加主题样式(渐变色、卡片阴影) - 区分系统默认和自定义条目 - 添加分类统计信息"
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import 'package:flutter/material.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';
|
||||
|
||||
/// 站点卡片,对应 `index.html` 里的 `.card`。
|
||||
///
|
||||
/// 结构是「36px 的字母方块 + 名称 + 描述」,悬停时上移 2px 并加强阴影。
|
||||
class LinkCard extends StatefulWidget {
|
||||
const LinkCard({super.key, required this.item, required this.onOpen});
|
||||
|
||||
/// 站点数据。
|
||||
final LinkItem item;
|
||||
|
||||
/// 打开回调。
|
||||
final VoidCallback onOpen;
|
||||
|
||||
@override
|
||||
State<LinkCard> createState() => _LinkCardState();
|
||||
}
|
||||
|
||||
class _LinkCardState extends State<LinkCard> {
|
||||
bool _hovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onOpen,
|
||||
child: AnimatedContainer(
|
||||
duration: AppSizes.transition,
|
||||
// `.card { transition: transform .2s, box-shadow .2s }`。
|
||||
curve: Curves.ease,
|
||||
transform: Matrix4.translationValues(
|
||||
0,
|
||||
_hovered ? -AppSizes.cardHoverLift : 0,
|
||||
0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSizes.cardPaddingHorizontal,
|
||||
vertical: AppSizes.cardPaddingVertical,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
border: Border.all(color: AppColors.border),
|
||||
borderRadius: BorderRadius.circular(AppSizes.cardRadius),
|
||||
boxShadow: _hovered
|
||||
? AppColors.cardShadowHover
|
||||
: AppColors.cardShadow,
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
_CardIcon(initial: widget.item.initial),
|
||||
const SizedBox(width: AppSizes.cardIconGap),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
widget.item.title,
|
||||
style: AppTextStyles.cardTitle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: AppSizes.cardTitleGap),
|
||||
Text(
|
||||
widget.item.description,
|
||||
style: AppTextStyles.cardDesc,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 卡片左侧的字母方块(`.card-icon`)。
|
||||
class _CardIcon extends StatelessWidget {
|
||||
const _CardIcon({required this.initial});
|
||||
|
||||
final String initial;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: AppSizes.cardIconSize,
|
||||
height: AppSizes.cardIconSize,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.iconSurface,
|
||||
borderRadius: BorderRadius.circular(AppSizes.cardIconRadius),
|
||||
),
|
||||
child: Text(initial, style: AppTextStyles.cardIcon),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user