Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Runtime & Framework
- Expo SDK `~54.0.23` with `newArchEnabled: true`, typed routes, and React Compiler enabled.
- React `19.1.0`, React Native `0.81.5`, web output via `react-native-web ~0.21.0` and `react-dom 19.1.0`.

## Routing & Navigation
- `expo-router ~6.0.14` as the entry point (`main: expo-router/entry`) and registered in app.json plugins.
- React Navigation 7.x stack: `@react-navigation/native ^7.1.8`, `@react-navigation/bottom-tabs ^7.4.0`, `@react-navigation/elements ^2.6.3`, plus `react-native-screens ~4.16.0` and `react-native-safe-area-context ~5.4.0`.

## Styling
- NativeWind `^4.2.1`; Babel uses `babel-preset-expo` with `jsxImportSource: "nativewind"` and `nativewind/babel`; Metro is wrapped with `withNativeWind(config, { input: "./global.css" })`.
- TailwindCSS `^3.4.18`; `global.css` contains `@tailwind` directives. `tailwind.config.js` currently scans only `App.tsx` and `components/**/*`, so expand `content` if writing classes in `app/**/*`, `hooks/**/*`, etc.

## Animation & Gestures
- `react-native-reanimated ~3.17.5` (use updated hooks such as `useScrollViewOffset`).
- `react-native-gesture-handler ~2.28.0`, `expo-haptics ~15.0.7`, `expo-image ~3.0.10`.

## State & Utilities
- Zustand `^5.0.8`.

## Tooling
- TypeScript `~5.9.2` with `strict: true` and alias `@/* -> ./*`; `nativewind-env.d.ts` adds typings.
- ESLint `^9.25.0` + `eslint-config-expo ~10.0.0`, formatting with `prettier-plugin-tailwindcss ^0.5.14`.
- Metro config only customizes NativeWind; Babel preset remains `babel-preset-expo`.

