You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
5.6 KiB
262 lines
5.6 KiB
|
1 month ago
|
/**
|
||
|
|
* 主题样式工厂
|
||
|
|
*
|
||
|
|
* 提供创建主题感知样式的工具函数
|
||
|
|
*
|
||
|
|
* React Native 不支持 CSS 类名,但可以通过样式工厂函数实现类似效果
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { StyleSheet, TextStyle, ViewStyle } from 'react-native';
|
||
|
|
import Colors from '@/constants/Colors';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 主题样式类型
|
||
|
|
*/
|
||
|
|
export type ThemeStyles = {
|
||
|
|
light: any;
|
||
|
|
dark: any;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建主题样式
|
||
|
|
*
|
||
|
|
* 类似于 CSS 类名的概念,但使用函数式方法
|
||
|
|
*
|
||
|
|
* @param createStyles - 样式创建函数,接收颜色对象
|
||
|
|
* @returns 主题样式对象
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* const styles = createThemeStyles((colors) => ({
|
||
|
|
* container: {
|
||
|
|
* backgroundColor: colors.background,
|
||
|
|
* padding: 16,
|
||
|
|
* },
|
||
|
|
* text: {
|
||
|
|
* color: colors.text,
|
||
|
|
* fontSize: 16,
|
||
|
|
* },
|
||
|
|
* }));
|
||
|
|
*
|
||
|
|
* // 使用
|
||
|
|
* const theme = useColorScheme();
|
||
|
|
* <View style={styles[theme].container}>
|
||
|
|
* <Text style={styles[theme].text}>Hello</Text>
|
||
|
|
* </View>
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export function createThemeStyles<T extends StyleSheet.NamedStyles<T>>(
|
||
|
|
createStyles: (colors: typeof Colors.light) => T
|
||
|
|
): ThemeStyles {
|
||
|
|
return {
|
||
|
|
light: StyleSheet.create(createStyles(Colors.light)),
|
||
|
|
dark: StyleSheet.create(createStyles(Colors.dark)),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建响应式主题样式
|
||
|
|
*
|
||
|
|
* 允许为不同主题定义完全不同的样式
|
||
|
|
*
|
||
|
|
* @param lightStyles - 浅色主题样式
|
||
|
|
* @param darkStyles - 深色主题样式
|
||
|
|
* @returns 主题样式对象
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* const styles = createResponsiveThemeStyles(
|
||
|
|
* {
|
||
|
|
* container: { backgroundColor: '#fff', padding: 16 },
|
||
|
|
* text: { color: '#000', fontSize: 14 },
|
||
|
|
* },
|
||
|
|
* {
|
||
|
|
* container: { backgroundColor: '#000', padding: 20 },
|
||
|
|
* text: { color: '#fff', fontSize: 16 },
|
||
|
|
* }
|
||
|
|
* );
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export function createResponsiveThemeStyles<T extends StyleSheet.NamedStyles<T>>(
|
||
|
|
lightStyles: T,
|
||
|
|
darkStyles: T
|
||
|
|
): ThemeStyles {
|
||
|
|
return {
|
||
|
|
light: StyleSheet.create(lightStyles),
|
||
|
|
dark: StyleSheet.create(darkStyles),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 预定义的通用样式类
|
||
|
|
*
|
||
|
|
* 类似于 Tailwind CSS 的工具类
|
||
|
|
*/
|
||
|
|
export const commonStyles = createThemeStyles((colors) => ({
|
||
|
|
// 容器样式
|
||
|
|
container: {
|
||
|
|
flex: 1,
|
||
|
|
backgroundColor: colors.background,
|
||
|
|
},
|
||
|
|
containerPadded: {
|
||
|
|
flex: 1,
|
||
|
|
backgroundColor: colors.background,
|
||
|
|
padding: 16,
|
||
|
|
},
|
||
|
|
containerCentered: {
|
||
|
|
flex: 1,
|
||
|
|
backgroundColor: colors.background,
|
||
|
|
justifyContent: 'center',
|
||
|
|
alignItems: 'center',
|
||
|
|
},
|
||
|
|
|
||
|
|
// 卡片样式
|
||
|
|
card: {
|
||
|
|
backgroundColor: colors.card,
|
||
|
|
borderRadius: 8,
|
||
|
|
padding: 16,
|
||
|
|
borderWidth: 1,
|
||
|
|
borderColor: colors.border,
|
||
|
|
},
|
||
|
|
cardElevated: {
|
||
|
|
backgroundColor: colors.card,
|
||
|
|
borderRadius: 8,
|
||
|
|
padding: 16,
|
||
|
|
shadowColor: '#000',
|
||
|
|
shadowOffset: { width: 0, height: 2 },
|
||
|
|
shadowOpacity: 0.1,
|
||
|
|
shadowRadius: 4,
|
||
|
|
elevation: 3,
|
||
|
|
},
|
||
|
|
|
||
|
|
// 文本样式
|
||
|
|
textPrimary: {
|
||
|
|
color: colors.text,
|
||
|
|
fontSize: 16,
|
||
|
|
} as TextStyle,
|
||
|
|
textSecondary: {
|
||
|
|
color: colors.textSecondary,
|
||
|
|
fontSize: 14,
|
||
|
|
} as TextStyle,
|
||
|
|
textTertiary: {
|
||
|
|
color: colors.textTertiary,
|
||
|
|
fontSize: 12,
|
||
|
|
} as TextStyle,
|
||
|
|
textTitle: {
|
||
|
|
color: colors.text,
|
||
|
|
fontSize: 24,
|
||
|
|
fontWeight: 'bold',
|
||
|
|
} as TextStyle,
|
||
|
|
textSubtitle: {
|
||
|
|
color: colors.text,
|
||
|
|
fontSize: 18,
|
||
|
|
fontWeight: '600',
|
||
|
|
} as TextStyle,
|
||
|
|
|
||
|
|
// 按钮样式
|
||
|
|
button: {
|
||
|
|
backgroundColor: colors.buttonPrimary,
|
||
|
|
paddingVertical: 12,
|
||
|
|
paddingHorizontal: 24,
|
||
|
|
borderRadius: 8,
|
||
|
|
alignItems: 'center',
|
||
|
|
justifyContent: 'center',
|
||
|
|
} as ViewStyle,
|
||
|
|
buttonOutline: {
|
||
|
|
backgroundColor: 'transparent',
|
||
|
|
paddingVertical: 12,
|
||
|
|
paddingHorizontal: 24,
|
||
|
|
borderRadius: 8,
|
||
|
|
borderWidth: 1,
|
||
|
|
borderColor: colors.buttonPrimary,
|
||
|
|
alignItems: 'center',
|
||
|
|
justifyContent: 'center',
|
||
|
|
} as ViewStyle,
|
||
|
|
buttonText: {
|
||
|
|
color: '#FFFFFF',
|
||
|
|
fontSize: 16,
|
||
|
|
fontWeight: '600',
|
||
|
|
} as TextStyle,
|
||
|
|
buttonTextOutline: {
|
||
|
|
color: colors.buttonPrimary,
|
||
|
|
fontSize: 16,
|
||
|
|
fontWeight: '600',
|
||
|
|
} as TextStyle,
|
||
|
|
|
||
|
|
// 输入框样式
|
||
|
|
input: {
|
||
|
|
backgroundColor: colors.inputBackground,
|
||
|
|
borderWidth: 1,
|
||
|
|
borderColor: colors.inputBorder,
|
||
|
|
borderRadius: 8,
|
||
|
|
paddingVertical: 12,
|
||
|
|
paddingHorizontal: 16,
|
||
|
|
fontSize: 16,
|
||
|
|
color: colors.text,
|
||
|
|
} as TextStyle,
|
||
|
|
inputFocused: {
|
||
|
|
backgroundColor: colors.inputBackground,
|
||
|
|
borderWidth: 2,
|
||
|
|
borderColor: colors.primary,
|
||
|
|
borderRadius: 8,
|
||
|
|
paddingVertical: 12,
|
||
|
|
paddingHorizontal: 16,
|
||
|
|
fontSize: 16,
|
||
|
|
color: colors.text,
|
||
|
|
} as TextStyle,
|
||
|
|
|
||
|
|
// 分隔线
|
||
|
|
separator: {
|
||
|
|
height: 1,
|
||
|
|
backgroundColor: colors.separator,
|
||
|
|
} as ViewStyle,
|
||
|
|
separatorVertical: {
|
||
|
|
width: 1,
|
||
|
|
backgroundColor: colors.separator,
|
||
|
|
} as ViewStyle,
|
||
|
|
|
||
|
|
// 间距
|
||
|
|
spacingXs: { height: 4 } as ViewStyle,
|
||
|
|
spacingSm: { height: 8 } as ViewStyle,
|
||
|
|
spacingMd: { height: 16 } as ViewStyle,
|
||
|
|
spacingLg: { height: 24 } as ViewStyle,
|
||
|
|
spacingXl: { height: 32 } as ViewStyle,
|
||
|
|
|
||
|
|
// 布局
|
||
|
|
row: {
|
||
|
|
flexDirection: 'row',
|
||
|
|
alignItems: 'center',
|
||
|
|
} as ViewStyle,
|
||
|
|
rowBetween: {
|
||
|
|
flexDirection: 'row',
|
||
|
|
alignItems: 'center',
|
||
|
|
justifyContent: 'space-between',
|
||
|
|
} as ViewStyle,
|
||
|
|
column: {
|
||
|
|
flexDirection: 'column',
|
||
|
|
} as ViewStyle,
|
||
|
|
center: {
|
||
|
|
justifyContent: 'center',
|
||
|
|
alignItems: 'center',
|
||
|
|
} as ViewStyle,
|
||
|
|
}));
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取主题样式
|
||
|
|
*
|
||
|
|
* @param styles - 主题样式对象
|
||
|
|
* @param theme - 当前主题
|
||
|
|
* @returns 当前主题的样式
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* const theme = useColorScheme();
|
||
|
|
* const style = getThemeStyle(styles, theme);
|
||
|
|
* <View style={style.container} />
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export function getThemeStyle<T>(styles: ThemeStyles, theme: 'light' | 'dark'): T {
|
||
|
|
return styles[theme];
|
||
|
|
}
|
||
|
|
|