Files
Navius/frontend/lib/features/home/presentation/widgets/link_search_field.dart
T
CNWei e2cc3ac30f feat: 进行功能分区方便后期维护
- 添加导航条目和分类数据模型
- 实现导航卡片网格展示
- 支持点击卡片打开链接
- 添加主题样式(渐变色、卡片阴影)
- 区分系统默认和自定义条目
- 添加分类统计信息"
2026-09-13 22:49:02 +08:00

98 lines
2.8 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.
import 'package:flutter/material.dart';
import '../../../../core/constants/app_sizes.dart';
import '../../../../core/theme/app_colors.dart';
import '../../../../core/theme/app_text_styles.dart';
/// 搜索框。
///
/// 对应 `index3.html` 的 `.search-box`:固定 44px 高、白色底、1px 描边、
/// 12px 圆角,聚焦时边框变主色并外扩 3px 的浅色光晕。
///
/// 用 [FocusNode] 而不是 `InputDecoration` 的 `focusedBorder`:
/// 那条光晕是「向外扩散」的矩形阴影,靠边框宽度画不出来。
class LinkSearchField extends StatefulWidget {
const LinkSearchField({
super.key,
required this.controller,
required this.hintText,
});
/// 文本控制器。
final TextEditingController controller;
/// 占位文案。
final String hintText;
@override
State<LinkSearchField> createState() => _LinkSearchFieldState();
}
class _LinkSearchFieldState extends State<LinkSearchField> {
final FocusNode _focusNode = FocusNode();
bool _focused = false;
@override
void initState() {
super.initState();
_focusNode.addListener(_handleFocusChange);
}
@override
void dispose() {
_focusNode
..removeListener(_handleFocusChange)
..dispose();
super.dispose();
}
void _handleFocusChange() {
if (_focusNode.hasFocus != _focused) {
setState(() => _focused = _focusNode.hasFocus);
}
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: AppSizes.transition,
// `.search-box { transition: border-color .2s, box-shadow .2s }`。
curve: Curves.ease,
height: AppSizes.searchHeight,
padding: const EdgeInsets.symmetric(
horizontal: AppSizes.searchPaddingHorizontal,
),
decoration: BoxDecoration(
color: AppColors.surface,
border: Border.all(
color: _focused ? AppColors.primary : AppColors.border,
),
borderRadius: BorderRadius.circular(AppSizes.searchRadius),
// 原型 `.search-box:focus` 的 box-shadow 会整体覆盖掉默认阴影,
// 聚焦时只剩这一圈光晕,不是「默认阴影 + 光晕」。
boxShadow: <BoxShadow>[
if (_focused)
const BoxShadow(color: AppColors.focusRing, spreadRadius: 3)
else
...AppColors.cardShadow,
],
),
child: TextField(
controller: widget.controller,
focusNode: _focusNode,
style: AppTextStyles.searchInput,
cursorColor: AppColors.primary,
textAlignVertical: TextAlignVertical.center,
textInputAction: TextInputAction.search,
decoration: InputDecoration(
isDense: true,
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
hintText: widget.hintText,
hintStyle: AppTextStyles.searchHint,
),
),
);
}
}