Initialize Expo mobile app with tab navigation and monorepo support
- Expo managed project at apps/mobile/ with TypeScript - Expo Router with 4 tabs: Map, Routes, Activities, Profile - app.config.ts with monorepo experiment, bundle IDs, scheme - Workspace packages linked: api, gpx, i18n, map-core, types - Profile tab imports API_VERSION from @trails-cool/api to verify shared package resolution Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
48f990f4ec
commit
95fdbfee2f
17 changed files with 5439 additions and 31 deletions
41
apps/mobile/.gitignore
vendored
Normal file
41
apps/mobile/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Expo
|
||||||
|
.expo/
|
||||||
|
dist/
|
||||||
|
web-build/
|
||||||
|
expo-env.d.ts
|
||||||
|
|
||||||
|
# Native
|
||||||
|
.kotlin/
|
||||||
|
*.orig.*
|
||||||
|
*.jks
|
||||||
|
*.p8
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
|
*.mobileprovision
|
||||||
|
|
||||||
|
# Metro
|
||||||
|
.metro-health-check*
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.*
|
||||||
|
yarn-debug.*
|
||||||
|
yarn-error.*
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# generated native folders
|
||||||
|
/ios
|
||||||
|
/android
|
||||||
36
apps/mobile/app.config.ts
Normal file
36
apps/mobile/app.config.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { ExpoConfig, ConfigContext } from "expo/config";
|
||||||
|
|
||||||
|
export default ({ config }: ConfigContext): ExpoConfig => ({
|
||||||
|
...config,
|
||||||
|
name: "trails.cool",
|
||||||
|
slug: "trails-cool",
|
||||||
|
version: "0.0.1",
|
||||||
|
scheme: "trailscool",
|
||||||
|
orientation: "portrait",
|
||||||
|
icon: "./assets/icon.png",
|
||||||
|
userInterfaceStyle: "light",
|
||||||
|
newArchEnabled: true,
|
||||||
|
splash: {
|
||||||
|
image: "./assets/splash-icon.png",
|
||||||
|
resizeMode: "contain",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
},
|
||||||
|
ios: {
|
||||||
|
supportsTablet: true,
|
||||||
|
bundleIdentifier: "cool.trails.app",
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
adaptiveIcon: {
|
||||||
|
foregroundImage: "./assets/adaptive-icon.png",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
},
|
||||||
|
package: "cool.trails.app",
|
||||||
|
},
|
||||||
|
web: {
|
||||||
|
favicon: "./assets/favicon.png",
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
monorepo: true,
|
||||||
|
},
|
||||||
|
plugins: ["expo-router"],
|
||||||
|
});
|
||||||
41
apps/mobile/app/(tabs)/_layout.tsx
Normal file
41
apps/mobile/app/(tabs)/_layout.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
export default function TabLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
screenOptions={{
|
||||||
|
tabBarActiveTintColor: "#4A6B40",
|
||||||
|
headerShown: false,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "Map",
|
||||||
|
tabBarIcon: () => null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="routes"
|
||||||
|
options={{
|
||||||
|
title: "Routes",
|
||||||
|
tabBarIcon: () => null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="activities"
|
||||||
|
options={{
|
||||||
|
title: "Activities",
|
||||||
|
tabBarIcon: () => null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="profile"
|
||||||
|
options={{
|
||||||
|
title: "Profile",
|
||||||
|
tabBarIcon: () => null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
apps/mobile/app/(tabs)/activities.tsx
Normal file
14
apps/mobile/app/(tabs)/activities.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export default function ActivitiesScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.text}>Activities</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: { flex: 1, justifyContent: "center", alignItems: "center" },
|
||||||
|
text: { fontSize: 18, color: "#666" },
|
||||||
|
});
|
||||||
14
apps/mobile/app/(tabs)/index.tsx
Normal file
14
apps/mobile/app/(tabs)/index.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export default function MapScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.text}>Map</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: { flex: 1, justifyContent: "center", alignItems: "center" },
|
||||||
|
text: { fontSize: 18, color: "#666" },
|
||||||
|
});
|
||||||
17
apps/mobile/app/(tabs)/profile.tsx
Normal file
17
apps/mobile/app/(tabs)/profile.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
import { API_VERSION } from "@trails-cool/api";
|
||||||
|
|
||||||
|
export default function ProfileScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.text}>Profile</Text>
|
||||||
|
<Text style={styles.version}>API v{API_VERSION}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: { flex: 1, justifyContent: "center", alignItems: "center" },
|
||||||
|
text: { fontSize: 18, color: "#666" },
|
||||||
|
version: { fontSize: 12, color: "#999", marginTop: 8 },
|
||||||
|
});
|
||||||
14
apps/mobile/app/(tabs)/routes.tsx
Normal file
14
apps/mobile/app/(tabs)/routes.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export default function RoutesScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.text}>Routes</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: { flex: 1, justifyContent: "center", alignItems: "center" },
|
||||||
|
text: { fontSize: 18, color: "#666" },
|
||||||
|
});
|
||||||
5
apps/mobile/app/_layout.tsx
Normal file
5
apps/mobile/app/_layout.tsx
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Stack } from "expo-router";
|
||||||
|
|
||||||
|
export default function RootLayout() {
|
||||||
|
return <Stack screenOptions={{ headerShown: false }} />;
|
||||||
|
}
|
||||||
BIN
apps/mobile/assets/adaptive-icon.png
Normal file
BIN
apps/mobile/assets/adaptive-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/mobile/assets/favicon.png
Normal file
BIN
apps/mobile/assets/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/mobile/assets/icon.png
Normal file
BIN
apps/mobile/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
apps/mobile/assets/splash-icon.png
Normal file
BIN
apps/mobile/assets/splash-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
1
apps/mobile/index.ts
Normal file
1
apps/mobile/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
import "expo-router/entry";
|
||||||
30
apps/mobile/package.json
Normal file
30
apps/mobile/package.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "@trails-cool/mobile",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@trails-cool/api": "workspace:*",
|
||||||
|
"@trails-cool/gpx": "workspace:*",
|
||||||
|
"@trails-cool/i18n": "workspace:*",
|
||||||
|
"@trails-cool/map-core": "workspace:*",
|
||||||
|
"@trails-cool/types": "workspace:*",
|
||||||
|
"expo": "~54.0.33",
|
||||||
|
"expo-router": "~4.0.22",
|
||||||
|
"expo-status-bar": "~3.0.9",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-native": "0.81.5",
|
||||||
|
"react-native-safe-area-context": "~5.4.0",
|
||||||
|
"react-native-screens": "~4.11.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "~19.1.0",
|
||||||
|
"typescript": "~5.9.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
apps/mobile/tsconfig.json
Normal file
6
apps/mobile/tsconfig.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "expo/tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
### 1.1 App Scaffold
|
### 1.1 App Scaffold
|
||||||
|
|
||||||
- [ ] 1.1.1 Initialize Expo managed project at `apps/mobile/` with TypeScript template
|
- [x] 1.1.1 Initialize Expo managed project at `apps/mobile/` with TypeScript template
|
||||||
- [ ] 1.1.2 Configure pnpm workspace to include `apps/mobile` and resolve shared packages (`@trails-cool/types`, `@trails-cool/gpx`, `@trails-cool/i18n`)
|
- [x] 1.1.2 Configure pnpm workspace to include `apps/mobile` and resolve shared packages (`@trails-cool/types`, `@trails-cool/gpx`, `@trails-cool/i18n`)
|
||||||
- [ ] 1.1.3 Set up Expo Router with bottom tab navigation (Map, Routes, Activities, Profile) and placeholder screens
|
- [x] 1.1.3 Set up Expo Router with bottom tab navigation (Map, Routes, Activities, Profile) and placeholder screens
|
||||||
- [ ] 1.1.4 Add app icon, splash screen, and `app.config.ts` with bundle identifiers for iOS and Android
|
- [x] 1.1.4 Add app icon, splash screen, and `app.config.ts` with bundle identifiers for iOS and Android
|
||||||
- [ ] 1.1.5 Configure EAS Build for development and preview profiles
|
- [ ] 1.1.5 Configure EAS Build for development and preview profiles
|
||||||
|
|
||||||
### 1.2 API Contract Package
|
### 1.2 API Contract Package
|
||||||
|
|
|
||||||
5243
pnpm-lock.yaml
generated
5243
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue