diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
index 11ace04..8f91958 100644
--- a/app/(tabs)/index.tsx
+++ b/app/(tabs)/index.tsx
@@ -1,6 +1,6 @@
import { Image, StyleSheet, Platform } from 'react-native';
import ParallaxScrollView from '@/components/default/ParallaxScrollView';
-import { ThemedText, ThemedView } from '@/components/theme/Theme';
+import { ThemedText, ThemedView } from '@/components/theme';
const HomeScreen = () => {
return (
diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx
index 406376e..c4545fc 100644
--- a/app/(tabs)/settings.tsx
+++ b/app/(tabs)/settings.tsx
@@ -2,7 +2,7 @@ import { StyleSheet, Image, Platform } from 'react-native';
import { Collapsible } from '@/components/default/Collapsible';
import { ExternalLink } from '@/components/default/ExternalLink';
import ParallaxScrollView from '@/components/default/ParallaxScrollView';
-import { ThemedText, ThemedView } from '@/components/theme/Theme';
+import { ThemedText, ThemedView } from '@/components/theme';
import { IconSymbol } from '@/components/ui/IconSymbol';
const TabTwoScreen = () => {
diff --git a/app/+not-found.tsx b/app/+not-found.tsx
index 59a6497..09d8c08 100644
--- a/app/+not-found.tsx
+++ b/app/+not-found.tsx
@@ -1,7 +1,6 @@
import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
-import { ThemedText, ThemedView } from '@/components/theme/Theme';
-import TextButton from '@/components/theme/buttons/TextButton';
+import { ThemedText, ThemedTextButton, ThemedView } from '@/components/theme';
const NotFoundScreen = () => {
return (
@@ -10,7 +9,7 @@ const NotFoundScreen = () => {
This screen doesn't exist.
-
+
>
diff --git a/components/default/Collapsible.tsx b/components/default/Collapsible.tsx
index 90219fb..47a2b8d 100644
--- a/components/default/Collapsible.tsx
+++ b/components/default/Collapsible.tsx
@@ -1,6 +1,6 @@
import { PropsWithChildren, useState } from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
-import { ThemedText, ThemedView } from '@/components/theme/Theme';
+import { ThemedText, ThemedView } from '@/components/theme';
import { IconSymbol } from '@/components/ui/IconSymbol';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
diff --git a/components/default/ParallaxScrollView.tsx b/components/default/ParallaxScrollView.tsx
index 2af4f0a..bbc8acf 100644
--- a/components/default/ParallaxScrollView.tsx
+++ b/components/default/ParallaxScrollView.tsx
@@ -6,7 +6,7 @@ import Animated, {
useAnimatedStyle,
useScrollViewOffset,
} from 'react-native-reanimated';
-import { ThemedView } from '@/components/theme/Theme';
+import { ThemedView } from '@/components/theme';
import { useBottomTabOverflow } from '@/components/ui/TabBarBackground';
import { useColorScheme } from '@/hooks/useColorScheme';
diff --git a/components/theme/buttons/TextButton.tsx b/components/theme/buttons/TextButton.tsx
deleted file mode 100644
index 65490f5..0000000
--- a/components/theme/buttons/TextButton.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import Button from '@/components/theme/buttons/Button';
-import { ThemedText } from '@/components/theme/Theme';
-import { Colors } from '@/constants/Colors';
-import { useColorScheme } from '@/hooks/useColorScheme';
-
-const DEFAULT_FONT_SIZE = 16;
-
-type Props = {
- width?: number;
- height?: number;
- text: string;
- fontSize?: number;
- onPress?: () => void;
-};
-
-const TextButton = ({ width, height, text, fontSize, onPress }: Props) => {
- const scheme = useColorScheme() ?? 'dark';
- return (
-
- );
-};
-export default TextButton;
diff --git a/components/theme/buttons/Button.tsx b/components/theme/buttons/ThemedButton.tsx
similarity index 55%
rename from components/theme/buttons/Button.tsx
rename to components/theme/buttons/ThemedButton.tsx
index 46bf696..fc72cbf 100644
--- a/components/theme/buttons/Button.tsx
+++ b/components/theme/buttons/ThemedButton.tsx
@@ -1,25 +1,30 @@
-import { StyleSheet, Pressable } from 'react-native';
-import { ThemedView } from '@/components/theme/Theme';
+import React from 'react';
+import { StyleSheet, Pressable, PressableProps } from 'react-native';
+import { ThemedView } from '@/components/theme';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
-import { StyleProp, ViewStyle } from 'react-native';
const DEFAULT_WIDTH = 320;
const DEFAULT_HEIGHT = 68;
-type Props = {
+type ThemedButtonProps = PressableProps & {
width?: number;
height?: number;
- onPress?: () => void;
+ containerStyle?: object;
+ buttonStyle?: object;
};
-const Button = ({
+const ThemedButton: React.FC = ({
width,
height,
children,
- onPress,
-}: Props & React.ComponentProps) => {
+ containerStyle,
+ buttonStyle,
+ style,
+ ...restProps // This now includes onPress automatically
+}) => {
const scheme = useColorScheme() ?? 'dark';
+
return (
{children}
);
};
-export default Button;
+
+export default ThemedButton;
const styles = StyleSheet.create({
buttonContainer: {
diff --git a/components/theme/buttons/ThemedTextButton.tsx b/components/theme/buttons/ThemedTextButton.tsx
new file mode 100644
index 0000000..8c1e1cb
--- /dev/null
+++ b/components/theme/buttons/ThemedTextButton.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { TextStyle, PressableProps } from 'react-native';
+import { ThemedButton, ThemedText } from '@/components/theme';
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+const DEFAULT_FONT_SIZE = 16;
+
+// Extend ThemedButton props (which already extends PressableProps)
+type ThemedTextButtonProps = Omit & {
+ width?: number;
+ height?: number;
+ text: string;
+ fontSize?: number;
+ textStyle?: TextStyle;
+ containerStyle?: object;
+ buttonStyle?: object;
+};
+
+const ThemedTextButton: React.FC = ({
+ width,
+ height,
+ text,
+ fontSize,
+ textStyle,
+ containerStyle,
+ buttonStyle,
+ ...restProps // This includes onPress and all other Pressable props
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ return (
+
+
+ {text}
+
+
+ );
+};
+
+export default ThemedTextButton;
diff --git a/components/theme/Theme.tsx b/components/theme/default/ThemedText.tsx
similarity index 79%
rename from components/theme/Theme.tsx
rename to components/theme/default/ThemedText.tsx
index 0defec1..7aefcc1 100644
--- a/components/theme/Theme.tsx
+++ b/components/theme/default/ThemedText.tsx
@@ -1,4 +1,4 @@
-import { View, type ViewProps } from 'react-native';
+import { type ViewProps } from 'react-native';
import { Text, type TextProps, StyleSheet } from 'react-native';
import { useThemeColor } from '@/hooks/useThemeColor';
@@ -12,12 +12,7 @@ export type ThemedTextProps = TextProps & {
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
};
-export const ThemedView = ({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) => {
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
- return ;
-};
-
-export const ThemedText = ({
+const ThemedText = ({
style,
lightColor,
darkColor,
@@ -40,6 +35,7 @@ export const ThemedText = ({
/>
);
};
+export default ThemedText;
const styles = StyleSheet.create({
default: {
diff --git a/components/theme/default/ThemedView.tsx b/components/theme/default/ThemedView.tsx
new file mode 100644
index 0000000..411c581
--- /dev/null
+++ b/components/theme/default/ThemedView.tsx
@@ -0,0 +1,13 @@
+import { View, type ViewProps } from 'react-native';
+import { useThemeColor } from '@/hooks/useThemeColor';
+
+export type ThemedViewProps = ViewProps & {
+ lightColor?: string;
+ darkColor?: string;
+};
+
+const ThemedView = ({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) => {
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
+ return ;
+};
+export default ThemedView;
diff --git a/components/theme/index.tsx b/components/theme/index.tsx
new file mode 100644
index 0000000..526ecbd
--- /dev/null
+++ b/components/theme/index.tsx
@@ -0,0 +1,25 @@
+import ThemedText from '@/components/theme/default/ThemedText';
+import ThemedView from '@/components/theme/default/ThemedView';
+import ThemedButton from '@/components/theme/buttons/ThemedButton';
+import ThemedTextButton from '@/components/theme/buttons/ThemedTextButton';
+import ThemedTextInput from '@/components/theme/inputs/ThemedTextInput';
+import ThemedCard from '@/components/theme/ui/ThemedCard';
+import ThemedBadge from '@/components/theme/ui/ThemedBadge';
+import ThemedIcon from '@/components/theme/ui/ThemedIcon';
+import ThemedSwitch from '@/components/theme/inputs/ThemedSwitch';
+import ThemedAvatar from '@/components/theme/ui/ThemedAvatar';
+import ThemedSearchBar from '@/components/theme/inputs/ThemedSearchBar';
+
+export {
+ ThemedText,
+ ThemedView,
+ ThemedButton,
+ ThemedTextButton,
+ ThemedTextInput,
+ ThemedCard,
+ ThemedBadge,
+ ThemedIcon,
+ ThemedSwitch,
+ ThemedAvatar,
+ ThemedSearchBar,
+};
diff --git a/components/theme/inputs/ThemedSearchBar.tsx b/components/theme/inputs/ThemedSearchBar.tsx
new file mode 100644
index 0000000..22cf8c8
--- /dev/null
+++ b/components/theme/inputs/ThemedSearchBar.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { StyleSheet, ViewProps, View, DimensionValue } from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { ThemedTextInput } from '@/components/theme';
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+type ThemedSearchBarProps = ViewProps & {
+ placeholder?: string;
+ value: string;
+ onChangeText: (text: string) => void;
+ width?: DimensionValue;
+ height?: number;
+};
+
+const ThemedSearchBar: React.FC = ({
+ placeholder = 'Search',
+ value,
+ onChangeText,
+ width = '100%',
+ height = 40,
+ style,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ return (
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ icon: {
+ position: 'absolute',
+ zIndex: 1,
+ left: 15,
+ },
+ input: {
+ paddingLeft: 45,
+ },
+});
+
+export default ThemedSearchBar;
diff --git a/components/theme/inputs/ThemedSwitch.tsx b/components/theme/inputs/ThemedSwitch.tsx
new file mode 100644
index 0000000..90ed403
--- /dev/null
+++ b/components/theme/inputs/ThemedSwitch.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { Switch, SwitchProps } from 'react-native';
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+type ThemedSwitchProps = SwitchProps;
+
+const ThemedSwitch: React.FC = ({
+ ...props
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ return (
+
+ );
+};
+
+export default ThemedSwitch;
diff --git a/components/theme/inputs/ThemedTextInput.tsx b/components/theme/inputs/ThemedTextInput.tsx
new file mode 100644
index 0000000..69dc6a7
--- /dev/null
+++ b/components/theme/inputs/ThemedTextInput.tsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import { StyleSheet, TextInput, TextInputProps, DimensionValue } from 'react-native';
+import { ThemedView } from '@/components/theme';
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+const DEFAULT_WIDTH = 320;
+const DEFAULT_HEIGHT = 50;
+
+type ThemedTextInputProps = TextInputProps & {
+ width?: DimensionValue;
+ height?: DimensionValue
+ containerStyle?: object;
+};
+
+const ThemedTextInput: React.FC = ({
+ width = DEFAULT_WIDTH,
+ height = DEFAULT_HEIGHT,
+ containerStyle,
+ style,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ return (
+
+
+
+ );
+};
+
+export default ThemedTextInput;
+
+const styles = StyleSheet.create({
+ inputContainer: {
+ padding: 3,
+ borderRadius: 10,
+ },
+ input: {
+ width: '100%',
+ height: '100%',
+ borderRadius: 8,
+ paddingHorizontal: 15,
+ fontSize: 16,
+ },
+});
diff --git a/components/theme/ui/ThemedAvatar.tsx b/components/theme/ui/ThemedAvatar.tsx
new file mode 100644
index 0000000..86b2299
--- /dev/null
+++ b/components/theme/ui/ThemedAvatar.tsx
@@ -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 & {
+ size?: number;
+ source?: ImageProps['source'];
+ name?: string;
+ borderWidth?: number;
+ borderColor?: string;
+};
+
+const ThemedAvatar: React.FC = ({
+ 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 (
+
+ {source ? (
+
+ ) : (
+
+ {initials}
+
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ },
+});
+
+export default ThemedAvatar;
diff --git a/components/theme/ui/ThemedBadge.tsx b/components/theme/ui/ThemedBadge.tsx
new file mode 100644
index 0000000..167b2b7
--- /dev/null
+++ b/components/theme/ui/ThemedBadge.tsx
@@ -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 = ({
+ value,
+ size = 24,
+ color,
+ textColor,
+ style,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+ const badgeColor = color || Colors[scheme].tint;
+ const badgeTextColor = textColor || Colors[scheme].background;
+
+ return (
+
+
+ {value}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ badge: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ text: {
+ fontWeight: 'bold',
+ },
+});
+
+export default ThemedBadge;
diff --git a/components/theme/ui/ThemedCard.tsx b/components/theme/ui/ThemedCard.tsx
new file mode 100644
index 0000000..06e733d
--- /dev/null
+++ b/components/theme/ui/ThemedCard.tsx
@@ -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 = ({
+ width = '100%',
+ height,
+ padding = 16,
+ elevation = 3,
+ borderRadius = 12,
+ style,
+ children,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ return (
+
+ {children}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ card: {
+ overflow: 'hidden',
+ },
+});
+
+export default ThemedCard;
diff --git a/components/theme/ui/ThemedDivider.tsx b/components/theme/ui/ThemedDivider.tsx
new file mode 100644
index 0000000..8d30ce4
--- /dev/null
+++ b/components/theme/ui/ThemedDivider.tsx
@@ -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 = ({
+ orientation = 'horizontal',
+ thickness = 1,
+ length = '100%',
+ style,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+ const color = restProps.color || Colors[scheme].border;
+
+ return (
+
+ );
+};
+
+export default ThemedDivider;
diff --git a/components/theme/ui/ThemedIcon.tsx b/components/theme/ui/ThemedIcon.tsx
new file mode 100644
index 0000000..bf698f6
--- /dev/null
+++ b/components/theme/ui/ThemedIcon.tsx
@@ -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 = ({
+ name,
+ size = 24,
+ color,
+ style,
+ ...restProps
+}) => {
+ const scheme = useColorScheme() ?? 'dark';
+ const iconColor = color || Colors[scheme].text;
+
+ return (
+
+ );
+};
+
+export default ThemedIcon;
diff --git a/constants/Colors.ts b/constants/Colors.ts
index 14e6784..2c09e6d 100644
--- a/constants/Colors.ts
+++ b/constants/Colors.ts
@@ -1,26 +1,50 @@
-/**
- * Below are the colors that are used in the app. The colors are defined in the light and dark mode.
- * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
- */
-
-const tintColorLight = '#0a7ea4';
+// Dark mode colors
+const dark = '#2e2f3d';
const tintColorDark = '#fff';
+const iconColorDark = '#9BA1A6';
+
+// Light mode colors
+const light = '#ECEDEE';
+const tintColorLight = '#0a7ea4';
+const iconColorLight = '#687076';
export const Colors = {
light: {
- text: '#11181C',
- background: '#fff',
+ text: dark,
+ background: light,
tint: tintColorLight,
- icon: '#687076',
- tabIconDefault: '#687076',
+ icon: iconColorLight,
+ tabIconDefault: iconColorLight,
tabIconSelected: tintColorLight,
+
+ // New colors
+ card: '#ffffff',
+ border: '#d0d7de',
+ notification: '#f85149',
+ placeholder: '#8b949e',
+ inactive: '#afb8c1',
+ subtle: '#f6f8fa',
+ error: '#e5484d',
+ success: '#46954a',
+ warning: '#daaa3f'
},
dark: {
- text: '#ECEDEE',
- background: '#151718',
+ text: light,
+ background: dark,
tint: tintColorDark,
- icon: '#9BA1A6',
- tabIconDefault: '#9BA1A6',
+ icon: iconColorDark,
+ tabIconDefault: iconColorDark,
tabIconSelected: tintColorDark,
+
+ // New colors
+ card: '#3a3b4a',
+ border: '#444c56',
+ notification: '#ff6a69',
+ placeholder: '#636e7b',
+ inactive: '#4d5560',
+ subtle: '#272934',
+ error: '#ff6369',
+ success: '#3fb950',
+ warning: '#d29922'
},
};