## Platform Config
- app.json: slug/name `kopi-shop`, scheme `kopishop`, portrait orientation, automatic UI mode.
- Splash and icons handled by `expo-splash-screen` plugin and Android adaptive icon assets.
- Web bundler is Metro with `"output": "static"`.
150 changes: 145 additions & 5 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,175 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { Platform, Pressable, StyleSheet, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';

import { HapticTab } from '@/components/haptic-tab';
import { IconSymbol } from '@/components/ui/icon-symbol';
import { Colors } from '@/constants/theme';
import { useColorScheme } from '@/hooks/use-color-scheme';

const BAR_SIDE_INSET = 12;
const BAR_RADIUS = 22;
const BAR_HEIGHT_IOS = 86;
const BAR_HEIGHT_ANDROID = 72;
const BAR_BOTTOM_OFFSET = -6;
const BAR_PADDING_TOP = 4;
const BAR_PADDING_BOTTOM_EXTRA = 4;
const TAB_ICON_SIZE = 18;
const TAB_LABEL_SIZE = 10;
const TAB_ITEM_PADDING_VERTICAL = 0;

const KOPI_SIZE = 82;
const KOPI_ICON_SIZE = 38;
const KOPI_LIFT = 20;
const KOPI_BORDER_WIDTH = 6;

const KopiTabButton = ({ onPress, accessibilityState }: BottomTabBarButtonProps) => {
const colorScheme = useColorScheme();
const theme = colorScheme ?? 'light';
const isFocused = accessibilityState?.selected;

return (
<Pressable
onPress={onPress}
style={({ pressed }) => [
styles.kopiButtonContainer,
{ transform: [{ scale: pressed ? 0.95 : 1 }] },
]}>
<View
style={[
styles.kopiButtonCircle,
{
backgroundColor: Colors[theme].tint,
borderColor: Colors[theme].background,
shadowColor: Colors[theme].tint,
shadowOpacity: isFocused ? 0.32 : 0.25,
},
]}>
<IconSymbol size={KOPI_ICON_SIZE} name="cup.and.saucer.fill" color="#FFFFFF" />
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Hardcoded white color ('#FFFFFF') is used instead of the theme colors. Consider using Colors.white or Colors[theme].background for consistency with the theming system, making it easier to adjust if the design changes.

Suggested change
<IconSymbol size={KOPI_ICON_SIZE} name="cup.and.saucer.fill" color="#FFFFFF" />
<IconSymbol size={KOPI_ICON_SIZE} name="cup.and.saucer.fill" color={Colors.white} />

Copilot uses AI. Check for mistakes.
</View>
</Pressable>
);
};

export default function TabLayout() {
const colorScheme = useColorScheme();
const insets = useSafeAreaInsets();
const theme = colorScheme ?? 'light';

return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
tabBarActiveTintColor: Colors[theme].tint,
tabBarInactiveTintColor: Colors[theme].tabIconDefault,
headerShown: false,
tabBarButton: HapticTab,
tabBarBackground: () => (
<View
style={[
styles.tabBarBackground,
{
backgroundColor: Colors[theme].background,
borderColor: Colors[theme].tabIconDefault,
borderTopColor: Colors[theme].tabIconDefault,
shadowColor: Colors[theme].tabIconDefault,
},
]}
/>
),
tabBarStyle: {
position: 'absolute',
left: BAR_SIDE_INSET,
right: BAR_SIDE_INSET,
backgroundColor: 'transparent',
height: (Platform.OS === 'ios' ? BAR_HEIGHT_IOS : BAR_HEIGHT_ANDROID) + insets.bottom,
paddingBottom: insets.bottom + BAR_PADDING_BOTTOM_EXTRA,
paddingTop: BAR_PADDING_TOP,
bottom: BAR_BOTTOM_OFFSET,
borderTopWidth: 0,
},
tabBarLabelStyle: {
fontSize: TAB_LABEL_SIZE,
fontWeight: '600',
},
tabBarItemStyle: {
flex: 1,
paddingVertical: TAB_ITEM_PADDING_VERTICAL,
},
}}>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
tabBarIcon: ({ color }) => <IconSymbol size={TAB_ICON_SIZE} name="house.fill" color={color} />,
}}
/>
<Tabs.Screen
name="favorites"
options={{
title: 'Favorites',
tabBarIcon: ({ color }) => <IconSymbol size={TAB_ICON_SIZE} name="star.fill" color={color} />,
}}
/>
<Tabs.Screen
name="kopi"
options={{
title: '',
tabBarLabel: () => null,
tabBarButton: (props) => <KopiTabButton {...props} />,
tabBarItemStyle: { flex: 1, marginTop: -KOPI_LIFT },
}}
/>
<Tabs.Screen
name="explore"
name="orders"
options={{
title: 'Explore',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
title: 'Orders',
tabBarIcon: ({ color }) => <IconSymbol size={TAB_ICON_SIZE} name="list.bullet.clipboard.fill" color={color} />,
}}
/>
<Tabs.Screen
name="me"
options={{
title: 'Me',
tabBarIcon: ({ color }) => <IconSymbol size={TAB_ICON_SIZE} name="person.fill" color={color} />,
}}
/>
</Tabs>
);
}

const styles = StyleSheet.create({
kopiButtonContainer: {
justifyContent: 'center',
alignItems: 'center',
marginTop: -KOPI_LIFT,
},
kopiButtonCircle: {
width: KOPI_SIZE,
height: KOPI_SIZE,
borderRadius: KOPI_SIZE / 2,
justifyContent: 'center',
alignItems: 'center',
borderWidth: KOPI_BORDER_WIDTH,
shadowOffset: {
width: 0,
height: 6,
},
shadowOpacity: 0.25,
shadowRadius: 6,
elevation: 8,
},
tabBarBackground: {
flex: 1,
borderTopLeftRadius: BAR_RADIUS,
borderTopRightRadius: BAR_RADIUS,
borderTopWidth: 1,
borderWidth: 1,
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The borderWidth: 1 creates a border on all sides of the tab bar, but borderTopWidth: 1 is already set on line 167. This creates a double border on the top edge (2px total). Consider removing either borderWidth or borderTopWidth to avoid the redundant top border.

Suggested change
borderWidth: 1,

Copilot uses AI. Check for mistakes.
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.08,
shadowRadius: 6,
elevation: 4,
overflow: 'hidden',
},
});
112 changes: 0 additions & 112 deletions app/(tabs)/explore.tsx

This file was deleted.

9 changes: 9 additions & 0 deletions app/(tabs)/favorites.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Text, View } from 'react-native';

export default function FavoritesScreen() {
return (
<View className="flex-1 justify-center items-center bg-milk-coffee">
<Text className="text-xl font-bold text-dark-coffee">Favorites Screen</Text>
</View>
);
}
Loading
Loading