diff --git a/app/(tabs)/._layout.tsx.swp b/app/(tabs)/._layout.tsx.swp deleted file mode 100644 index de750c1..0000000 Binary files a/app/(tabs)/._layout.tsx.swp and /dev/null differ diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 1432fa9..7738fb2 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -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 ( - Home Screen - + +
console.log('Open filters')} + > + + + } + /> + + History Screen + + ); } \ No newline at end of file diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 8847d4c..e4ad379 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -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 ( - - Home Screen - + +
console.log('New workout')} + > + + + } + /> + + Workout Screen + + ); } \ No newline at end of file diff --git a/app/(tabs)/library/_layout.native.tsx b/app/(tabs)/library/_layout.native.tsx deleted file mode 100644 index 376202c..0000000 --- a/app/(tabs)/library/_layout.native.tsx +++ /dev/null @@ -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(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 ( - -
- - setFilterSheetOpen(true)} - /> - - - } - > - - 12 exercises • 5 templates - -
- - setFilterSheetOpen(false)} - options={currentFilters} - onApplyFilters={handleApplyFilters} - availableFilters={availableFilters} - /> - - - - - - -
- ); -} \ No newline at end of file diff --git a/app/(tabs)/library/_layout.tsx b/app/(tabs)/library/_layout.tsx index 2195c6e..47b5c46 100644 --- a/app/(tabs)/library/_layout.tsx +++ b/app/(tabs)/library/_layout.tsx @@ -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'; \ No newline at end of file +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(initialFilters); + + const handleApplyFilters = (filters: FilterOptions) => { + setCurrentFilters(filters); + const totalFilters = Object.values(filters).reduce( + (acc, curr) => acc + curr.length, + 0 + ); + setActiveFilters(totalFilters); + }; + + return ( + +
+ + setFilterSheetOpen(true)} + /> + + + } + /> + + setFilterSheetOpen(false)} + options={currentFilters} + onApplyFilters={handleApplyFilters} + availableFilters={availableFilters} + /> + + + + + + + + ); +} \ No newline at end of file diff --git a/app/(tabs)/library/_layout.web.tsx b/app/(tabs)/library/_layout.web.tsx deleted file mode 100644 index 40a499c..0000000 --- a/app/(tabs)/library/_layout.web.tsx +++ /dev/null @@ -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(null); - - const handleTabPress = (index: number) => { - setActiveIndex(index); - pagerRef.current?.setPage(index); - }; - - return ( - - {/* Header */} - - Library - - - - {/* Tab Headers */} - - {tabs.map((tab, index) => ( - - handleTabPress(index)} - className="px-4 py-3 items-center" - > - - {tab.title} - - - {activeIndex === index && ( - - )} - - ))} - - - {/* Content */} - - setActiveIndex(e.nativeEvent.position)} - style={{ flex: 1 }} - > - {tabs.map((tab) => ( - - - - ))} - - - - ); -} \ No newline at end of file diff --git a/app/(tabs)/library/index.tsx b/app/(tabs)/library/index.tsx deleted file mode 100644 index a24f618..0000000 --- a/app/(tabs)/library/index.tsx +++ /dev/null @@ -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 ( - - Templates Content - - ); -} - -function ProgramsTab() { - return ( - - Programs (Coming Soon) - - ); -} - -export default function LibraryScreen() { - const { colors } = useTheme(); - - return ( - - {/* Header with Theme Toggle */} - - Library - - - - {/* Material Top Tabs */} - - - - - - - ); -} - -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, - }, -}); \ No newline at end of file diff --git a/app/(tabs)/profile.tsx b/app/(tabs)/profile.tsx index fddf095..bd2cd30 100644 --- a/app/(tabs)/profile.tsx +++ b/app/(tabs)/profile.tsx @@ -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 ( - +
{ - console.log('Open settings'); - }} + onPress={() => console.log('Open settings')} > @@ -37,7 +35,7 @@ export default function ProfileScreen() { paddingBottom: insets.bottom + 20 }} > - {/* Profile Header Section */} + {/* Profile content remains the same */} @@ -49,7 +47,6 @@ export default function ProfileScreen() { @johndoe - {/* Stats Section */} 24 @@ -65,39 +62,18 @@ export default function ProfileScreen() { - {/* Profile Actions */} - - - - - - + ); } \ No newline at end of file diff --git a/app/(tabs)/social.tsx b/app/(tabs)/social.tsx index 3339a3e..38a2075 100644 --- a/app/(tabs)/social.tsx +++ b/app/(tabs)/social.tsx @@ -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 ( - +
{ - // TODO: Open notifications - console.log('Open notifications'); - }} + onPress={() => console.log('Open notifications')} > - {/* Add a notification badge if needed */} @@ -27,6 +24,9 @@ export default function SocialScreen() { } /> - + + Social Screen + + ); -} +} \ No newline at end of file diff --git a/app/_layout.tsx b/app/_layout.tsx index 4dc2c74..03fb4fb 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -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, }; diff --git a/components/layout/TabScreen.tsx b/components/layout/TabScreen.tsx new file mode 100644 index 0000000..e448497 --- /dev/null +++ b/components/layout/TabScreen.tsx @@ -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 ( + + {children} + + ); +} \ No newline at end of file diff --git a/lib/constants.ts b/lib/constants.ts index 61987ab..6962073 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -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%)', }, }; \ No newline at end of file diff --git a/lib/theme.ts b/lib/theme.ts index ebd6294..aafc7ad 100644 --- a/lib/theme.ts +++ b/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; - } \ No newline at end of file + 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; +} \ No newline at end of file