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'; /// 站点卡片,对应 `index3.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 createState() => _LinkCardState(); } class _LinkCardState extends State { 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: [ _CardIcon(initial: widget.item.initial), const SizedBox(width: AppSizes.cardIconGap), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ 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), ); } }