diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 30914fb..75914cd 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,13 +1,12 @@ -import React from 'react'; import FontAwesome from '@expo/vector-icons/FontAwesome'; -import { Link, Tabs } from 'expo-router'; -import { Pressable } from 'react-native'; +import { Tabs } from 'expo-router'; +import { useColorScheme } from 'react-native'; import Colors from '@/constants/Colors'; -import { useColorScheme } from '@/components/useColorScheme'; -import { useClientOnlyValue } from '@/components/useClientOnlyValue'; -// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ +/** + * You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ + */ function TabBarIcon(props: { name: React.ComponentProps['name']; color: string; @@ -16,42 +15,30 @@ function TabBarIcon(props: { } export default function TabLayout() { - const colorScheme = useColorScheme(); + const colorScheme = 'dark'; // Force dark mode return ( , - headerRight: () => ( - - - {({ pressed }) => ( - - )} - - - ), + title: 'Home', + tabBarIcon: ({ color }) => , }} /> , + title: 'Services', + tabBarIcon: ({ color }) => , }} /> diff --git a/app/(tabs)/home.tsx b/app/(tabs)/home.tsx new file mode 100644 index 0000000..82dbf9a --- /dev/null +++ b/app/(tabs)/home.tsx @@ -0,0 +1,56 @@ +import { StyleSheet, SafeAreaView, ScrollView } from 'react-native'; +import { Text, View } from '@/components/Themed'; +import FeatureCard from '@/components/FeatureCard'; +import PrayerTimeCard from '@/components/PrayerTimeCard'; +import ServicesGrid from '@/components/ServicesGrid'; + +export default function HomeScreen() { + return ( + + + + Home + + + + + + + + + + + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + innerContainer: { + paddingHorizontal: 15, + }, + title: { + fontSize: 22, + fontWeight: 'bold', + marginVertical: 15, + }, + cardRow: { + flexDirection: 'row', + justifyContent: 'space-between', + }, +}); diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 6cbee6d..1963b3d 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,31 +1,5 @@ -import { StyleSheet } from 'react-native'; +import { Redirect } from 'expo-router'; -import EditScreenInfo from '@/components/EditScreenInfo'; -import { Text, View } from '@/components/Themed'; - -export default function TabOneScreen() { - return ( - - Tab One - - - - ); +export default function TabIndex() { + return ; } - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - fontSize: 20, - fontWeight: 'bold', - }, - separator: { - marginVertical: 30, - height: 1, - width: '80%', - }, -}); diff --git a/app/(tabs)/services.tsx b/app/(tabs)/services.tsx new file mode 100644 index 0000000..cd83519 --- /dev/null +++ b/app/(tabs)/services.tsx @@ -0,0 +1,59 @@ +import { StyleSheet, SafeAreaView, ScrollView } from 'react-native'; +import { Text, View } from '@/components/Themed'; +import AdhkarCard from '@/components/AdhkarCard'; +import SupplicationListItem from '@/components/SupplicationListItem'; + +const adhkarCategories = [ + 'Thikr said in the morning and evening', + 'Thikr before sleeping', + 'Thikr after salam', +]; + +const supplications = [ + 'Upon breaking fast', + 'Supplication said by one fasting when presented with food and does not break his fast', + 'When insulted while fasting', + 'Supplication upon seeing the early or premature fruit', + 'Supplication upon sneezing', +] + +export default function ServicesScreen() { + return ( + + + + Services + Adhkar + {adhkarCategories.map((title, index) => ( + + ))} + + Hisn Al-Muslim + {supplications.map((text, index) => ( + {}} /> + ))} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + innerContainer: { + paddingHorizontal: 15, + }, + title: { + fontSize: 22, + fontWeight: 'bold', + marginVertical: 15, + }, + sectionTitle: { + fontSize: 20, + fontWeight: 'bold', + color: '#fff', + marginVertical: 10, + } +}); diff --git a/app/(tabs)/two.tsx b/app/(tabs)/two.tsx deleted file mode 100644 index f2ea47e..0000000 --- a/app/(tabs)/two.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { StyleSheet } from 'react-native'; - -import EditScreenInfo from '@/components/EditScreenInfo'; -import { Text, View } from '@/components/Themed'; - -export default function TabTwoScreen() { - return ( - - Tab Two - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - fontSize: 20, - fontWeight: 'bold', - }, - separator: { - marginVertical: 30, - height: 1, - width: '80%', - }, -}); diff --git a/components/AdhkarCard.tsx b/components/AdhkarCard.tsx new file mode 100644 index 0000000..c19f4de --- /dev/null +++ b/components/AdhkarCard.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import Colors from '@/constants/Colors'; + +type AdhkarCardProps = { + title: string; +}; + +export default function AdhkarCard({ title }: AdhkarCardProps) { + const colorScheme = 'dark'; + + return ( + + {title} + + ); +} + +const styles = StyleSheet.create({ + container: { + borderRadius: 15, + padding: 20, + marginVertical: 10, + }, + title: { + fontSize: 16, + fontWeight: 'bold', + color: Colors.dark.text, + }, +}); diff --git a/components/FeatureCard.tsx b/components/FeatureCard.tsx new file mode 100644 index 0000000..5bcb3fc --- /dev/null +++ b/components/FeatureCard.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import Colors from '@/constants/Colors'; +import { FontAwesome } from '@expo/vector-icons'; + +type FeatureCardProps = { + title: string; + description: string; + isNew?: boolean; +}; + +export default function FeatureCard({ title, description, isNew = false }: FeatureCardProps) { + const colorScheme = 'dark'; // Assuming a dark theme + + return ( + + {isNew && ( + + New Experience + + )} + + + {title} + {description} + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + borderRadius: 15, + padding: 15, + marginVertical: 10, + }, + newBadge: { + backgroundColor: Colors.dark.tint, + borderRadius: 7, + paddingVertical: 4, + paddingHorizontal: 8, + alignSelf: 'flex-start', + marginBottom: 10, + }, + newText: { + color: Colors.dark.secondary, + fontWeight: 'bold', + fontSize: 12, + }, + content: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, + title: { + fontSize: 18, + fontWeight: 'bold', + color: Colors.dark.text, + }, + description: { + fontSize: 14, + color: Colors.dark.textSecondary, + marginTop: 5, + }, +}); diff --git a/components/PrayerTimeCard.tsx b/components/PrayerTimeCard.tsx new file mode 100644 index 0000000..3c613c5 --- /dev/null +++ b/components/PrayerTimeCard.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { View, Text, StyleSheet, ImageBackground } from 'react-native'; +import Colors from '@/constants/Colors'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; + +const prayerTimes = [ + { name: 'Al-fajr', time: '04:48 AM', icon: 'weather-sunset-up' }, + { name: 'Sunrise', time: '06:20 AM', icon: 'weather-sunny' }, + { name: 'Dhohr', time: '01:06 PM', icon: 'weather-partly-cloudy' }, + { name: 'Asr', time: '04:50 PM', icon: 'weather-cloudy' }, + { name: 'Maghreb', time: '07:51 PM', icon: 'weather-sunset-down' }, + { name: 'Isha', time: '09:02 PM', icon: 'weather-night' }, +]; + +export default function PrayerTimeCard() { + const colorScheme = 'dark'; + + return ( + + + + + Mashhad, Iran + + Left on Maghreb prayer + 49:44 + + {prayerTimes.map((prayer, index) => ( + + + {prayer.name} + {prayer.time} + + ))} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + marginVertical: 20, + borderRadius: 15, + }, + overlay: { + backgroundColor: 'rgba(0,0,0,0.5)', + borderRadius: 15, + padding: 20, + }, + header: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 20, + }, + location: { + color: Colors.dark.text, + marginLeft: 10, + }, + remainingTimeLabel: { + color: Colors.dark.textSecondary, + textAlign: 'center', + }, + remainingTime: { + color: Colors.dark.text, + fontSize: 48, + fontWeight: 'bold', + textAlign: 'center', + marginVertical: 10, + }, + prayerTimesContainer: { + flexDirection: 'row', + justifyContent: 'space-around', + marginTop: 20, + }, + prayerTimeItem: { + alignItems: 'center', + }, + prayerName: { + color: Colors.dark.text, + marginTop: 5, + }, + prayerTime: { + color: Colors.dark.textSecondary, + fontSize: 12, + }, +}); diff --git a/components/ServicesGrid.tsx b/components/ServicesGrid.tsx new file mode 100644 index 0000000..326bc59 --- /dev/null +++ b/components/ServicesGrid.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import Colors from '@/constants/Colors'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; + +const services = [ + { name: 'Qur\'an', icon: 'book-open-variant' }, + { name: 'Hadith', icon: 'book-open-page-variant' }, + { name: 'Du\'a', icon: 'human-greeting' }, +]; + +export default function ServicesGrid() { + const colorScheme = 'dark'; + + return ( + + Services to Enrich Your Spiritual Experience + + {services.map((service, index) => ( + + + + + {service.name} + + ))} + + + ); +} + +const styles = StyleSheet.create({ + container: { + marginVertical: 20, + }, + title: { + fontSize: 18, + fontWeight: 'bold', + color: Colors.dark.text, + marginBottom: 15, + }, + grid: { + flexDirection: 'row', + justifyContent: 'space-around', + }, + serviceItem: { + alignItems: 'center', + }, + iconContainer: { + width: 60, + height: 60, + borderRadius: 15, + justifyContent: 'center', + alignItems: 'center', + marginBottom: 10, + }, + serviceName: { + color: Colors.dark.text, + fontSize: 14, + }, +}); diff --git a/components/SupplicationListItem.tsx b/components/SupplicationListItem.tsx new file mode 100644 index 0000000..586d714 --- /dev/null +++ b/components/SupplicationListItem.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { View, Text, StyleSheet, Pressable } from 'react-native'; +import Colors from '@/constants/Colors'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; + +type SupplicationListItemProps = { + text: string; + onPress: () => void; +}; + +export default function SupplicationListItem({ text, onPress }: SupplicationListItemProps) { + const colorScheme = 'dark'; + + return ( + + {text} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingVertical: 20, + borderBottomWidth: 1, + borderBottomColor: Colors.dark.secondary, + }, + text: { + fontSize: 16, + color: Colors.dark.text, + flex: 1, + }, +}); diff --git a/constants/Colors.ts b/constants/Colors.ts index 1c706c7..355709a 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -1,19 +1,30 @@ -const tintColorLight = '#2f95dc'; -const tintColorDark = '#fff'; +const primary = '#1C1C1E'; // A deep, dark gray, almost black +const secondary = '#2C2C2E'; // A slightly lighter gray for cards and surfaces +const accent = '#D4AF37'; // A gold/yellow accent for highlights and buttons +const text = '#FFFFFF'; +const textSecondary = '#8E8E93'; // A muted gray for secondary text export default { light: { text: '#000', background: '#fff', - tint: tintColorLight, + tint: accent, tabIconDefault: '#ccc', - tabIconSelected: tintColorLight, + tabIconSelected: accent, + primary, + secondary, + accent, + textSecondary, }, dark: { - text: '#fff', - background: '#000', - tint: tintColorDark, + text: text, + background: primary, + tint: accent, tabIconDefault: '#ccc', - tabIconSelected: tintColorDark, + tabIconSelected: accent, + primary, + secondary, + accent, + textSecondary, }, }; diff --git a/package-lock.json b/package-lock.json index 4c2326e..3c8a49d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,11 +24,13 @@ "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1", + "react-native-vector-icons": "^10.3.0", "react-native-web": "~0.20.0" }, "devDependencies": { "@babel/core": "^7.25.2", "@types/react": "~19.0.10", + "@types/react-native-vector-icons": "^6.4.18", "jest": "^29.2.1", "jest-expo": "~53.0.9", "react-test-renderer": "19.0.0", @@ -2961,6 +2963,25 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-native": { + "version": "0.70.19", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.19.tgz", + "integrity": "sha512-c6WbyCgWTBgKKMESj/8b4w+zWcZSsCforson7UdXtXMecG3MxCinYi6ihhrHVPyUrVzORsvEzK8zg32z4pK6Sg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-native-vector-icons": { + "version": "6.4.18", + "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.18.tgz", + "integrity": "sha512-YGlNWb+k5laTBHd7+uZowB9DpIK3SXUneZqAiKQaj1jnJCZM0x71GDim5JCTMi4IFkhc9m8H/Gm28T5BjyivUw==", + "dev": true, + "dependencies": { + "@types/react": "*", + "@types/react-native": "^0.70" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -8510,6 +8531,21 @@ "node": ">= 6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/psl": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", @@ -8826,6 +8862,86 @@ "react-native": "*" } }, + "node_modules/react-native-vector-icons": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz", + "integrity": "sha512-IFQ0RE57819hOUdFvgK4FowM5aMXg7C7XKsuGLevqXkkIJatc3QopN0wYrb2IrzUgmdpfP+QVIbI3S6h7M0btw==", + "deprecated": "react-native-vector-icons package has moved to a new model of per-icon-family packages. See the https://github.com/oblador/react-native-vector-icons/blob/master/MIGRATION.md on how to migrate", + "dependencies": { + "prop-types": "^15.7.2", + "yargs": "^16.1.1" + }, + "bin": { + "fa-upgrade.sh": "bin/fa-upgrade.sh", + "fa5-upgrade": "bin/fa5-upgrade.sh", + "fa6-upgrade": "bin/fa6-upgrade.sh", + "generate-icon": "bin/generate-icon.js" + } + }, + "node_modules/react-native-vector-icons/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/react-native-vector-icons/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/react-native-vector-icons/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-vector-icons/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-vector-icons/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-vector-icons/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/react-native-web": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz", diff --git a/package.json b/package.json index 4556709..33d15e3 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,13 @@ "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1", + "react-native-vector-icons": "^10.3.0", "react-native-web": "~0.20.0" }, "devDependencies": { "@babel/core": "^7.25.2", "@types/react": "~19.0.10", + "@types/react-native-vector-icons": "^6.4.18", "jest": "^29.2.1", "jest-expo": "~53.0.9", "react-test-renderer": "19.0.0",