Files
frontend/src/components/business/SearchBar.tsx
lan ea9e51b0b0
All checks were successful
Frontend CI / ota-ios (push) Successful in 1m33s
Frontend CI / ota-android (push) Successful in 1m34s
Frontend CI / build-and-push-web (push) Successful in 2m31s
Frontend CI / build-android-apk (push) Successful in 1h2m56s
feat(ui): implement keyword highlighting and improve search experience
- Add keyword highlighting in `PostCard` and `PostContentRenderer` using `HighlightText`.
- Implement smart excerpt logic in `PostCard` to show relevant context around search keywords.
- Update `SearchBar` styles for better visual feedback and consistency.
- Enhance `SearchScreen` with modern tab variants and improved tag styling.
- Add support for updating group descriptions in `GroupInfoScreen` and `GroupService`.
- Refactor various UI components for improved layout stability and typography.
2026-05-07 01:08:58 +08:00

132 lines
3.6 KiB
TypeScript

/**
* SearchBar 搜索栏组件
* 用于搜索内容
*/
import React, { useMemo, useState } from 'react';
import { View, TextInput, TouchableOpacity, StyleSheet } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
interface SearchBarProps {
value: string;
onChangeText: (text: string) => void;
onSubmit: () => void;
placeholder?: string;
onFocus?: () => void;
onBlur?: () => void;
autoFocus?: boolean;
compact?: boolean;
}
function createSearchBarStyles(colors: AppColors, compact: boolean) {
return StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: `${colors.primary.main}08`,
borderRadius: borderRadius.full,
paddingHorizontal: compact ? spacing.sm : spacing.md,
height: compact ? 38 : 48,
borderWidth: 1.5,
borderColor: 'transparent',
},
containerFocused: {
borderColor: `${colors.primary.main}50`,
backgroundColor: `${colors.primary.main}10`,
},
searchIconWrap: {
width: compact ? 22 : 32,
height: compact ? 22 : 32,
marginLeft: compact ? 2 : 0,
marginRight: compact ? 6 : spacing.sm,
borderRadius: borderRadius.full,
backgroundColor: 'transparent',
alignItems: 'center',
justifyContent: 'center',
},
searchIconWrapFocused: {
backgroundColor: 'transparent',
},
input: {
flex: 1,
fontSize: compact ? fontSizes.md : fontSizes.lg,
color: colors.text.primary,
paddingVertical: compact ? 0 : spacing.sm,
paddingHorizontal: compact ? 2 : 0,
fontWeight: '500',
},
clearButton: {
width: 22,
height: 22,
marginLeft: spacing.xs,
borderRadius: borderRadius.full,
backgroundColor: `${colors.text.secondary}20`,
alignItems: 'center',
justifyContent: 'center',
},
});
}
const SearchBar: React.FC<SearchBarProps> = ({
value,
onChangeText,
onSubmit,
placeholder = '搜索...',
onFocus,
onBlur,
autoFocus = false,
compact = false,
}) => {
const colors = useAppColors();
const styles = useMemo(() => createSearchBarStyles(colors, compact), [colors, compact]);
const [isFocused, setIsFocused] = useState(false);
const handleFocus = () => {
setIsFocused(true);
onFocus?.();
};
const handleBlur = () => {
setIsFocused(false);
onBlur?.();
};
return (
<View style={[styles.container, isFocused && styles.containerFocused]}>
<View style={[styles.searchIconWrap, isFocused && styles.searchIconWrapFocused]}>
<MaterialCommunityIcons
name="magnify"
size={compact ? 16 : 18}
color={isFocused ? colors.primary.main : colors.text.secondary}
/>
</View>
<TextInput
style={styles.input}
value={value}
onChangeText={onChangeText}
placeholder={placeholder}
placeholderTextColor={colors.text.hint}
returnKeyType="search"
onSubmitEditing={onSubmit}
onFocus={handleFocus}
onBlur={handleBlur}
autoFocus={autoFocus}
cursorColor={colors.primary.main}
selectionColor={`${colors.primary.main}40`}
/>
{value.length > 0 && (
<TouchableOpacity
onPress={() => onChangeText('')}
style={styles.clearButton}
activeOpacity={0.7}
>
<MaterialCommunityIcons name="close" size={14} color={colors.text.secondary} />
</TouchableOpacity>
)}
</View>
);
};
export default SearchBar;