feat(Theme): enhance theming and UI consistency across components
- Updated app.json to set userInterfaceStyle to automatic for improved theme adaptability. - Refactored layout components to utilize useAppColors for dynamic theming, ensuring consistent color usage. - Introduced SystemChrome component to manage system UI background color based on theme. - Enhanced TabsLayout, ProfileStackLayout, and other components to leverage new theming structure. - Improved QRCodeScanner, SearchBar, and CommentItem styles to align with the updated theme system. - Consolidated styles in SystemMessageItem and TabBar for better maintainability and visual coherence.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* 支持多种变体、尺寸、加载状态和图标
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
TouchableOpacity,
|
||||
ActivityIndicator,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
TextStyle,
|
||||
} from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { colors, borderRadius, spacing, fontSizes, shadows } from '../../theme';
|
||||
import { borderRadius, spacing, fontSizes, useAppColors, type AppColors } from '../../theme';
|
||||
import Text from './Text';
|
||||
|
||||
type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'text' | 'danger';
|
||||
@@ -27,12 +27,86 @@ interface ButtonProps {
|
||||
size?: ButtonSize;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
icon?: string; // MaterialCommunityIcons name
|
||||
icon?: string;
|
||||
iconPosition?: IconPosition;
|
||||
fullWidth?: boolean;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
function createButtonStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
base: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
content: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
size_sm: {
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.md,
|
||||
minHeight: 32,
|
||||
},
|
||||
size_md: {
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
minHeight: 40,
|
||||
},
|
||||
size_lg: {
|
||||
paddingVertical: spacing.lg,
|
||||
paddingHorizontal: spacing.xl,
|
||||
minHeight: 48,
|
||||
},
|
||||
primary: {
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: colors.secondary.main,
|
||||
},
|
||||
outline: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.main,
|
||||
},
|
||||
text: {
|
||||
backgroundColor: 'transparent',
|
||||
shadowColor: 'transparent',
|
||||
elevation: 0,
|
||||
},
|
||||
danger: {
|
||||
backgroundColor: colors.error.main,
|
||||
},
|
||||
disabled: {
|
||||
backgroundColor: colors.background.disabled,
|
||||
borderColor: colors.background.disabled,
|
||||
},
|
||||
fullWidth: {
|
||||
width: '100%',
|
||||
},
|
||||
textBase: {
|
||||
fontWeight: '600',
|
||||
},
|
||||
textSize_sm: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
textSize_md: {
|
||||
fontSize: fontSizes.md,
|
||||
},
|
||||
textSize_lg: {
|
||||
fontSize: fontSizes.lg,
|
||||
},
|
||||
iconLeft: {
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
iconRight: {
|
||||
marginLeft: spacing.sm,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const Button: React.FC<ButtonProps> = ({
|
||||
title,
|
||||
onPress,
|
||||
@@ -45,11 +119,12 @@ const Button: React.FC<ButtonProps> = ({
|
||||
fullWidth = false,
|
||||
style,
|
||||
}) => {
|
||||
// 获取按钮样式
|
||||
const colors = useAppColors();
|
||||
const styles = useMemo(() => createButtonStyles(colors), [colors]);
|
||||
|
||||
const getButtonStyle = (): ViewStyle[] => {
|
||||
const baseStyle: ViewStyle[] = [styles.base, styles[`size_${size}`]];
|
||||
|
||||
// 变体样式
|
||||
switch (variant) {
|
||||
case 'primary':
|
||||
baseStyle.push(styles.primary);
|
||||
@@ -68,12 +143,10 @@ const Button: React.FC<ButtonProps> = ({
|
||||
break;
|
||||
}
|
||||
|
||||
// 禁用状态
|
||||
if (disabled || loading) {
|
||||
baseStyle.push(styles.disabled);
|
||||
}
|
||||
|
||||
// 全宽度
|
||||
if (fullWidth) {
|
||||
baseStyle.push(styles.fullWidth);
|
||||
}
|
||||
@@ -81,7 +154,6 @@ const Button: React.FC<ButtonProps> = ({
|
||||
return baseStyle;
|
||||
};
|
||||
|
||||
// 获取文本样式
|
||||
const getTextStyle = (): TextStyle => {
|
||||
const baseStyle: TextStyle = {
|
||||
...styles.textBase,
|
||||
@@ -109,7 +181,6 @@ const Button: React.FC<ButtonProps> = ({
|
||||
return baseStyle;
|
||||
};
|
||||
|
||||
// 获取图标大小
|
||||
const getIconSize = (): number => {
|
||||
switch (size) {
|
||||
case 'sm':
|
||||
@@ -121,7 +192,6 @@ const Button: React.FC<ButtonProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 获取图标颜色
|
||||
const getIconColor = (): string => {
|
||||
if (disabled || loading) {
|
||||
return colors.text.disabled;
|
||||
@@ -150,9 +220,9 @@ const Button: React.FC<ButtonProps> = ({
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={variant === 'outline' || variant === 'text'
|
||||
? colors.primary.main
|
||||
: colors.text.inverse}
|
||||
color={
|
||||
variant === 'outline' || variant === 'text' ? colors.primary.main : colors.text.inverse
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.content}>
|
||||
@@ -179,82 +249,4 @@ const Button: React.FC<ButtonProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
content: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
// 尺寸样式
|
||||
size_sm: {
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.md,
|
||||
minHeight: 32,
|
||||
},
|
||||
size_md: {
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
minHeight: 40,
|
||||
},
|
||||
size_lg: {
|
||||
paddingVertical: spacing.lg,
|
||||
paddingHorizontal: spacing.xl,
|
||||
minHeight: 48,
|
||||
},
|
||||
// 变体样式
|
||||
primary: {
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: colors.secondary.main,
|
||||
},
|
||||
outline: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.main,
|
||||
},
|
||||
text: {
|
||||
backgroundColor: 'transparent',
|
||||
shadowColor: 'transparent',
|
||||
elevation: 0,
|
||||
},
|
||||
danger: {
|
||||
backgroundColor: colors.error.main,
|
||||
},
|
||||
// 禁用状态
|
||||
disabled: {
|
||||
backgroundColor: colors.background.disabled,
|
||||
borderColor: colors.background.disabled,
|
||||
},
|
||||
// 全宽度
|
||||
fullWidth: {
|
||||
width: '100%',
|
||||
},
|
||||
// 文本样式
|
||||
textBase: {
|
||||
fontWeight: '600',
|
||||
},
|
||||
textSize_sm: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
textSize_md: {
|
||||
fontSize: fontSizes.md,
|
||||
},
|
||||
textSize_lg: {
|
||||
fontSize: fontSizes.lg,
|
||||
},
|
||||
// 图标样式
|
||||
iconLeft: {
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
iconRight: {
|
||||
marginLeft: spacing.sm,
|
||||
},
|
||||
});
|
||||
|
||||
export default Button;
|
||||
|
||||
Reference in New Issue
Block a user