Added theme components. Reorganized them. Prepping for Tech Tracker Rewrite
This commit is contained in:
84
components/theme/ui/ThemedAvatar.tsx
Normal file
84
components/theme/ui/ThemedAvatar.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Image, ImageProps, View } from 'react-native';
|
||||
import { ThemedText } from '@/components/theme';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
|
||||
type ThemedAvatarProps = Omit<ImageProps, 'source'> & {
|
||||
size?: number;
|
||||
source?: ImageProps['source'];
|
||||
name?: string;
|
||||
borderWidth?: number;
|
||||
borderColor?: string;
|
||||
};
|
||||
|
||||
const ThemedAvatar: React.FC<ThemedAvatarProps> = ({
|
||||
size = 50,
|
||||
source,
|
||||
name,
|
||||
borderWidth = 0,
|
||||
borderColor,
|
||||
style,
|
||||
...restProps
|
||||
}) => {
|
||||
const scheme = useColorScheme() ?? 'dark';
|
||||
const border = borderColor || Colors[scheme].tint;
|
||||
|
||||
// Get initials from name
|
||||
const getInitials = (name?: string) => {
|
||||
if (!name) return '';
|
||||
return name
|
||||
.split(' ')
|
||||
.map(part => part[0])
|
||||
.join('')
|
||||
.toUpperCase()
|
||||
.substring(0, 2);
|
||||
};
|
||||
|
||||
const initials = getInitials(name);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: size / 2,
|
||||
borderWidth,
|
||||
borderColor: border,
|
||||
backgroundColor: source ? 'transparent' : Colors[scheme].tint,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{source ? (
|
||||
<Image
|
||||
source={source}
|
||||
style={[
|
||||
{
|
||||
width: size - 2 * borderWidth,
|
||||
height: size - 2 * borderWidth,
|
||||
borderRadius: (size - 2 * borderWidth) / 2,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
{...restProps}
|
||||
/>
|
||||
) : (
|
||||
<ThemedText style={{ color: Colors[scheme].background, fontSize: size * 0.4 }}>
|
||||
{initials}
|
||||
</ThemedText>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
});
|
||||
|
||||
export default ThemedAvatar;
|
62
components/theme/ui/ThemedBadge.tsx
Normal file
62
components/theme/ui/ThemedBadge.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, ViewProps } from 'react-native';
|
||||
import { ThemedView, ThemedText } from '@/components/theme';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
|
||||
type ThemedBadgeProps = ViewProps & {
|
||||
value: number | string;
|
||||
size?: number;
|
||||
color?: string;
|
||||
textColor?: string;
|
||||
};
|
||||
|
||||
const ThemedBadge: React.FC<ThemedBadgeProps> = ({
|
||||
value,
|
||||
size = 24,
|
||||
color,
|
||||
textColor,
|
||||
style,
|
||||
...restProps
|
||||
}) => {
|
||||
const scheme = useColorScheme() ?? 'dark';
|
||||
const badgeColor = color || Colors[scheme].tint;
|
||||
const badgeTextColor = textColor || Colors[scheme].background;
|
||||
|
||||
return (
|
||||
<ThemedView
|
||||
style={[
|
||||
styles.badge,
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: size / 2,
|
||||
backgroundColor: badgeColor,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
{...restProps}
|
||||
>
|
||||
<ThemedText
|
||||
style={[
|
||||
styles.text,
|
||||
{ color: badgeTextColor, fontSize: size * 0.5 }
|
||||
]}
|
||||
>
|
||||
{value}
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
badge: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
|
||||
export default ThemedBadge;
|
64
components/theme/ui/ThemedCard.tsx
Normal file
64
components/theme/ui/ThemedCard.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, ViewProps, Platform, DimensionValue } from 'react-native';
|
||||
import { ThemedView } from '@/components/theme';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
|
||||
type ThemedCardProps = ViewProps & {
|
||||
width?: DimensionValue;
|
||||
height?: DimensionValue;
|
||||
padding?: number;
|
||||
elevation?: number;
|
||||
borderRadius?: number;
|
||||
};
|
||||
|
||||
const ThemedCard: React.FC<ThemedCardProps> = ({
|
||||
width = '100%',
|
||||
height,
|
||||
padding = 16,
|
||||
elevation = 3,
|
||||
borderRadius = 12,
|
||||
style,
|
||||
children,
|
||||
...restProps
|
||||
}) => {
|
||||
const scheme = useColorScheme() ?? 'dark';
|
||||
|
||||
return (
|
||||
<ThemedView
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
width,
|
||||
height,
|
||||
padding,
|
||||
borderRadius,
|
||||
backgroundColor: Colors[scheme].card,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
shadowColor: Colors[scheme].text,
|
||||
shadowOffset: { width: 0, height: elevation/2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: elevation,
|
||||
},
|
||||
android: {
|
||||
elevation,
|
||||
},
|
||||
}),
|
||||
},
|
||||
style,
|
||||
]}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</ThemedView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
});
|
||||
|
||||
export default ThemedCard;
|
37
components/theme/ui/ThemedDivider.tsx
Normal file
37
components/theme/ui/ThemedDivider.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, ViewProps, View, DimensionValue } from 'react-native';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
|
||||
type ThemedDividerProps = ViewProps & {
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
thickness?: DimensionValue
|
||||
length?: DimensionValue
|
||||
color?: string;
|
||||
};
|
||||
|
||||
const ThemedDivider: React.FC<ThemedDividerProps> = ({
|
||||
orientation = 'horizontal',
|
||||
thickness = 1,
|
||||
length = '100%',
|
||||
style,
|
||||
...restProps
|
||||
}) => {
|
||||
const scheme = useColorScheme() ?? 'dark';
|
||||
const color = restProps.color || Colors[scheme].border;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
orientation === 'horizontal'
|
||||
? { height: thickness, width: length }
|
||||
: { width: thickness, height: length },
|
||||
{ backgroundColor: color },
|
||||
style,
|
||||
]}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemedDivider;
|
34
components/theme/ui/ThemedIcon.tsx
Normal file
34
components/theme/ui/ThemedIcon.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, ViewProps } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons'; // Or your preferred icon library
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
|
||||
type ThemedIconProps = ViewProps & {
|
||||
name: string;
|
||||
size?: number;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
const ThemedIcon: React.FC<ThemedIconProps> = ({
|
||||
name,
|
||||
size = 24,
|
||||
color,
|
||||
style,
|
||||
...restProps
|
||||
}) => {
|
||||
const scheme = useColorScheme() ?? 'dark';
|
||||
const iconColor = color || Colors[scheme].text;
|
||||
|
||||
return (
|
||||
<Ionicons
|
||||
name={name}
|
||||
size={size}
|
||||
color={iconColor}
|
||||
style={style}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemedIcon;
|
Reference in New Issue
Block a user