diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..caccf6c
--- /dev/null
+++ b/AGENTS.md
@@ -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"`.
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
index 54e11d0..d10b14a 100644
--- a/app/(tabs)/_layout.tsx
+++ b/app/(tabs)/_layout.tsx
@@ -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 (
+ [
+ styles.kopiButtonContainer,
+ { transform: [{ scale: pressed ? 0.95 : 1 }] },
+ ]}>
+
+
+
+
+ );
+};
+
export default function TabLayout() {
const colorScheme = useColorScheme();
+ const insets = useSafeAreaInsets();
+ const theme = colorScheme ?? 'light';
return (
(
+
+ ),
+ 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,
+ },
}}>
,
+ tabBarIcon: ({ color }) => ,
+ }}
+ />
+ ,
+ }}
+ />
+ null,
+ tabBarButton: (props) => ,
+ tabBarItemStyle: { flex: 1, marginTop: -KOPI_LIFT },
}}
/>
,
+ title: 'Orders',
+ tabBarIcon: ({ color }) => ,
+ }}
+ />
+ ,
}}
/>
);
}
+
+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,
+ shadowOffset: { width: 0, height: -2 },
+ shadowOpacity: 0.08,
+ shadowRadius: 6,
+ elevation: 4,
+ overflow: 'hidden',
+ },
+});
diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx
deleted file mode 100644
index 71518f9..0000000
--- a/app/(tabs)/explore.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-import { Image } from 'expo-image';
-import { Platform, StyleSheet } from 'react-native';
-
-import { Collapsible } from '@/components/ui/collapsible';
-import { ExternalLink } from '@/components/external-link';
-import ParallaxScrollView from '@/components/parallax-scroll-view';
-import { ThemedText } from '@/components/themed-text';
-import { ThemedView } from '@/components/themed-view';
-import { IconSymbol } from '@/components/ui/icon-symbol';
-import { Fonts } from '@/constants/theme';
-
-export default function TabTwoScreen() {
- return (
-
- }>
-
-
- Explore
-
-
- This app includes example code to help you get started.
-
-
- This app has two screens:{' '}
- app/(tabs)/index.tsx and{' '}
- app/(tabs)/explore.tsx
-
-
- The layout file in app/(tabs)/_layout.tsx{' '}
- sets up the tab navigator.
-
-
- Learn more
-
-
-
-
- You can open this project on Android, iOS, and the web. To open the web version, press{' '}
- w in the terminal running this project.
-
-
-
-
- For static images, you can use the @2x and{' '}
- @3x suffixes to provide files for
- different screen densities
-
-
-
- Learn more
-
-
-
-
- This template has light and dark mode support. The{' '}
- useColorScheme() hook lets you inspect
- what the user's current color scheme is, and so you can adjust UI colors accordingly.
-
-
- Learn more
-
-
-
-
- This template includes an example of an animated component. The{' '}
- components/HelloWave.tsx component uses
- the powerful{' '}
-
- react-native-reanimated
- {' '}
- library to create a waving hand animation.
-
- {Platform.select({
- ios: (
-
- The components/ParallaxScrollView.tsx{' '}
- component provides a parallax effect for the header image.
-
- ),
- })}
-
-
- );
-}
-
-const styles = StyleSheet.create({
- headerImage: {
- color: '#808080',
- bottom: -90,
- left: -35,
- position: 'absolute',
- },
- titleContainer: {
- flexDirection: 'row',
- gap: 8,
- },
-});
diff --git a/app/(tabs)/favorites.tsx b/app/(tabs)/favorites.tsx
new file mode 100644
index 0000000..1498f9d
--- /dev/null
+++ b/app/(tabs)/favorites.tsx
@@ -0,0 +1,9 @@
+import { Text, View } from 'react-native';
+
+export default function FavoritesScreen() {
+ return (
+
+ Favorites Screen
+
+ );
+}
diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
index 786b736..c24b44e 100644
--- a/app/(tabs)/index.tsx
+++ b/app/(tabs)/index.tsx
@@ -1,98 +1,9 @@
-import { Image } from 'expo-image';
-import { Platform, StyleSheet } from 'react-native';
-
-import { HelloWave } from '@/components/hello-wave';
-import ParallaxScrollView from '@/components/parallax-scroll-view';
-import { ThemedText } from '@/components/themed-text';
-import { ThemedView } from '@/components/themed-view';
-import { Link } from 'expo-router';
+import { Text, View } from 'react-native';
export default function HomeScreen() {
return (
-
- }>
-
- Welcome!
-
-
-
- Step 1: Try it
-
- Edit app/(tabs)/index.tsx to see changes.
- Press{' '}
-
- {Platform.select({
- ios: 'cmd + d',
- android: 'cmd + m',
- web: 'F12',
- })}
- {' '}
- to open developer tools.
-
-
-
-
-
- Step 2: Explore
-
-
-
- alert('Action pressed')} />
- alert('Share pressed')}
- />
-
- alert('Delete pressed')}
- />
-
-
-
-
-
- {`Tap the Explore tab to learn more about what's included in this starter app.`}
-
-
-
- Step 3: Get a fresh start
-
- {`When you're ready, run `}
- npm run reset-project to get a fresh{' '}
- app directory. This will move the current{' '}
- app to{' '}
- app-example.
-
-
-
+
+ Home Screen
+
);
}
-
-const styles = StyleSheet.create({
- titleContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 8,
- },
- stepContainer: {
- gap: 8,
- marginBottom: 8,
- },
- reactLogo: {
- height: 178,
- width: 290,
- bottom: 0,
- left: 0,
- position: 'absolute',
- },
-});
diff --git a/app/(tabs)/kopi.tsx b/app/(tabs)/kopi.tsx
new file mode 100644
index 0000000..36ecf97
--- /dev/null
+++ b/app/(tabs)/kopi.tsx
@@ -0,0 +1,9 @@
+import { Text, View } from 'react-native';
+
+export default function KopiScreen() {
+ return (
+
+ Kopi Screen
+
+ );
+}
diff --git a/app/(tabs)/me.tsx b/app/(tabs)/me.tsx
new file mode 100644
index 0000000..2e6add0
--- /dev/null
+++ b/app/(tabs)/me.tsx
@@ -0,0 +1,9 @@
+import { Text, View } from 'react-native';
+
+export default function MeScreen() {
+ return (
+
+ Me Screen
+
+ );
+}
diff --git a/app/(tabs)/orders.tsx b/app/(tabs)/orders.tsx
new file mode 100644
index 0000000..f3bfadc
--- /dev/null
+++ b/app/(tabs)/orders.tsx
@@ -0,0 +1,9 @@
+import { Text, View } from 'react-native';
+
+export default function OrdersScreen() {
+ return (
+
+ Orders Screen
+
+ );
+}
diff --git a/components/ui/icon-symbol.tsx b/components/ui/icon-symbol.tsx
index b7ece6b..d8c6078 100644
--- a/components/ui/icon-symbol.tsx
+++ b/components/ui/icon-symbol.tsx
@@ -1,7 +1,7 @@
// Fallback for using MaterialIcons on Android and web.
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
-import { SymbolWeight, SymbolViewProps } from 'expo-symbols';
+import { SymbolViewProps, SymbolWeight } from 'expo-symbols';
import { ComponentProps } from 'react';
import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native';
@@ -18,6 +18,10 @@ const MAPPING = {
'paperplane.fill': 'send',
'chevron.left.forwardslash.chevron.right': 'code',
'chevron.right': 'chevron-right',
+ 'cup.and.saucer.fill': 'coffee',
+ 'list.bullet.clipboard.fill': 'receipt',
+ 'person.fill': 'person',
+ 'star.fill': 'star',
} as IconMapping;
/**
diff --git a/constants/theme.ts b/constants/theme.ts
index f06facd..6786d5b 100644
--- a/constants/theme.ts
+++ b/constants/theme.ts
@@ -5,25 +5,36 @@
import { Platform } from 'react-native';
-const tintColorLight = '#0a7ea4';
-const tintColorDark = '#fff';
+
+const Palette = {
+ milkCoffee: '#F5F5F0', // Creamy Milk
+ darkCoffee: '#4A3B32', // Dark Coffee
+ lightCoffee: '#D7CCC8', // Light Coffee
+ mediumCoffee: '#8D6E63', // Medium Coffee
+ grey: '#BCAAA4',
+ white: '#FFFFFF',
+ black: '#000000',
+};
export const Colors = {
light: {
- text: '#11181C',
- background: '#fff',
- tint: tintColorLight,
- icon: '#687076',
- tabIconDefault: '#687076',
- tabIconSelected: tintColorLight,
+ text: Palette.darkCoffee,
+ background: Palette.milkCoffee,
+ tint: Palette.darkCoffee,
+ icon: Palette.mediumCoffee,
+ tabIconDefault: Palette.grey,
+ tabIconSelected: Palette.darkCoffee,
+ // Add palette for direct access if needed, though usually we use the semantic names above
+ ...Palette,
},
dark: {
text: '#ECEDEE',
background: '#151718',
- tint: tintColorDark,
+ tint: Palette.lightCoffee,
icon: '#9BA1A6',
tabIconDefault: '#9BA1A6',
- tabIconSelected: tintColorDark,
+ tabIconSelected: Palette.lightCoffee,
+ ...Palette,
},
};
diff --git a/global.css b/global.css
index bd6213e..3cc8733 100644
--- a/global.css
+++ b/global.css
@@ -1,3 +1,13 @@
@tailwind base;
@tailwind components;
-@tailwind utilities;
\ No newline at end of file
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --color-milk-coffee: #F5F5F0;
+ --color-dark-coffee: #4A3B32;
+ --color-light-coffee: #D7CCC8;
+ --color-medium-coffee: #8D6E63;
+ --color-grey: #BCAAA4;
+ }
+}
\ No newline at end of file
diff --git a/tailwind.config.js b/tailwind.config.js
index 5a6c92c..5b6bf81 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,10 +1,22 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all files that contain Nativewind classes.
- content: ["./App.tsx", "./components/**/*.{js,jsx,ts,tsx}"],
+content: [
+ './App.tsx',
+ './app/**/*.{js,jsx,ts,tsx}',
+ './components/**/*.{js,jsx,ts,tsx}',
+],
presets: [require("nativewind/preset")],
theme: {
- extend: {},
+ extend: {
+ colors: {
+ 'milk-coffee': 'var(--color-milk-coffee)',
+ 'dark-coffee': 'var(--color-dark-coffee)',
+ 'light-coffee': 'var(--color-light-coffee)',
+ 'medium-coffee': 'var(--color-medium-coffee)',
+ 'grey': 'var(--color-grey)',
+ },
+ },
},
plugins: [],
}
\ No newline at end of file