mirror of
https://github.com/DocNR/POWR.git
synced 2025-04-19 10:51:19 +00:00
minor ui update
This commit is contained in:
parent
af6a5c2683
commit
147ea582fc
Binary file not shown.
@ -3,26 +3,25 @@ import React from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
import { Tabs } from 'expo-router';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import { Dumbbell, Library, Users, History, User } from 'lucide-react-native';
|
||||
import { convertHSLValues } from '@/lib/theme';
|
||||
import { Dumbbell, Library, Users, History, User, } from 'lucide-react-native';
|
||||
import type { CustomTheme } from '@/lib/theme';
|
||||
|
||||
export default function TabLayout() {
|
||||
const { colors, dark } = useTheme();
|
||||
const { purple, mutedForeground } = convertHSLValues(dark ? 'dark' : 'light');
|
||||
const theme = useTheme() as CustomTheme;
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarStyle: {
|
||||
backgroundColor: colors.background,
|
||||
borderTopColor: colors.border,
|
||||
backgroundColor: theme.colors.background,
|
||||
borderTopColor: theme.colors.border,
|
||||
borderTopWidth: Platform.OS === 'ios' ? 0.5 : 1,
|
||||
elevation: 0,
|
||||
shadowOpacity: 0,
|
||||
},
|
||||
tabBarActiveTintColor: purple,
|
||||
tabBarInactiveTintColor: mutedForeground,
|
||||
tabBarActiveTintColor: theme.colors.tabActive,
|
||||
tabBarInactiveTintColor: theme.colors.tabInactive,
|
||||
tabBarShowLabel: true,
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 12,
|
||||
|
@ -1,11 +1,29 @@
|
||||
// app/(tabs)/history.tsx
|
||||
// app/(tabs)/history.tsx
|
||||
import { View } from 'react-native';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { TabScreen } from '@/components/layout/TabScreen';
|
||||
import Header from '@/components/Header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Filter } from 'lucide-react-native';
|
||||
|
||||
export default function HomeScreen() {
|
||||
export default function HistoryScreen() {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Home Screen</Text>
|
||||
</View>
|
||||
<TabScreen>
|
||||
<Header
|
||||
title="History"
|
||||
rightElement={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onPress={() => console.log('Open filters')}
|
||||
>
|
||||
<Filter className="text-foreground" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>History Screen</Text>
|
||||
</View>
|
||||
</TabScreen>
|
||||
);
|
||||
}
|
@ -1,11 +1,29 @@
|
||||
// app/(tabs)/index.tsx
|
||||
// app/(tabs)/index.tsx (Workout tab)
|
||||
import { View } from 'react-native';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { TabScreen } from '@/components/layout/TabScreen';
|
||||
import Header from '@/components/Header';
|
||||
import { Plus } from 'lucide-react-native';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export default function HomeScreen() {
|
||||
export default function WorkoutScreen() {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Home Screen</Text>
|
||||
</View>
|
||||
<TabScreen>
|
||||
<Header
|
||||
title="Workout"
|
||||
rightElement={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onPress={() => console.log('New workout')}
|
||||
>
|
||||
<Plus className="text-foreground" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Workout Screen</Text>
|
||||
</View>
|
||||
</TabScreen>
|
||||
);
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
// app/(tabs)/library/_layout.native.tsx
|
||||
import { View } from 'react-native';
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
import { SearchPopover } from '@/components/library/SearchPopover';
|
||||
import { FilterPopover } from '@/components/library/FilterPopover';
|
||||
import { FilterSheet, type FilterOptions, type SourceType } from '@/components/library/FilterSheet';
|
||||
import ExercisesScreen from './exercises';
|
||||
import TemplatesScreen from './templates';
|
||||
import ProgramsScreen from './programs';
|
||||
import Header from '@/components/Header';
|
||||
import { useState } from 'react';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import { convertHSLValues } from '@/lib/theme';
|
||||
|
||||
const Tab = createMaterialTopTabNavigator();
|
||||
|
||||
// Default available filters
|
||||
const availableFilters = {
|
||||
equipment: ['Barbell', 'Dumbbell', 'Bodyweight', 'Machine', 'Cables', 'Other'],
|
||||
tags: ['Strength', 'Cardio', 'Mobility', 'Recovery'],
|
||||
source: ['local', 'powr', 'nostr'] as SourceType[] // Fixed: Create mutable array of SourceType
|
||||
};
|
||||
|
||||
// Initial filter state
|
||||
const initialFilters: FilterOptions = {
|
||||
equipment: [],
|
||||
tags: [],
|
||||
source: []
|
||||
};
|
||||
|
||||
export default function LibraryLayout() {
|
||||
const { colors, dark } = useTheme();
|
||||
const { purple, mutedForeground } = convertHSLValues(dark ? 'dark' : 'light');
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [activeFilters, setActiveFilters] = useState(0);
|
||||
const [filterSheetOpen, setFilterSheetOpen] = useState(false);
|
||||
const [currentFilters, setCurrentFilters] = useState<FilterOptions>(initialFilters);
|
||||
|
||||
const handleApplyFilters = (filters: FilterOptions) => {
|
||||
setCurrentFilters(filters);
|
||||
// Count total active filters
|
||||
const totalFilters = Object.values(filters).reduce(
|
||||
(acc, curr) => acc + curr.length,
|
||||
0
|
||||
);
|
||||
setActiveFilters(totalFilters);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex-1">
|
||||
<Header
|
||||
title="Library"
|
||||
rightElement={
|
||||
<View className="flex-row items-center gap-2">
|
||||
<SearchPopover
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
/>
|
||||
<FilterPopover
|
||||
activeFilters={activeFilters}
|
||||
onOpenFilters={() => setFilterSheetOpen(true)}
|
||||
/>
|
||||
<ThemeToggle />
|
||||
</View>
|
||||
}
|
||||
>
|
||||
<Text className="text-muted-foreground text-sm mt-1">
|
||||
12 exercises • 5 templates
|
||||
</Text>
|
||||
</Header>
|
||||
|
||||
<FilterSheet
|
||||
isOpen={filterSheetOpen}
|
||||
onClose={() => setFilterSheetOpen(false)}
|
||||
options={currentFilters}
|
||||
onApplyFilters={handleApplyFilters}
|
||||
availableFilters={availableFilters}
|
||||
/>
|
||||
|
||||
<Tab.Navigator
|
||||
initialRouteName="templates"
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: purple,
|
||||
tabBarInactiveTintColor: mutedForeground,
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 14,
|
||||
textTransform: 'capitalize',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
tabBarIndicatorStyle: {
|
||||
backgroundColor: purple,
|
||||
height: 2,
|
||||
},
|
||||
tabBarStyle: {
|
||||
backgroundColor: colors.background,
|
||||
elevation: 0,
|
||||
shadowOpacity: 0,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.border,
|
||||
},
|
||||
tabBarPressColor: colors.primary,
|
||||
}}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="exercises"
|
||||
component={ExercisesScreen}
|
||||
options={{ title: 'Exercises' }}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="templates"
|
||||
component={TemplatesScreen}
|
||||
options={{ title: 'Templates' }}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="programs"
|
||||
component={ProgramsScreen}
|
||||
options={{ title: 'Programs' }}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
</View>
|
||||
);
|
||||
}
|
@ -1,3 +1,119 @@
|
||||
// app/(tabs)/library/_layout.tsx
|
||||
// This is the fallback layout that gets overridden by platform-specific files
|
||||
export { default } from './_layout.native';
|
||||
import { View } from 'react-native';
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
import { SearchPopover } from '@/components/library/SearchPopover';
|
||||
import { FilterPopover } from '@/components/library/FilterPopover';
|
||||
import { FilterSheet, type FilterOptions, type SourceType } from '@/components/library/FilterSheet';
|
||||
import ExercisesScreen from './exercises';
|
||||
import TemplatesScreen from './templates';
|
||||
import ProgramsScreen from './programs';
|
||||
import Header from '@/components/Header';
|
||||
import { useState } from 'react';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import type { CustomTheme } from '@/lib/theme';
|
||||
import { TabScreen } from '@/components/layout/TabScreen';
|
||||
|
||||
const Tab = createMaterialTopTabNavigator();
|
||||
|
||||
// Default available filters
|
||||
const availableFilters = {
|
||||
equipment: ['Barbell', 'Dumbbell', 'Bodyweight', 'Machine', 'Cables', 'Other'],
|
||||
tags: ['Strength', 'Cardio', 'Mobility', 'Recovery'],
|
||||
source: ['local', 'powr', 'nostr'] as SourceType[]
|
||||
};
|
||||
|
||||
// Initial filter state
|
||||
const initialFilters: FilterOptions = {
|
||||
equipment: [],
|
||||
tags: [],
|
||||
source: []
|
||||
};
|
||||
|
||||
export default function LibraryLayout() {
|
||||
const theme = useTheme() as CustomTheme;
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [activeFilters, setActiveFilters] = useState(0);
|
||||
const [filterSheetOpen, setFilterSheetOpen] = useState(false);
|
||||
const [currentFilters, setCurrentFilters] = useState<FilterOptions>(initialFilters);
|
||||
|
||||
const handleApplyFilters = (filters: FilterOptions) => {
|
||||
setCurrentFilters(filters);
|
||||
const totalFilters = Object.values(filters).reduce(
|
||||
(acc, curr) => acc + curr.length,
|
||||
0
|
||||
);
|
||||
setActiveFilters(totalFilters);
|
||||
};
|
||||
|
||||
return (
|
||||
<TabScreen>
|
||||
<Header
|
||||
title="Library"
|
||||
rightElement={
|
||||
<View className="flex-row items-center gap-2">
|
||||
<SearchPopover
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
/>
|
||||
<FilterPopover
|
||||
activeFilters={activeFilters}
|
||||
onOpenFilters={() => setFilterSheetOpen(true)}
|
||||
/>
|
||||
<ThemeToggle />
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
|
||||
<FilterSheet
|
||||
isOpen={filterSheetOpen}
|
||||
onClose={() => setFilterSheetOpen(false)}
|
||||
options={currentFilters}
|
||||
onApplyFilters={handleApplyFilters}
|
||||
availableFilters={availableFilters}
|
||||
/>
|
||||
|
||||
<Tab.Navigator
|
||||
initialRouteName="templates"
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: theme.colors.tabIndicator,
|
||||
tabBarInactiveTintColor: theme.colors.tabInactive,
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 14,
|
||||
textTransform: 'capitalize',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
tabBarIndicatorStyle: {
|
||||
backgroundColor: theme.colors.tabIndicator,
|
||||
height: 2,
|
||||
},
|
||||
tabBarStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
elevation: 0,
|
||||
shadowOpacity: 0,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.colors.border,
|
||||
},
|
||||
tabBarPressColor: theme.colors.primary,
|
||||
}}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="exercises"
|
||||
component={ExercisesScreen}
|
||||
options={{ title: 'Exercises' }}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="templates"
|
||||
component={TemplatesScreen}
|
||||
options={{ title: 'Templates' }}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="programs"
|
||||
component={ProgramsScreen}
|
||||
options={{ title: 'Programs' }}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
</TabScreen>
|
||||
);
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
// app/(tabs)/library/_layout.web.tsx
|
||||
import React from 'react';
|
||||
import { View, Pressable } from 'react-native';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
import Pager from '@/components/pager';
|
||||
import { CUSTOM_COLORS } from '@/lib/constants';
|
||||
import type { PagerRef } from '@/components/pager/types';
|
||||
import ExercisesScreen from './exercises';
|
||||
import TemplatesScreen from './templates';
|
||||
import ProgramsScreen from './programs';
|
||||
|
||||
const tabs = [
|
||||
{ key: 'exercises', title: 'Exercises', component: ExercisesScreen },
|
||||
{ key: 'templates', title: 'Templates', component: TemplatesScreen },
|
||||
{ key: 'programs', title: 'Programs', component: ProgramsScreen },
|
||||
];
|
||||
|
||||
export default function LibraryLayout() {
|
||||
const [activeIndex, setActiveIndex] = React.useState(0);
|
||||
const pagerRef = React.useRef<PagerRef>(null);
|
||||
|
||||
const handleTabPress = (index: number) => {
|
||||
setActiveIndex(index);
|
||||
pagerRef.current?.setPage(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex-1 bg-background">
|
||||
{/* Header */}
|
||||
<View className="flex-row justify-between items-center px-4 pt-14 pb-4 bg-card">
|
||||
<Text className="text-2xl font-bold">Library</Text>
|
||||
<ThemeToggle />
|
||||
</View>
|
||||
|
||||
{/* Tab Headers */}
|
||||
<View className="flex-row bg-card border-b border-border">
|
||||
{tabs.map((tab, index) => (
|
||||
<View key={tab.key} className="flex-1">
|
||||
<Pressable
|
||||
onPress={() => handleTabPress(index)}
|
||||
className="px-4 py-3 items-center"
|
||||
>
|
||||
<Text
|
||||
className={activeIndex === index
|
||||
? 'font-semibold text-primary'
|
||||
: 'font-semibold text-muted-foreground'}
|
||||
style={activeIndex === index ? { color: CUSTOM_COLORS.purple } : undefined}
|
||||
>
|
||||
{tab.title}
|
||||
</Text>
|
||||
</Pressable>
|
||||
{activeIndex === index && (
|
||||
<View
|
||||
className="h-0.5"
|
||||
style={{ backgroundColor: CUSTOM_COLORS.purple }}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Content */}
|
||||
<View style={{ flex: 1 }}>
|
||||
<Pager
|
||||
ref={pagerRef}
|
||||
initialPage={0}
|
||||
onPageSelected={(e) => setActiveIndex(e.nativeEvent.position)}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
{tabs.map((tab) => (
|
||||
<View key={tab.key} style={{ flex: 1 }}>
|
||||
<tab.component />
|
||||
</View>
|
||||
))}
|
||||
</Pager>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
// app/(tabs)/library/index.tsx
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, Platform } from 'react-native';
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
import ExercisesScreen from './exercises';
|
||||
|
||||
const Tab = createMaterialTopTabNavigator();
|
||||
|
||||
function TemplatesTab() {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Templates Content</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function ProgramsTab() {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Programs (Coming Soon)</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default function LibraryScreen() {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* Header with Theme Toggle */}
|
||||
<View style={[styles.header, { backgroundColor: colors.card }]}>
|
||||
<Text className="text-2xl font-bold">Library</Text>
|
||||
<ThemeToggle />
|
||||
</View>
|
||||
|
||||
{/* Material Top Tabs */}
|
||||
<Tab.Navigator
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: colors.text,
|
||||
tabBarInactiveTintColor: 'grey',
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 14,
|
||||
textTransform: 'capitalize',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
tabBarIndicatorStyle: {
|
||||
backgroundColor: colors.text,
|
||||
},
|
||||
tabBarStyle: { backgroundColor: colors.card },
|
||||
swipeEnabled: true, // Enable swipe navigation
|
||||
animationEnabled: true, // Enable animations when swiping
|
||||
lazy: true }}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="exercises"
|
||||
component={ExercisesScreen}
|
||||
options={{
|
||||
title: 'Exercises',
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="templates"
|
||||
component={TemplatesTab}
|
||||
options={{
|
||||
title: 'Templates',
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="programs"
|
||||
component={ProgramsTab}
|
||||
options={{
|
||||
title: 'Programs',
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: Platform.OS === 'ios' ? 60 : 16,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
});
|
@ -1,5 +1,4 @@
|
||||
// app/(tabs)/profile.tsx
|
||||
import React from 'react';
|
||||
import { View, ScrollView } from 'react-native';
|
||||
import { Settings } from 'lucide-react-native';
|
||||
import { H1 } from '@/components/ui/typography';
|
||||
@ -8,6 +7,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import Header from '@/components/Header';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { TabScreen } from '@/components/layout/TabScreen';
|
||||
|
||||
const PLACEHOLDER_IMAGE = 'https://github.com/shadcn.png';
|
||||
|
||||
@ -15,16 +15,14 @@ export default function ProfileScreen() {
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
return (
|
||||
<View className="flex-1">
|
||||
<TabScreen>
|
||||
<Header
|
||||
title="Profile"
|
||||
rightElement={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onPress={() => {
|
||||
console.log('Open settings');
|
||||
}}
|
||||
onPress={() => console.log('Open settings')}
|
||||
>
|
||||
<Settings className="text-foreground" />
|
||||
</Button>
|
||||
@ -37,7 +35,7 @@ export default function ProfileScreen() {
|
||||
paddingBottom: insets.bottom + 20
|
||||
}}
|
||||
>
|
||||
{/* Profile Header Section */}
|
||||
{/* Profile content remains the same */}
|
||||
<View className="items-center pt-6 pb-8">
|
||||
<Avatar className="w-24 h-24 mb-4" alt="Profile picture">
|
||||
<AvatarImage source={{ uri: PLACEHOLDER_IMAGE }} />
|
||||
@ -49,7 +47,6 @@ export default function ProfileScreen() {
|
||||
<Text className="text-muted-foreground">@johndoe</Text>
|
||||
</View>
|
||||
|
||||
{/* Stats Section */}
|
||||
<View className="flex-row justify-around px-4 py-6 bg-card">
|
||||
<View className="items-center">
|
||||
<Text className="text-2xl font-bold">24</Text>
|
||||
@ -65,39 +62,18 @@ export default function ProfileScreen() {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Profile Actions */}
|
||||
<View className="p-4 gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mb-2"
|
||||
onPress={() => {
|
||||
console.log('Edit profile');
|
||||
}}
|
||||
>
|
||||
<Button variant="outline" className="mb-2">
|
||||
<Text>Edit Profile</Text>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mb-2"
|
||||
onPress={() => {
|
||||
console.log('Account settings');
|
||||
}}
|
||||
>
|
||||
<Button variant="outline" className="mb-2">
|
||||
<Text>Account Settings</Text>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mb-2"
|
||||
onPress={() => {
|
||||
console.log('Preferences');
|
||||
}}
|
||||
>
|
||||
<Button variant="outline" className="mb-2">
|
||||
<Text>Preferences</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</TabScreen>
|
||||
);
|
||||
}
|
@ -1,25 +1,22 @@
|
||||
// app/(tabs)/index.tsx (and similar for other tab screens)
|
||||
// app/(tabs)/social.tsx
|
||||
import { View } from 'react-native';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Bell } from 'lucide-react-native';
|
||||
import Header from '@/components/Header';
|
||||
import { TabScreen } from '@/components/layout/TabScreen';
|
||||
|
||||
export default function SocialScreen() {
|
||||
return (
|
||||
<View className="flex-1">
|
||||
<TabScreen>
|
||||
<Header
|
||||
title="Social"
|
||||
rightElement={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onPress={() => {
|
||||
// TODO: Open notifications
|
||||
console.log('Open notifications');
|
||||
}}
|
||||
onPress={() => console.log('Open notifications')}
|
||||
>
|
||||
{/* Add a notification badge if needed */}
|
||||
<View className="relative">
|
||||
<Bell className="text-foreground" />
|
||||
<View className="absolute -top-1 -right-1 w-2 h-2 bg-primary rounded-full" />
|
||||
@ -27,6 +24,9 @@ export default function SocialScreen() {
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Text>Social Screen</Text>
|
||||
</View>
|
||||
</TabScreen>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// app/_layout.tsx
|
||||
import '@/global.css';
|
||||
import { DarkTheme, DefaultTheme, Theme, ThemeProvider } from '@react-navigation/native';
|
||||
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
|
||||
import { Stack } from 'expo-router';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import * as React from 'react';
|
||||
@ -10,12 +10,14 @@ import { useColorScheme } from '@/lib/useColorScheme';
|
||||
import { PortalHost } from '@rn-primitives/portal';
|
||||
import { setAndroidNavigationBar } from '@/lib/android-navigation-bar';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import type { ExtendedTheme } from '@react-navigation/native';
|
||||
|
||||
const LIGHT_THEME: Theme = {
|
||||
const LIGHT_THEME: ExtendedTheme = {
|
||||
...DefaultTheme,
|
||||
colors: NAV_THEME.light,
|
||||
};
|
||||
const DARK_THEME: Theme = {
|
||||
|
||||
const DARK_THEME: ExtendedTheme = {
|
||||
...DarkTheme,
|
||||
colors: NAV_THEME.dark,
|
||||
};
|
||||
|
23
components/layout/TabScreen.tsx
Normal file
23
components/layout/TabScreen.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
// components/layout/TabScreen.tsx
|
||||
import React from 'react';
|
||||
import { View, ViewProps } from 'react-native';
|
||||
|
||||
interface TabScreenProps extends ViewProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function TabScreen({
|
||||
children,
|
||||
style,
|
||||
...props
|
||||
}: TabScreenProps) {
|
||||
return (
|
||||
<View
|
||||
className="flex-1 bg-background"
|
||||
style={style}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
@ -12,8 +12,8 @@ export const NAV_THEME: {
|
||||
notification: 'hsl(0, 84.2%, 60.2%)',
|
||||
primary: 'hsl(261, 90%, 66%)',
|
||||
text: 'hsl(240, 10%, 3.9%)',
|
||||
tabActive: 'hsl(261, 90%, 66%)',
|
||||
tabInactive: 'hsl(240, 3.8%, 46.1%)',
|
||||
tabActive: '#000000',
|
||||
tabInactive: '#737373',
|
||||
tabIndicator: 'hsl(261, 90%, 66%)',
|
||||
},
|
||||
dark: {
|
||||
@ -23,8 +23,8 @@ export const NAV_THEME: {
|
||||
notification: 'hsl(0, 72%, 51%)',
|
||||
primary: 'hsl(261, 90%, 66%)',
|
||||
text: 'hsl(0, 0%, 98%)',
|
||||
tabActive: 'hsl(261, 90%, 66%)',
|
||||
tabInactive: 'hsl(240, 5%, 64.9%)',
|
||||
tabActive: '#FFFFFF',
|
||||
tabInactive: '#A3A3A3',
|
||||
tabIndicator: 'hsl(261, 90%, 66%)',
|
||||
},
|
||||
};
|
101
lib/theme.ts
101
lib/theme.ts
@ -1,8 +1,8 @@
|
||||
// lib/theme.ts
|
||||
import { Theme } from '@react-navigation/native';
|
||||
import type { DarkTheme, DefaultTheme } from '@react-navigation/native';
|
||||
import { ColorSchemeName } from 'react-native';
|
||||
|
||||
// Update the interface for our navigation theme colors
|
||||
// Define our colors type based on the built-in theme types
|
||||
export interface NavigationThemeColors {
|
||||
primary: string;
|
||||
background: string;
|
||||
@ -15,79 +15,30 @@ export interface NavigationThemeColors {
|
||||
tabIndicator: string;
|
||||
}
|
||||
|
||||
// Original ThemeColors interface remains the same
|
||||
export interface ThemeColors {
|
||||
background: string;
|
||||
foreground: string;
|
||||
card: string;
|
||||
'card-foreground': string;
|
||||
popover: string;
|
||||
'popover-foreground': string;
|
||||
primary: string;
|
||||
'primary-foreground': string;
|
||||
secondary: string;
|
||||
'secondary-foreground': string;
|
||||
muted: string;
|
||||
'muted-foreground': string;
|
||||
accent: string;
|
||||
'accent-foreground': string;
|
||||
destructive: string;
|
||||
'destructive-foreground': string;
|
||||
border: string;
|
||||
input: string;
|
||||
ring: string;
|
||||
purple: string;
|
||||
'purple-pressed': string;
|
||||
// Define our custom theme type using the existing theme types
|
||||
export interface CustomTheme {
|
||||
dark: boolean;
|
||||
colors: NavigationThemeColors;
|
||||
}
|
||||
|
||||
// Export the color conversion function
|
||||
export function convertHSLValues(colorScheme: 'light' | 'dark') {
|
||||
const purple = colorScheme === 'light'
|
||||
? 'hsl(261, 90%, 66%)'
|
||||
: 'hsl(261, 90%, 66%)';
|
||||
const mutedForeground = colorScheme === 'light'
|
||||
? 'hsl(240, 3.8%, 46.1%)'
|
||||
: 'hsl(240, 5%, 64.9%)';
|
||||
export function getNavigationTheme(scheme: ColorSchemeName): CustomTheme {
|
||||
const colorScheme = scheme ?? 'light';
|
||||
const isDark = colorScheme === 'dark';
|
||||
|
||||
return {
|
||||
purple,
|
||||
mutedForeground,
|
||||
};
|
||||
}
|
||||
|
||||
export function getNavigationTheme(scheme: ColorSchemeName): Theme {
|
||||
const colorScheme = scheme ?? 'light';
|
||||
const { purple, mutedForeground } = convertHSLValues(colorScheme as 'light' | 'dark');
|
||||
|
||||
const theme: Theme = {
|
||||
dark: colorScheme === 'dark',
|
||||
colors: {
|
||||
primary: purple,
|
||||
background: colorScheme === 'dark' ? 'hsl(240, 10%, 3.9%)' : 'hsl(0, 0%, 100%)',
|
||||
card: colorScheme === 'dark' ? 'hsl(240, 10%, 5.9%)' : 'hsl(0, 0%, 100%)',
|
||||
text: colorScheme === 'dark' ? 'hsl(0, 0%, 98%)' : 'hsl(240, 10%, 3.9%)',
|
||||
border: colorScheme === 'dark' ? 'hsl(240, 3.7%, 15.9%)' : 'hsl(240, 5.9%, 90%)',
|
||||
notification: colorScheme === 'dark' ? 'hsl(0, 72%, 51%)' : 'hsl(0, 84.2%, 60.2%)',
|
||||
},
|
||||
fonts: {
|
||||
regular: {
|
||||
fontFamily: 'System',
|
||||
fontWeight: '400',
|
||||
},
|
||||
medium: {
|
||||
fontFamily: 'System',
|
||||
fontWeight: '500',
|
||||
},
|
||||
bold: {
|
||||
fontFamily: 'System',
|
||||
fontWeight: '700',
|
||||
},
|
||||
heavy: {
|
||||
fontFamily: 'System',
|
||||
fontWeight: '900',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return theme;
|
||||
}
|
||||
const theme: CustomTheme = {
|
||||
dark: isDark,
|
||||
colors: {
|
||||
primary: 'hsl(261, 90%, 66%)',
|
||||
background: isDark ? 'hsl(240, 10%, 3.9%)' : 'hsl(0, 0%, 100%)',
|
||||
card: isDark ? 'hsl(240, 10%, 5.9%)' : 'hsl(0, 0%, 100%)',
|
||||
text: isDark ? 'hsl(0, 0%, 98%)' : 'hsl(240, 10%, 3.9%)',
|
||||
border: isDark ? 'hsl(240, 3.7%, 15.9%)' : 'hsl(240, 5.9%, 90%)',
|
||||
notification: isDark ? 'hsl(0, 72%, 51%)' : 'hsl(0, 84.2%, 60.2%)',
|
||||
tabActive: isDark ? '#FFFFFF' : '#000000',
|
||||
tabInactive: isDark ? '#A3A3A3' : '#737373',
|
||||
tabIndicator: 'hsl(261, 90%, 66%)',
|
||||
}
|
||||
};
|
||||
|
||||
return theme;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user