|
|
|
|
/**
|
|
|
|
|
* 主题化组件
|
|
|
|
|
*
|
|
|
|
|
* 提供自动适配主题的 Text 和 View 组件
|
|
|
|
|
* 支持从 settingsStore 读取主题设置
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { Text as DefaultText, View as DefaultView, TextStyle } from 'react-native';
|
|
|
|
|
|
|
|
|
|
import Colors from '@/constants/Colors';
|
|
|
|
|
import { useColorScheme } from '@/hooks/useTheme';
|
|
|
|
|
|
|
|
|
|
type ThemeProps = {
|
|
|
|
|
lightColor?: string;
|
|
|
|
|
darkColor?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type TextProps = ThemeProps & DefaultText['props'];
|
|
|
|
|
export type ViewProps = ThemeProps & DefaultView['props'];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取主题颜色
|
|
|
|
|
*
|
|
|
|
|
* @param props - 包含 light 和 dark 颜色的对象
|
|
|
|
|
* @param colorName - Colors 中定义的颜色名称
|
|
|
|
|
* @returns 当前主题对应的颜色值
|
|
|
|
|
*/
|
|
|
|
|
export function useThemeColor(
|
|
|
|
|
props: { light?: string; dark?: string },
|
|
|
|
|
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
|
|
|
|
|
) {
|
|
|
|
|
const theme = useColorScheme() ?? 'light';
|
|
|
|
|
const colorFromProps = props[theme];
|
|
|
|
|
|
|
|
|
|
if (colorFromProps) {
|
|
|
|
|
return colorFromProps;
|
|
|
|
|
} else {
|
|
|
|
|
return Colors[theme][colorName];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主题化 Text 组件
|
|
|
|
|
*
|
|
|
|
|
* 自动应用当前主题的文本颜色
|
|
|
|
|
*/
|
|
|
|
|
export function Text(props: TextProps) {
|
|
|
|
|
const { style, lightColor, darkColor, ...otherProps } = props;
|
|
|
|
|
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
|
|
|
|
|
|
|
|
|
|
return <DefaultText style={[{ color }, style]} {...otherProps} />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主题化 View 组件
|
|
|
|
|
*
|
|
|
|
|
* 自动应用当前主题的背景颜色
|
|
|
|
|
*/
|
|
|
|
|
export function View(props: ViewProps) {
|
|
|
|
|
const { style, lightColor, darkColor, ...otherProps } = props;
|
|
|
|
|
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
|
|
|
|
|
|
|
|
|
|
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主题化 Text 组件(带类型)
|
|
|
|
|
*
|
|
|
|
|
* 支持不同的文本类型:title, subtitle, defaultSemiBold, link
|
|
|
|
|
*/
|
|
|
|
|
export type ThemedTextProps = TextProps & {
|
|
|
|
|
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function ThemedText({ style, type = 'default', ...rest }: ThemedTextProps) {
|
|
|
|
|
const color = useThemeColor({}, 'text');
|
|
|
|
|
const linkColor = useThemeColor({}, 'tint');
|
|
|
|
|
|
|
|
|
|
const typeStyles: Record<string, TextStyle> = {
|
|
|
|
|
default: {
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
lineHeight: 24,
|
|
|
|
|
},
|
|
|
|
|
defaultSemiBold: {
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
lineHeight: 24,
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
},
|
|
|
|
|
title: {
|
|
|
|
|
fontSize: 32,
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
lineHeight: 40,
|
|
|
|
|
},
|
|
|
|
|
subtitle: {
|
|
|
|
|
fontSize: 20,
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
lineHeight: 28,
|
|
|
|
|
},
|
|
|
|
|
link: {
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
lineHeight: 24,
|
|
|
|
|
color: linkColor,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Text
|
|
|
|
|
style={[
|
|
|
|
|
{ color },
|
|
|
|
|
typeStyles[type],
|
|
|
|
|
style,
|
|
|
|
|
]}
|
|
|
|
|
{...rest}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主题化 View 组件
|
|
|
|
|
*/
|
|
|
|
|
export type ThemedViewProps = ViewProps;
|
|
|
|
|
|
|
|
|
|
export function ThemedView({ style, ...otherProps }: ThemedViewProps) {
|
|
|
|
|
const backgroundColor = useThemeColor({}, 'background');
|
|
|
|
|
|
|
|
|
|
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
|
|
|
|
|
}
|