Initial draft
43
.gitignore
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
app-example
|
||||||
|
|
||||||
|
# generated native folders
|
||||||
|
/ios
|
||||||
|
/android
|
||||||
1
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ "recommendations": ["expo.vscode-expo-tools"] }
|
||||||
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll": "explicit",
|
||||||
|
"source.organizeImports": "explicit",
|
||||||
|
"source.sortMembers": "explicit"
|
||||||
|
}
|
||||||
|
}
|
||||||
50
README.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Welcome to your Expo app 👋
|
||||||
|
|
||||||
|
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
|
||||||
|
|
||||||
|
## Get started
|
||||||
|
|
||||||
|
1. Install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx expo start
|
||||||
|
```
|
||||||
|
|
||||||
|
In the output, you'll find options to open the app in a
|
||||||
|
|
||||||
|
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
||||||
|
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
||||||
|
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
||||||
|
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
||||||
|
|
||||||
|
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
||||||
|
|
||||||
|
## Get a fresh project
|
||||||
|
|
||||||
|
When you're ready, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run reset-project
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
|
||||||
|
|
||||||
|
## Learn more
|
||||||
|
|
||||||
|
To learn more about developing your project with Expo, look at the following resources:
|
||||||
|
|
||||||
|
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
|
||||||
|
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
|
||||||
|
|
||||||
|
## Join the community
|
||||||
|
|
||||||
|
Join our community of developers creating universal apps.
|
||||||
|
|
||||||
|
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
|
||||||
|
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
|
||||||
48
app.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "my-drawer-app",
|
||||||
|
"slug": "my-drawer-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/images/icon.png",
|
||||||
|
"scheme": "mydrawerapp",
|
||||||
|
"userInterfaceStyle": "automatic",
|
||||||
|
"newArchEnabled": true,
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"backgroundColor": "#E6F4FE",
|
||||||
|
"foregroundImage": "./assets/images/android-icon-foreground.png",
|
||||||
|
"backgroundImage": "./assets/images/android-icon-background.png",
|
||||||
|
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
||||||
|
},
|
||||||
|
"edgeToEdgeEnabled": true,
|
||||||
|
"predictiveBackGestureEnabled": false
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"output": "static",
|
||||||
|
"favicon": "./assets/images/favicon.png"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"expo-router",
|
||||||
|
[
|
||||||
|
"expo-splash-screen",
|
||||||
|
{
|
||||||
|
"image": "./assets/images/splash-icon.png",
|
||||||
|
"imageWidth": 200,
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"dark": {
|
||||||
|
"backgroundColor": "#000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"experiments": {
|
||||||
|
"typedRoutes": true,
|
||||||
|
"reactCompiler": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
160
app/HomeScreen.tsx
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Linking, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import { Item } from 'types/Item';
|
||||||
|
|
||||||
|
const API_URL = "http://192.168.178.22:8000";
|
||||||
|
|
||||||
|
export default function HomeScreen() {
|
||||||
|
const [data, setData] = useState<Item[]>([]);
|
||||||
|
const [selected, setSelected] = useState<'home' | 'royal-road' | 'podcasts' | 'mixtapes'>('home');
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(API_URL)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(json => {
|
||||||
|
if (json.status === "ok" && Array.isArray(json.data)) {
|
||||||
|
setData(json.data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.error("API error:", err));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Filter items for current category
|
||||||
|
const filteredData =
|
||||||
|
selected === "home" ? data : data.filter(item => item.category === selected);
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{ label: 'Home', key: 'home' },
|
||||||
|
{ label: 'Royal Road', key: 'royal-road' },
|
||||||
|
{ label: 'Podcasts', key: 'podcasts' },
|
||||||
|
{ label: 'Mixtapes', key: 'mixtapes' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
{/* Side Menu */}
|
||||||
|
<View style={[styles.sideMenu, menuOpen && styles.sideMenuOpen]}>
|
||||||
|
{menuItems.map(item => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={item.key}
|
||||||
|
style={[styles.menuItem, selected === item.key && styles.menuItemSelected]}
|
||||||
|
onPress={() => {
|
||||||
|
setSelected(item.key as any);
|
||||||
|
setMenuOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={styles.menuText}>{item.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<View style={styles.mainContent}>
|
||||||
|
<TouchableOpacity style={styles.menuButton} onPress={() => setMenuOpen(!menuOpen)}>
|
||||||
|
<Text style={styles.menuButtonText}>☰</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<Text style={styles.title}>
|
||||||
|
{selected === 'home' && 'Welcome to Home!'}
|
||||||
|
{selected === 'royal-road' && 'Royal Road Updates'}
|
||||||
|
{selected === 'podcasts' && 'Latest Podcasts'}
|
||||||
|
{selected === 'mixtapes' && 'New Mixtapes'}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<ScrollView style={styles.dataContainer}>
|
||||||
|
{filteredData.map(item => (
|
||||||
|
<View key={item.timestamp + item.title} style={styles.dataItem}>
|
||||||
|
<Text style={styles.dataTitle}>{item.title}</Text>
|
||||||
|
<Text style={styles.dataDescription}>{item.info}</Text>
|
||||||
|
<TouchableOpacity onPress={() => Linking.openURL(item.link)}>
|
||||||
|
<Text style={{ color: "blue" }}>Read more</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
backgroundColor: '#f2f2f2',
|
||||||
|
},
|
||||||
|
sideMenu: {
|
||||||
|
width: 0,
|
||||||
|
backgroundColor: '#333',
|
||||||
|
paddingTop: 40,
|
||||||
|
paddingHorizontal: 0,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
sideMenuOpen: {
|
||||||
|
width: 180,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
paddingVertical: 16,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
menuItemSelected: {
|
||||||
|
backgroundColor: '#555',
|
||||||
|
},
|
||||||
|
menuText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
mainContent: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
menuButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 40,
|
||||||
|
left: 16,
|
||||||
|
zIndex: 1,
|
||||||
|
backgroundColor: '#333',
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 8,
|
||||||
|
},
|
||||||
|
menuButtonText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 24,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginTop: 60,
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
dataContainer: {
|
||||||
|
marginTop: 24,
|
||||||
|
width: '90%',
|
||||||
|
},
|
||||||
|
dataItem: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
dataTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#222',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
dataDescription: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#555',
|
||||||
|
},
|
||||||
|
});
|
||||||
94
app/MainContent.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Linking, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import { Item } from 'types/Item';
|
||||||
|
|
||||||
|
type MainContentProps = {
|
||||||
|
selected: string;
|
||||||
|
onToggleMenu: () => void;
|
||||||
|
data: Item[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function MainContent({ selected, onToggleMenu, data }: MainContentProps) {
|
||||||
|
const getTitle = () => {
|
||||||
|
switch (selected) {
|
||||||
|
case 'home': return 'Welcome to Home!';
|
||||||
|
case 'royal-road': return 'Royal Road Updates';
|
||||||
|
case 'podcasts': return 'Latest Podcasts';
|
||||||
|
case 'mixtapes': return 'Mixtapes';
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.mainContent}>
|
||||||
|
<TouchableOpacity style={styles.menuButton} onPress={onToggleMenu}>
|
||||||
|
<Text style={styles.menuButtonText}>☰</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={styles.title}>{getTitle()}</Text>
|
||||||
|
|
||||||
|
<ScrollView style={styles.dataContainer}>
|
||||||
|
{data.map(item => (
|
||||||
|
<TouchableOpacity key={item.timestamp} onPress={() => Linking.openURL(item.link)}>
|
||||||
|
<View style={styles.dataItem}>
|
||||||
|
<Text style={styles.dataTitle}>{item.title}</Text>
|
||||||
|
<Text style={styles.dataDescription}>{item.info}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
mainContent: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
position: 'relative',
|
||||||
|
backgroundColor: '#f2f2f2',
|
||||||
|
},
|
||||||
|
menuButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 40,
|
||||||
|
left: 16,
|
||||||
|
zIndex: 1,
|
||||||
|
backgroundColor: '#333',
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 8,
|
||||||
|
},
|
||||||
|
menuButtonText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 24,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#333',
|
||||||
|
marginTop: 60,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
dataContainer: {
|
||||||
|
width: '90%',
|
||||||
|
},
|
||||||
|
dataItem: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
dataTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#222',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
dataDescription: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#555',
|
||||||
|
},
|
||||||
|
});
|
||||||
52
app/SideMenu.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
|
||||||
|
export type MenuItem = {
|
||||||
|
label: string;
|
||||||
|
key: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SideMenuProps = {
|
||||||
|
menuItems: MenuItem[];
|
||||||
|
selected: string;
|
||||||
|
onSelect: (key: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SideMenu({ menuItems, selected, onSelect }: SideMenuProps) {
|
||||||
|
return (
|
||||||
|
<View style={styles.sideMenu}>
|
||||||
|
{menuItems.map(item => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={item.key}
|
||||||
|
style={[
|
||||||
|
styles.menuItem,
|
||||||
|
selected === item.key && styles.menuItemSelected,
|
||||||
|
]}
|
||||||
|
onPress={() => onSelect(item.key)}>
|
||||||
|
<Text style={styles.menuText}>{item.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
sideMenu: {
|
||||||
|
width: 180,
|
||||||
|
backgroundColor: '#333',
|
||||||
|
paddingTop: 40,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
paddingVertical: 16,
|
||||||
|
borderRadius: 4,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
menuItemSelected: {
|
||||||
|
backgroundColor: '#555',
|
||||||
|
},
|
||||||
|
menuText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
});
|
||||||
6
app/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import HomeScreen from './HomeScreen';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return <HomeScreen />;
|
||||||
|
}
|
||||||
BIN
assets/images/android-icon-background.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/images/android-icon-foreground.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
assets/images/android-icon-monochrome.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
assets/images/favicon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/icon.png
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
assets/images/partial-react-logo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
assets/images/react-logo.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/images/react-logo@2x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/react-logo@3x.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/images/splash-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
49
backup_package.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "my-drawer-app",
|
||||||
|
"main": "expo-router/entry",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"reset-project": "node ./scripts/reset-project.js",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web",
|
||||||
|
"lint": "expo lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/metro-runtime": "~6.1.2",
|
||||||
|
"@expo/vector-icons": "^15.0.2",
|
||||||
|
"@react-native-firebase/app": "^23.4.0",
|
||||||
|
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||||
|
"@react-navigation/elements": "^2.6.3",
|
||||||
|
"@react-navigation/native": "^7.1.8",
|
||||||
|
"expo": "~54.0.10",
|
||||||
|
"expo-constants": "~18.0.9",
|
||||||
|
"expo-font": "~14.0.8",
|
||||||
|
"expo-haptics": "~15.0.7",
|
||||||
|
"expo-image": "~3.0.8",
|
||||||
|
"expo-linking": "~8.0.8",
|
||||||
|
"expo-router": "~6.0.8",
|
||||||
|
"expo-splash-screen": "~31.0.10",
|
||||||
|
"expo-status-bar": "~3.0.8",
|
||||||
|
"expo-symbols": "~1.0.7",
|
||||||
|
"expo-system-ui": "~6.0.7",
|
||||||
|
"expo-web-browser": "~15.0.7",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"react-native": "0.81.4",
|
||||||
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
|
"react-native-reanimated": "~4.1.1",
|
||||||
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
|
"react-native-screens": "~4.16.0",
|
||||||
|
"react-native-web": "~0.21.0",
|
||||||
|
"react-native-worklets": "0.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "~19.1.0",
|
||||||
|
"eslint": "^9.25.0",
|
||||||
|
"eslint-config-expo": "~10.0.0",
|
||||||
|
"typescript": "~5.9.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
10
eslint.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// https://docs.expo.dev/guides/using-eslint/
|
||||||
|
const { defineConfig } = require('eslint/config');
|
||||||
|
const expoConfig = require('eslint-config-expo/flat');
|
||||||
|
|
||||||
|
module.exports = defineConfig([
|
||||||
|
expoConfig,
|
||||||
|
{
|
||||||
|
ignores: ['dist/*'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
44
package.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "my-drawer-app",
|
||||||
|
"main": "expo-router/entry",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"reset-project": "node ./scripts/reset-project.js",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web",
|
||||||
|
"lint": "expo lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/metro-runtime": "~6.1.2",
|
||||||
|
"@expo/vector-icons": "^15.0.2",
|
||||||
|
"expo": "~54.0.10",
|
||||||
|
"expo-constants": "~18.0.9",
|
||||||
|
"expo-font": "~14.0.8",
|
||||||
|
"expo-haptics": "~15.0.7",
|
||||||
|
"expo-image": "~3.0.8",
|
||||||
|
"expo-linking": "~8.0.8",
|
||||||
|
"expo-router": "~6.0.8",
|
||||||
|
"expo-splash-screen": "~31.0.10",
|
||||||
|
"expo-status-bar": "~3.0.8",
|
||||||
|
"expo-symbols": "~1.0.7",
|
||||||
|
"expo-system-ui": "~6.0.7",
|
||||||
|
"expo-web-browser": "~15.0.7",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"react-native": "0.81.4",
|
||||||
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
|
"react-native-reanimated": "~4.1.1",
|
||||||
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
|
"react-native-screens": "~4.16.0",
|
||||||
|
"react-native-web": "~0.21.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "~19.1.0",
|
||||||
|
"eslint": "^9.25.0",
|
||||||
|
"eslint-config-expo": "~10.0.0",
|
||||||
|
"typescript": "~5.9.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
20
tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"extends": "expo/tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./*"
|
||||||
|
],
|
||||||
|
"types/*": [
|
||||||
|
"./types/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".expo/types/**/*.ts",
|
||||||
|
"expo-env.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
7
types/Item.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export type Item = {
|
||||||
|
timestamp: number;
|
||||||
|
category: 'home' | 'royal-road' | 'podcasts' | 'mixtapes';
|
||||||
|
title: string;
|
||||||
|
info: string;
|
||||||
|
link: string;
|
||||||
|
};
|
||||||