Added theme components. Reorganized them. Prepping for Tech Tracker Rewrite

This commit is contained in:
2025-03-04 16:55:45 -06:00
parent fb577e81db
commit 4775917db0
20 changed files with 595 additions and 72 deletions

View 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;

View 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;

View 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;

View 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;

View 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;