Skip to content

Commit

Permalink
feat(mobile): app layout (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkdev98 committed Jun 9, 2024
1 parent 048c90d commit f187371
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 70 deletions.
53 changes: 36 additions & 17 deletions apps/mobile/app/(app)/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,56 @@
import { useColorScheme } from '@/hooks/useColorScheme'
import { theme } from '@/lib/theme'
import { Tabs } from 'expo-router'

import { TabBarIcon } from '@/components/navigation/TabBarIcon'
import { CogIcon, LandPlotIcon, ScanTextIcon, WalletIcon } from 'lucide-react-native'

export default function TabLayout() {
const colorScheme = useColorScheme()
return (
<Tabs
screenOptions={{
// tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
headerShadowVisible: false,
tabBarActiveTintColor: theme[colorScheme ?? 'light'].primary,
tabBarShowLabel: false,
tabBarStyle: {
borderTopWidth: 0,
},
headerTitleStyle: {
fontFamily: 'Be Vietnam Pro',
fontSize: 16,
color: theme[colorScheme ?? 'light'].primary,
},
}}
>
<Tabs.Screen
name="index"
options={{
headerShown: false,
tabBarShowLabel: false,
tabBarIcon: ({ color }) => <WalletIcon color={color} />,
}}
/>
<Tabs.Screen
name="budgets"
options={{
headerTitle: 'Budgets',
tabBarShowLabel: false,
tabBarIcon: ({ color }) => <LandPlotIcon color={color} />,
}}
/>
<Tabs.Screen
name="scanner"
options={{
headerTitle: 'Scanner',
tabBarShowLabel: false,
tabBarIcon: ({ color, focused }) => (
<TabBarIcon
name={focused ? 'home' : 'home-outline'}
color={color}
/>
),
tabBarIcon: ({ color }) => <ScanTextIcon color={color} />,
}}
/>
<Tabs.Screen
name="explore"
name="settings"
options={{
headerTitle: 'Settings',
tabBarShowLabel: false,
tabBarIcon: ({ color, focused }) => (
<TabBarIcon
name={focused ? 'code-slash' : 'code-slash-outline'}
color={color}
/>
),
tabBarIcon: ({ color }) => <CogIcon color={color} />,
}}
/>
</Tabs>
Expand Down
11 changes: 11 additions & 0 deletions apps/mobile/app/(app)/(tabs)/budgets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Toolbar } from '@/components/common/toolbar'
import { Text, View } from 'react-native'

export default function BudgetsScreen() {
return (
<View className="flex-1 bg-card">
<Text className="font-sans">Budgets Screen</Text>
<Toolbar />
</View>
)
}
37 changes: 0 additions & 37 deletions apps/mobile/app/(app)/(tabs)/explore.tsx

This file was deleted.

16 changes: 14 additions & 2 deletions apps/mobile/app/(app)/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { Text } from 'react-native'
import { Toolbar } from '@/components/common/toolbar'
import { HomeHeader } from '@/components/home/header'
import { ScrollView, Text, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'

export default function HomeScreen() {
return <Text className="font-sans">Home Screen</Text>
const { top } = useSafeAreaInsets()
return (
<View className="flex-1 bg-card" style={{ paddingTop: top }}>
<HomeHeader />
<ScrollView>
<Text className="font-sans">Home Screen</Text>
</ScrollView>
<Toolbar />
</View>
)
}
11 changes: 11 additions & 0 deletions apps/mobile/app/(app)/(tabs)/scanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Toolbar } from '@/components/common/toolbar'
import { Text, View } from 'react-native'

export default function ScannerScreen() {
return (
<View className="flex-1 bg-card">
<Text className="font-sans">Scanner Screen</Text>
<Toolbar />
</View>
)
}
53 changes: 53 additions & 0 deletions apps/mobile/app/(app)/(tabs)/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/Avatar'
import { Badge } from '@/components/Badge'
import { Button } from '@/components/Button'
import { IconButton } from '@/components/IconButton'
import { useAuth, useUser } from '@clerk/clerk-expo'
import { LogOutIcon, PencilIcon } from 'lucide-react-native'
import { ScrollView, Text, View } from 'react-native'

export default function SettingsScreen() {
const { signOut } = useAuth()
const { user } = useUser()

return (
<ScrollView contentContainerClassName="py-4" className="bg-card">
<View className="bg-muted rounded-lg mx-6 px-4 py-3 justify-end h-40">
<View className="flex flex-row items-center gap-2 justify-between">
<View className="flex flex-row items-center gap-3">
<Avatar className="w-12 h-12">
<AvatarImage
source={{
uri: user?.imageUrl,
}}
/>
<AvatarFallback>QK</AvatarFallback>
</Avatar>
<View>
<Badge
variant="secondary"
label="Free"
className="self-start rounded-md mb-1"
/>
<Text className="font-medium">
{user?.fullName ?? user?.primaryEmailAddress?.emailAddress}
</Text>
</View>
</View>
<IconButton icon={PencilIcon} size="sm" variant="ghost" />
</View>
</View>
<Text className='font-sans mx-6 text-muted-foreground mt-6'>
Others
</Text>
<Button
label="Sign out"
variant="ghost"
onPress={() => signOut()}
labelClasses="text-red-500 font-regular"
leftIcon={LogOutIcon}
className="justify-start gap-6 px-6"
/>
</ScrollView>
)
}
11 changes: 10 additions & 1 deletion apps/mobile/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,14 @@ export default function AuthenticatedLayout() {
return <Redirect href={'/login'} />
}

return <Stack />
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen
name="new-record"
options={{
presentation: 'modal',
}}
/>
</Stack>
)
}
5 changes: 5 additions & 0 deletions apps/mobile/app/(app)/new-record.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Text } from 'react-native'

export default function NewRecordScreen() {
return <Text className="font-sans m-4 mx-auto">New Record</Text>
}
8 changes: 4 additions & 4 deletions apps/mobile/components/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { Text, View } from 'react-native'
import { cn } from '../lib/utils'

const badgeVariants = cva(
'flex flex-row items-center rounded-full px-2 py-1 text-xs font-semibold',
'flex flex-row items-center rounded-full px-2 py-0.5 text-xs font-semibold',
{
variants: {
variant: {
default: 'bg-primary',
secondary: 'bg-secondary',
secondary: 'bg-secondary border border-border',
destructive: 'bg-destructive',
success: 'bg-green-500 dark:bg-green-700',
},
Expand All @@ -24,7 +24,7 @@ const badgeTextVariants = cva('font-medium text-center text-xs', {
variants: {
variant: {
default: 'text-primary-foreground',
secondary: 'text-secondary-foreground',
secondary: 'text-muted-foreground',
destructive: 'text-destructive-foreground',
success: 'text-green-100',
},
Expand All @@ -36,7 +36,7 @@ const badgeTextVariants = cva('font-medium text-center text-xs', {

export interface BadgeProps
extends React.ComponentPropsWithoutRef<typeof View>,
VariantProps<typeof badgeVariants> {
VariantProps<typeof badgeVariants> {
label: string
labelClasses?: string
}
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const buttonVariants = cva(
secondary: 'bg-secondary',
outline: 'border-border border',
destructive: 'bg-destructive',
ghost: 'bg-slate-700',
ghost: 'bg-transparent',
link: 'text-primary underline-offset-4',
},
size: {
Expand All @@ -36,7 +36,7 @@ const buttonTextVariants = cva('text-center font-medium font-sans', {
secondary: 'text-secondary-foreground',
outline: 'text-primary',
destructive: 'text-destructive-foreground',
ghost: 'text-primary-foreground',
ghost: 'text-primary',
link: 'text-primary-foreground underline',
},
size: {
Expand Down
19 changes: 12 additions & 7 deletions apps/mobile/components/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type VariantProps, cva } from 'class-variance-authority'
import { TouchableOpacity } from 'react-native'

import { forwardRef } from 'react'
import type { SvgProps } from 'react-native-svg'
import { cn } from '../lib/utils'

Expand All @@ -17,9 +18,10 @@ const buttonVariants = cva(
link: 'text-primary underline-offset-4',
},
size: {
default: 'h-12 w-12',
default: 'h-10 w-10',
lg: 'h-12 w-12',
sm: 'h-8 w-8',
lg: 'h-14 w-14',
xl: 'h-14 w-14',
},
},
defaultVariants: {
Expand All @@ -40,9 +42,10 @@ const iconVariants = cva('text-center font-medium font-sans', {
link: 'text-primary-foreground underline',
},
size: {
default: 'text-base',
default: 'w-5 h-5',
sm: 'w-5 h-5',
lg: 'text-xl',
lg: 'w-6 h-6',
xl: 'w-6 h-6',
},
},
defaultVariants: {
Expand All @@ -57,17 +60,19 @@ export interface IconButtonProps
icon: React.ComponentType<SvgProps>
iconClasses?: string
}
function IconButton({

const IconButton = forwardRef(function ({
icon: Icon,
iconClasses,
className,
variant,
size,
disabled,
...props
}: IconButtonProps) {
}: IconButtonProps, ref: React.ForwardedRef<TouchableOpacity>) {
return (
<TouchableOpacity
ref={ref}
activeOpacity={0.8}
className={cn(buttonVariants({ variant, size, className }), {
'opacity-50': disabled,
Expand All @@ -80,6 +85,6 @@ function IconButton({
/>
</TouchableOpacity>
)
}
})

export { IconButton, buttonVariants, iconVariants }
7 changes: 7 additions & 0 deletions apps/mobile/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@ const Input = forwardRef<React.ElementRef<typeof TextInput>, InputProps>(
<View className={cn('flex flex-col gap-1.5', className)}>
{label && <Text className={cn('text-base', labelClasses)}>{label}</Text>}
<View>
{leftSection && (
<View className="absolute left-2 top-1/2 transform -translate-y-1/2">
{leftSection}
</View>
)}
<TextInput
className={cn(
inputClasses,
'border border-border placeholder-input py-2.5 px-4 rounded-lg font-sans',
leftSection && 'pl-10',
rightSection && 'pr-10',
)}
{...props}
/>
Expand Down
20 changes: 20 additions & 0 deletions apps/mobile/components/common/toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Link } from 'expo-router'
import { PlusIcon, Sparkles } from 'lucide-react-native'
import { View } from 'react-native'
import { IconButton } from '../IconButton'
import { Input } from '../Input'

export function Toolbar() {
return (
<View className="gap-3 items-center absolute flex-row bottom-4 left-6 right-6">
<Input
placeholder="Ask AI anything..."
leftSection={<Sparkles className="w-5 h-5 text-muted-foreground" />}
className="flex-1"
/>
<Link href="/new-record" asChild>
<IconButton icon={PlusIcon} className="w-10 h-10" iconClasses='size-6' />
</Link>
</View>
)
}
Loading

0 comments on commit f187371

Please sign in to comment.