├── assets
├── images
│ ├── icon.png
│ ├── favicon.png
│ ├── react-logo.png
│ ├── adaptive-icon.png
│ ├── react-logo@2x.png
│ ├── react-logo@3x.png
│ ├── splash-icon.png
│ └── partial-react-logo.png
└── fonts
│ └── SpaceMono-Regular.ttf
├── styles
├── theme
│ ├── borderRadius.ts
│ ├── index.ts
│ ├── spacing.ts
│ ├── typography.ts
│ ├── shadows.ts
│ └── colors.ts
└── globalStyles.ts
├── tsconfig.json
├── hooks
└── useBottomTabOverflow.ts
├── app
├── +not-found.tsx
├── _layout.tsx
├── quranbookk.tsx
├── (tabs)
│ ├── create.tsx
│ ├── profile.tsx
│ ├── notifications.tsx
│ ├── explore.tsx
│ ├── _layout.tsx
│ └── index.tsx
├── about.tsx
└── mixture.tsx
├── eas.json
├── .gitignore
├── utils
└── icon_mapping.ts
├── components
├── ui
│ ├── ExternalLink.tsx
│ ├── HapticButton.tsx
│ ├── WebViewContent.tsx
│ ├── IconSymbol.tsx
│ ├── IconSymbol.ios.tsx
│ └── LargeScreenTab.tsx
├── HelloWave.tsx
├── Collapsable.tsx
└── ParallaxEffect.tsx
├── constants
└── customThemes.ts
├── app.json
├── README.md
└── package.json
/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/icon.png
--------------------------------------------------------------------------------
/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/favicon.png
--------------------------------------------------------------------------------
/assets/images/react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/react-logo.png
--------------------------------------------------------------------------------
/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/assets/images/react-logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/react-logo@2x.png
--------------------------------------------------------------------------------
/assets/images/react-logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/react-logo@3x.png
--------------------------------------------------------------------------------
/assets/images/splash-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/splash-icon.png
--------------------------------------------------------------------------------
/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/partial-react-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farhan7reza7/rename-and-push-7/HEAD/assets/images/partial-react-logo.png
--------------------------------------------------------------------------------
/styles/theme/borderRadius.ts:
--------------------------------------------------------------------------------
1 | export const borderRadius = {
2 | none: 0,
3 | sm: 2,
4 | DEFAULT: 4,
5 | md: 6,
6 | lg: 8,
7 | xl: 12,
8 | "2xl": 16,
9 | "3xl": 24,
10 | full: 9999,
11 | };
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "paths": {
6 | "@/*": [
7 | "./*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "**/*.ts",
13 | "**/*.tsx",
14 | ".expo/types/**/*.ts",
15 | "expo-env.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/hooks/useBottomTabOverflow.ts:
--------------------------------------------------------------------------------
1 | import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
2 | import { useSafeAreaInsets } from "react-native-safe-area-context";
3 |
4 | const useBottomTabOverflow = () => {
5 | const tabHeight = useBottomTabBarHeight();
6 | const { bottom } = useSafeAreaInsets();
7 | return tabHeight - bottom;
8 | };
9 |
10 | export default useBottomTabOverflow;
11 |
--------------------------------------------------------------------------------
/styles/globalStyles.ts:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from "react-native";
2 | import theme from "./theme";
3 |
4 | const globalStyles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | },
8 | card: {
9 | padding: 16,
10 | backgroundColor: theme.colors.white,
11 | color: theme.colors.gray[900],
12 | borderRadius: theme.borderRadius.md,
13 | ...theme.shadows.md,
14 | },
15 | });
16 |
17 | export default globalStyles;
18 |
--------------------------------------------------------------------------------
/app/+not-found.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from "react-native";
2 |
3 | export default function NotFound() {
4 | return (
5 |
6 | Not Found - 404
7 |
8 | );
9 | }
10 |
11 | const styles = StyleSheet.create({
12 | container: {
13 | flex: 1,
14 | justifyContent: "center",
15 | alignItems: "center",
16 | },
17 | text: {
18 | fontSize: 24,
19 | color: "#000",
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/eas.json:
--------------------------------------------------------------------------------
1 | {
2 | "cli": {
3 | "version": ">= 15.0.12",
4 | "appVersionSource": "remote"
5 | },
6 | "build": {
7 | "development": {
8 | "developmentClient": true,
9 | "distribution": "internal",
10 | "channel": "development"
11 | },
12 | "preview": {
13 | "distribution": "internal",
14 | "channel": "preview"
15 | },
16 | "production": {
17 | "autoIncrement": true,
18 | "channel": "production"
19 | }
20 | },
21 | "submit": {
22 | "production": {}
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
2 |
3 | # dependencies
4 | node_modules/
5 |
6 | # Expo
7 | .expo/
8 | dist/
9 | web-build/
10 | expo-env.d.ts
11 |
12 | # Native
13 | *.orig.*
14 | *.jks
15 | *.p8
16 | *.p12
17 | *.key
18 | *.mobileprovision
19 |
20 | # Metro
21 | .metro-health-check*
22 |
23 | # debug
24 | npm-debug.*
25 | yarn-debug.*
26 | yarn-error.*
27 |
28 | # macOS
29 | .DS_Store
30 | *.pem
31 |
32 | # local env files
33 | .env*.local
34 |
35 | # typescript
36 | *.tsbuildinfo
37 |
38 | app-example
39 |
--------------------------------------------------------------------------------
/utils/icon_mapping.ts:
--------------------------------------------------------------------------------
1 | import { MaterialIcons } from "@expo/vector-icons";
2 | import { SymbolViewProps } from "expo-symbols";
3 | import { ComponentProps } from "react";
4 |
5 | const Icon_Mapping: Partial<
6 | Record["name"]>
7 | > = {
8 | "house.fill": "home",
9 | "paperplane.fill": "send",
10 | "square.and.pencil": "create",
11 | "bell.fill": "notifications",
12 | "person.fill": "person",
13 | "chevron.right": "chevron-right",
14 | "chevron.down": "expand-more",
15 | };
16 |
17 | export default Icon_Mapping;
18 |
--------------------------------------------------------------------------------
/components/ui/ExternalLink.tsx:
--------------------------------------------------------------------------------
1 | import { ExternalPathString, Link, type LinkProps } from "expo-router";
2 | import { openBrowserAsync } from "expo-web-browser";
3 | import { Platform } from "react-native";
4 |
5 | type Props = Omit & {
6 | href: ExternalPathString;
7 | };
8 |
9 | const ExternalLink = ({ href, ...rest }: Props) => (
10 | {
15 | if (Platform.OS !== "web") {
16 | e.preventDefault();
17 | openBrowserAsync(href);
18 | }
19 | }}
20 | />
21 | );
22 |
23 | export default ExternalLink;
24 |
--------------------------------------------------------------------------------
/styles/theme/index.ts:
--------------------------------------------------------------------------------
1 | import { colors } from "./colors";
2 | import { typography } from "./typography";
3 | import { borderRadius } from "./borderRadius";
4 | import { dropShadows, shadows } from "./shadows";
5 |
6 | const theme = {
7 | colors,
8 | typography,
9 | borderRadius,
10 | shadows,
11 | dropShadows,
12 | } as const;
13 |
14 | export default theme;
15 |
16 | export type ThemeColors = typeof theme.colors;
17 | export type ThemeTypography = typeof theme.typography;
18 | export type ThemeBorderRadius = typeof theme.borderRadius;
19 | export type ThemeShadows = typeof theme.dropShadows;
20 | export type Shadows = typeof theme.shadows;
21 | export type Theme = typeof theme;
22 |
--------------------------------------------------------------------------------
/styles/theme/spacing.ts:
--------------------------------------------------------------------------------
1 | export const spacing = {
2 | none: 0,
3 | xs: 4,
4 | sm: 8,
5 | md: 16,
6 | lg: 24,
7 | xl: 32,
8 | "2xl": 48,
9 | "3xl": 64,
10 | px: 1,
11 | 0: 0,
12 | 0.5: 2,
13 | 1: 4,
14 | 1.5: 6,
15 | 2: 8,
16 | 2.5: 10,
17 | 3: 12,
18 | 3.5: 14,
19 | 4: 16,
20 | 5: 20,
21 | 6: 24,
22 | 7: 28,
23 | 8: 32,
24 | 9: 36,
25 | 10: 40,
26 | 11: 44,
27 | 12: 48,
28 | 14: 56,
29 | 16: 64,
30 | 20: 80,
31 | 24: 96,
32 | 28: 112,
33 | 32: 128,
34 | 36: 144,
35 | 40: 160,
36 | 44: 176,
37 | 48: 192,
38 | 52: 208,
39 | 56: 224,
40 | 60: 240,
41 | 64: 256,
42 | 72: 288,
43 | 80: 320,
44 | 96: 384,
45 | };
46 |
--------------------------------------------------------------------------------
/components/ui/HapticButton.tsx:
--------------------------------------------------------------------------------
1 | import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
2 | import { PlatformPressable } from "@react-navigation/elements";
3 | import * as Haptics from "expo-haptics";
4 |
5 | const HapticButton = (props: BottomTabBarButtonProps) => {
6 | //if (props.href === "/about") return;
7 | return (
8 | {
11 | if (process.env.EXPO_OS !== "web") {
12 | Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(
13 | () => {}
14 | );
15 | }
16 | props.onPressIn?.(e);
17 | }}
18 | android_ripple={{
19 | // Adjust the radius to control ripple size
20 | radius: 50,
21 | // Optionally, customize the ripple color
22 | //color: "rgba(0,0,0,0.1)",
23 | }}
24 | />
25 | );
26 | };
27 |
28 | export default HapticButton;
29 |
--------------------------------------------------------------------------------
/constants/customThemes.ts:
--------------------------------------------------------------------------------
1 | import { DarkTheme, DefaultTheme } from "@react-navigation/native";
2 |
3 | const tintColorLight = "#0a7ea4";
4 | const tintColorDark = "#fff";
5 |
6 | const CustomDarkTheme = {
7 | ...DarkTheme,
8 | colors: {
9 | ...DarkTheme.colors,
10 | primary: "blue",
11 | tint: tintColorDark,
12 | icon: "#9BA1A6",
13 | tabIconDefault: "#9BA1A6",
14 | tabIconSelected: tintColorDark,
15 | },
16 | };
17 |
18 | const CustomLightTheme = {
19 | ...DefaultTheme,
20 | colors: {
21 | ...DefaultTheme.colors,
22 | primary: "deeppink",
23 | /*NavBar related
24 | //text: "red",
25 | //card: "red",
26 | //notification: "red",
27 | //border: "red",*/
28 | tint: tintColorLight,
29 | icon: "#687076",
30 | tabIconDefault: "#687076",
31 | tabIconSelected: tintColorLight,
32 | },
33 | };
34 |
35 | export { CustomLightTheme, CustomDarkTheme };
36 |
--------------------------------------------------------------------------------
/components/HelloWave.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { StyleSheet, Text } from "react-native";
3 | import Animated, {
4 | Easing,
5 | useAnimatedStyle,
6 | useSharedValue,
7 | withRepeat,
8 | withSequence,
9 | withTiming,
10 | } from "react-native-reanimated";
11 |
12 | const HelloWave = () => {
13 | const deg = useSharedValue(0);
14 |
15 | useEffect(() => {
16 | deg.value = withRepeat(
17 | withSequence(
18 | withTiming(25, { duration: 150, easing: Easing.inOut(Easing.ease) }),
19 | withTiming(0, { duration: 150 })
20 | ),
21 | 4
22 | );
23 | }, []);
24 |
25 | const animatedStyle = useAnimatedStyle(() => ({
26 | transform: [{ rotate: deg.value + "deg" }],
27 | }));
28 |
29 | return (
30 |
31 | 👋
32 |
33 | );
34 | };
35 |
36 | const ss = StyleSheet.create({
37 | animatedText: {
38 | fontSize: 28,
39 | marginTop: -10,
40 | },
41 | });
42 |
43 | export default HelloWave;
44 |
--------------------------------------------------------------------------------
/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from "@react-navigation/native";
2 | import { Stack } from "expo-router";
3 | import { useMemo } from "react";
4 | import { useColorScheme } from "react-native";
5 | import { SafeAreaProvider } from "react-native-safe-area-context";
6 | import { CustomDarkTheme, CustomLightTheme } from "@/constants/customThemes";
7 | import { GestureHandlerRootView } from "react-native-gesture-handler";
8 |
9 | export default function RootLayout() {
10 | const colorScheme = useColorScheme();
11 |
12 | const theme = useMemo(
13 | () => (colorScheme === "dark" ? CustomDarkTheme : CustomLightTheme),
14 | [colorScheme]
15 | );
16 |
17 | return (
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/components/ui/WebViewContent.tsx:
--------------------------------------------------------------------------------
1 | import { ExternalPathString } from "expo-router";
2 | import { CSSProperties } from "react";
3 | import { Platform, StyleProp, ViewStyle } from "react-native";
4 | import WebView from "react-native-webview";
5 |
6 | interface Props {
7 | source: { uri: ExternalPathString };
8 | style?: StyleProp;
9 | }
10 |
11 | const WebViewContentScrollable = ({ source, style }: Props): JSX.Element => {
12 | if (Platform.OS === "web") {
13 | return (
14 |
15 | );
16 | } else {
17 | return (
18 |
24 | );
25 | }
26 | };
27 |
28 | export const WebViewContent = ({ source, style }: Props): JSX.Element => {
29 | if (Platform.OS === "web") {
30 | return (
31 |
32 | );
33 | } else {
34 | return ;
35 | }
36 | };
37 |
38 | export default WebViewContentScrollable;
39 |
--------------------------------------------------------------------------------
/components/ui/IconSymbol.tsx:
--------------------------------------------------------------------------------
1 | import { MaterialIcons } from "@expo/vector-icons";
2 | import {
3 | OpaqueColorValue,
4 | StyleProp,
5 | TextStyle,
6 | useWindowDimensions,
7 | } from "react-native";
8 | import Icon_Mapping from "@/utils/icon_mapping";
9 | import { useMemo } from "react";
10 | import { useTheme } from "@react-navigation/native";
11 |
12 | interface Props {
13 | name: keyof typeof Icon_Mapping;
14 | size?: number;
15 | color?: string | OpaqueColorValue;
16 | style?: StyleProp;
17 | accessible?: boolean;
18 | accessibilityLabel?: string;
19 | }
20 |
21 | const IconSymbol = ({
22 | name,
23 | size = 24,
24 | color,
25 | style,
26 | accessible = true,
27 | accessibilityLabel,
28 | }: Props): JSX.Element => {
29 | const { fontScale } = useWindowDimensions();
30 |
31 | const {
32 | colors: { text },
33 | } = useTheme();
34 |
35 | const { scaledSize, iconColor } = useMemo(
36 | () => ({ scaledSize: size * fontScale, iconColor: color || text }),
37 | [color, text, size, fontScale]
38 | );
39 |
40 | return (
41 |
49 | );
50 | };
51 |
52 | export default IconSymbol;
53 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "tester-app",
4 | "slug": "tester-app",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "com.farhan7fr.testerapp",
9 | "userInterfaceStyle": "automatic",
10 | "newArchEnabled": true,
11 | "ios": {
12 | "supportsTablet": true
13 | },
14 | "android": {
15 | "adaptiveIcon": {
16 | "foregroundImage": "./assets/images/adaptive-icon.png",
17 | "backgroundColor": "#ffffff"
18 | },
19 | "package": "com.farhan7fr.testerapp"
20 | },
21 | "web": {
22 | "bundler": "metro",
23 | "output": "static",
24 | "favicon": "./assets/images/favicon.png"
25 | },
26 | "plugins": [
27 | "expo-router",
28 | "expo-secure-store",
29 | [
30 | "expo-splash-screen",
31 | {
32 | "image": "./assets/images/splash-icon.png",
33 | "imageWidth": 200,
34 | "resizeMode": "contain",
35 | "backgroundColor": "#ffffff"
36 | }
37 | ]
38 | ],
39 | "experiments": {
40 | "typedRoutes": true
41 | },
42 | "extra": {
43 | "router": {
44 | "origin": false
45 | },
46 | "eas": {
47 | "projectId": "632f439a-ef41-457b-b93f-d5f067019b8d"
48 | }
49 | },
50 | "runtimeVersion": {
51 | "policy": "appVersion"
52 | },
53 | "updates": {
54 | "url": "https://u.expo.dev/632f439a-ef41-457b-b93f-d5f067019b8d"
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/components/ui/IconSymbol.ios.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from "@react-navigation/native";
2 | import { SymbolView, SymbolWeight, SymbolViewProps } from "expo-symbols";
3 | import { useMemo } from "react";
4 | import { StyleProp, useWindowDimensions, ViewProps } from "react-native";
5 |
6 | interface Props {
7 | name: SymbolViewProps["name"];
8 | size?: number;
9 | color?: string;
10 | weight?: SymbolWeight;
11 | style?: StyleProp;
12 | accessible?: boolean;
13 | accessibilityLabel?: string;
14 | }
15 |
16 | const IconSymbol = ({
17 | name,
18 | size = 24,
19 | color,
20 | weight = "regular",
21 | style,
22 | accessible = true,
23 | accessibilityLabel,
24 | }: Props): JSX.Element => {
25 | const { fontScale } = useWindowDimensions();
26 | const {
27 | colors: { text },
28 | } = useTheme();
29 |
30 | const { scaledSize, iconColor } = useMemo(
31 | () => ({ scaledSize: size * fontScale, iconColor: color || text }),
32 | [color, text, size, fontScale]
33 | );
34 |
35 | return (
36 |
53 | );
54 | };
55 |
56 | export default IconSymbol;
57 |
--------------------------------------------------------------------------------
/components/Collapsable.tsx:
--------------------------------------------------------------------------------
1 | import { useState, PropsWithChildren, useCallback } from "react";
2 | import IconSymbol from "./ui/IconSymbol";
3 | import { Pressable, StyleSheet, View, type ViewStyle } from "react-native";
4 | import { Text } from "react-native";
5 | import { useTheme } from "@react-navigation/native";
6 |
7 | type Props = {
8 | title: string;
9 | style?: ViewStyle;
10 | };
11 |
12 | const Collapsable = ({ title, children, style }: PropsWithChildren) => {
13 | const [isOpen, setIsOpen] = useState(false);
14 | const toggle = useCallback(() => {
15 | setIsOpen((v) => !v);
16 | }, []);
17 |
18 | const {
19 | colors: { background, text },
20 | } = useTheme();
21 |
22 | return (
23 |
24 |
25 |
36 | {title}
37 |
38 | {isOpen && {children}}
39 |
40 | );
41 | };
42 |
43 | const ss = StyleSheet.create({
44 | container: { padding: 5, borderRadius: 5, width: "100%", gap: 6 },
45 | button: { flexDirection: "row", alignItems: "center", gap: 6 },
46 | title: { fontWeight: "bold" },
47 | children: { paddingLeft: 24 },
48 | });
49 |
50 | export default Collapsable;
51 |
--------------------------------------------------------------------------------
/app/quranbookk.tsx:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from "react";
2 | import {
3 | ActivityIndicator,
4 | StyleSheet,
5 | useColorScheme,
6 | View,
7 | } from "react-native";
8 | import * as SplashScreen from "expo-splash-screen";
9 | import WebView from "react-native-webview";
10 |
11 | SplashScreen.preventAutoHideAsync();
12 |
13 | export default function QuranBookkApp() {
14 | const [isLoaded, setIsLoaded] = useState(false);
15 | const colorScheme = useColorScheme();
16 |
17 | /*const handleStart = useCallback(async () => {
18 | setIsLoaded(false);
19 | await SplashScreen.preventAutoHideAsync();
20 | }, []);*/
21 |
22 | const handleLoaded = useCallback(async () => {
23 | await SplashScreen.hideAsync();
24 | setIsLoaded(true);
25 | }, []);
26 |
27 | return (
28 |
29 | {!isLoaded && (
30 |
31 |
32 |
33 | )}
34 |
43 |
44 | );
45 | }
46 |
47 | const ss = StyleSheet.create({
48 | container: { flex: 1 },
49 | webview: {
50 | flex: 1,
51 | borderWidth: 0,
52 | },
53 | loaderContainer: {
54 | ...StyleSheet.absoluteFillObject,
55 | justifyContent: "center",
56 | alignItems: "center",
57 | backgroundColor: "rgba(0,0,0, 0.3)",
58 | zIndex: 1,
59 | },
60 | });
61 |
--------------------------------------------------------------------------------
/app/(tabs)/create.tsx:
--------------------------------------------------------------------------------
1 | import Collapsable from "@/components/Collapsable";
2 | import useBottomTabOverflow from "@/hooks/useBottomTabOverflow";
3 | import { useTheme } from "@react-navigation/native";
4 | import {
5 | ScrollView,
6 | StyleSheet,
7 | Text,
8 | useWindowDimensions,
9 | View,
10 | } from "react-native";
11 |
12 | export default function Create() {
13 | const { width } = useWindowDimensions();
14 | const {
15 | colors: { background, text },
16 | } = useTheme();
17 |
18 | const overflowHeight = useBottomTabOverflow();
19 |
20 | return (
21 |
22 | 768
27 | ? { paddingLeft: 116 }
28 | : { paddingBottom: overflowHeight + 16 },
29 | ]}
30 | >
31 | Create Section
32 | {Array(20)
33 | .fill(0)
34 | .map((_, i) => (
35 |
40 |
41 | {i + 1} First Collapsable, check if work or not
42 |
43 |
44 | ))}
45 |
46 |
47 | );
48 | }
49 |
50 | const styles = StyleSheet.create({
51 | container: {
52 | flex: 1,
53 | },
54 | scrollContainer: {
55 | width: "100%",
56 | },
57 | scrollContent: {
58 | alignItems: "center",
59 | gap: 10,
60 | paddingTop: 50,
61 | padding: 16,
62 | },
63 | text: { color: "#000", fontSize: 24 },
64 | content: {
65 | fontSize: 16,
66 | },
67 | });
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Expo app 👋
2 |
3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
4 |
5 | ## Get started
6 |
7 | 1. Install dependencies
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | 2. Start the app
14 |
15 | ```bash
16 | npx expo start
17 | ```
18 |
19 | In the output, you'll find options to open the app in a
20 |
21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25 |
26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27 |
28 | ## Get a fresh project
29 |
30 | When you're ready, run:
31 |
32 | ```bash
33 | npm run reset-project
34 | ```
35 |
36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
37 |
38 | ## Learn more
39 |
40 | To learn more about developing your project with Expo, look at the following resources:
41 |
42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43 | - [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.
44 |
45 | ## Join the community
46 |
47 | Join our community of developers creating universal apps.
48 |
49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tester-app",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web",
10 | "test": "jest --watchAll",
11 | "lint": "expo lint"
12 | },
13 | "jest": {
14 | "preset": "jest-expo"
15 | },
16 | "dependencies": {
17 | "@expo/vector-icons": "^14.0.2",
18 | "@react-navigation/bottom-tabs": "^7.2.0",
19 | "@react-navigation/native": "^7.0.14",
20 | "expo": "~52.0.37",
21 | "expo-blur": "~14.0.3",
22 | "expo-constants": "~17.0.7",
23 | "expo-font": "~13.0.4",
24 | "expo-haptics": "~14.0.1",
25 | "expo-image": "~2.0.6",
26 | "expo-image-picker": "~16.0.6",
27 | "expo-linking": "~7.0.5",
28 | "expo-media-library": "~17.0.6",
29 | "expo-router": "~4.0.17",
30 | "expo-secure-store": "~14.0.1",
31 | "expo-splash-screen": "~0.29.22",
32 | "expo-status-bar": "~2.0.1",
33 | "expo-symbols": "~0.2.2",
34 | "expo-system-ui": "~4.0.8",
35 | "expo-updates": "~0.27.1",
36 | "expo-web-browser": "~14.0.2",
37 | "html-to-image": "^1.11.13",
38 | "react": "18.3.1",
39 | "react-dom": "18.3.1",
40 | "react-native": "0.76.7",
41 | "react-native-gesture-handler": "~2.20.2",
42 | "react-native-reanimated": "~3.16.1",
43 | "react-native-safe-area-context": "4.12.0",
44 | "react-native-screens": "~4.4.0",
45 | "react-native-view-shot": "~4.0.3",
46 | "react-native-web": "~0.19.13",
47 | "react-native-webview": "13.12.5"
48 | },
49 | "devDependencies": {
50 | "@babel/core": "^7.25.2",
51 | "@types/jest": "^29.5.12",
52 | "@types/react": "~18.3.12",
53 | "@types/react-test-renderer": "^18.3.0",
54 | "jest": "^29.2.1",
55 | "jest-expo": "~52.0.4",
56 | "react-test-renderer": "18.3.1",
57 | "typescript": "^5.3.3"
58 | },
59 | "private": true
60 | }
61 |
--------------------------------------------------------------------------------
/components/ParallaxEffect.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, View } from "react-native";
2 | import Animated, {
3 | interpolate,
4 | useAnimatedRef,
5 | useAnimatedStyle,
6 | useScrollViewOffset,
7 | } from "react-native-reanimated";
8 |
9 | interface Props {
10 | children: JSX.Element;
11 | headerContent: JSX.Element;
12 | HEADER_HEIGHT?: number;
13 | bottom?: number;
14 | }
15 |
16 | const ParallaxEffect = ({
17 | headerContent,
18 | children,
19 | HEADER_HEIGHT = 250,
20 | bottom = 0,
21 | }: Props) => {
22 | const srollRef = useAnimatedRef();
23 | const scrollOffset = useScrollViewOffset(srollRef);
24 | const animatedStyle = useAnimatedStyle(() => {
25 | return {
26 | transform: [
27 | {
28 | translateY: interpolate(
29 | scrollOffset.value,
30 | [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
31 | [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
32 | ),
33 | },
34 | {
35 | scale: interpolate(
36 | scrollOffset.value,
37 | [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
38 | [1, 1, 2]
39 | ),
40 | },
41 | ],
42 | };
43 | });
44 |
45 | return (
46 |
47 |
53 |
56 | {headerContent}
57 |
58 | {children}
59 |
60 |
61 | );
62 | };
63 |
64 | const ss = StyleSheet.create({
65 | container: { flex: 1 },
66 | scrollContent: { overflow: "hidden", flexGrow: 1 },
67 | header: {
68 | overflow: "hidden",
69 | },
70 | children: {
71 | flex: 1,
72 | overflow: "hidden",
73 | },
74 | });
75 |
76 | export default ParallaxEffect;
77 |
--------------------------------------------------------------------------------
/styles/theme/typography.ts:
--------------------------------------------------------------------------------
1 | export const typography = {
2 | fontSize: {
3 | xs: { fontSize: "0.75rem", lineHeight: "1rem" },
4 | sm: { fontSize: "0.875rem", lineHeight: "1.25rem" },
5 | base: { fontSize: "1rem", lineHeight: "1.5rem" },
6 | lg: { fontSize: "1.125rem", lineHeight: "1.75rem" },
7 | xl: { fontSize: "1.25rem", lineHeight: "1.75rem" },
8 | "2xl": { fontSize: "1.5rem", lineHeight: "2rem" },
9 | "3xl": { fontSize: "1.875rem", lineHeight: "2.25rem" },
10 | "4xl": { fontSize: "2.25rem", lineHeight: "2.5rem" },
11 | "5xl": { fontSize: "3rem", lineHeight: "1rem" },
12 | "6xl": { fontSize: "3.75rem", lineHeight: "1" },
13 | "7xl": { fontSize: "4.5rem", lineHeight: "1" },
14 | "8xl": { fontSize: "6rem", lineHeight: "1" },
15 | "9xl": { fontSize: "8rem", lineHeight: "1" },
16 | },
17 | lineHeight: {
18 | none: 1,
19 | tight: 1.25,
20 | snug: 1.375,
21 | normal: 1.5,
22 | relaxed: 1.625,
23 | loose: 2,
24 | },
25 | fontWeight: {
26 | thin: "100",
27 | extralight: "200",
28 | light: "300",
29 | normal: "400",
30 | medium: "500",
31 | semibold: "600",
32 | bold: "700",
33 | extrabold: "800",
34 | black: "900",
35 | },
36 | fontFamily: {
37 | sans: [
38 | "ui-sans-serif",
39 | "system-ui",
40 | "sans-serif",
41 | '"Apple Color Emoji"',
42 | '"Segoe UI Emoji"',
43 | '"Segoe UI Symbol"',
44 | '"Noto Color Emoji"',
45 | ],
46 | serif: [
47 | "ui-serif",
48 | "Georgia",
49 | "Cambria",
50 | '"Times New Roman"',
51 | "Times",
52 | "serif",
53 | ],
54 | mono: [
55 | "ui-monospace",
56 | "SFMono-Regular",
57 | "Menlo",
58 | "Monaco",
59 | "Consolas",
60 | '"Liberation Mono"',
61 | '"Courier New"',
62 | "monospace",
63 | ],
64 | },
65 | h1: {
66 | fontSize: 32,
67 | lineHeight: 40,
68 | fontWeight: "700",
69 | },
70 | h2: {
71 | fontSize: 24,
72 | lineHeight: 32,
73 | fontWeight: "600",
74 | },
75 | };
76 |
--------------------------------------------------------------------------------
/app/(tabs)/profile.tsx:
--------------------------------------------------------------------------------
1 | import Collapsable from "@/components/Collapsable";
2 | import HelloWave from "@/components/HelloWave";
3 | import ParallaxEffect from "@/components/ParallaxEffect";
4 | import useBottomTabOverflow from "@/hooks/useBottomTabOverflow";
5 | import { StyleSheet, Text, useWindowDimensions, View } from "react-native";
6 |
7 | export default function Profile() {
8 | const { width } = useWindowDimensions();
9 | const bottom = useBottomTabOverflow();
10 |
11 | return (
12 |
15 |
16 | Header Section
17 |
18 |
19 | }
20 | bottom={bottom}
21 | >
22 | 768 ? { paddingLeft: 116 } : { paddingBottom: bottom + 16 },
26 | ]}
27 | >
28 |
29 | Profile Section
30 |
31 |
32 |
33 | {Array(20)
34 | .fill(0)
35 | .map((_, i) => (
36 |
41 | Content {i + 1}
42 |
43 | ))}
44 |
45 |
46 |
47 | );
48 | }
49 |
50 | const styles = StyleSheet.create({
51 | container: { flex: 1, backgroundColor: "#fff", padding: 16 },
52 | title: {
53 | justifyContent: "center",
54 | alignItems: "center",
55 | gap: 8,
56 | flexDirection: "row",
57 | },
58 | text: { color: "#000", fontSize: 24 },
59 | collapsables: {
60 | justifyContent: "center",
61 | alignItems: "center",
62 | gap: 5,
63 | },
64 | header: {
65 | flex: 1,
66 | backgroundColor: "lightblue",
67 | alignItems: "center",
68 | justifyContent: "center",
69 | },
70 | });
71 |
--------------------------------------------------------------------------------
/components/ui/LargeScreenTab.tsx:
--------------------------------------------------------------------------------
1 | import { Ionicons } from "@expo/vector-icons";
2 | import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
3 | import { Pressable, StyleSheet, Text } from "react-native";
4 |
5 | interface LargeScreenTabProps extends BottomTabBarButtonProps {
6 | route: { name: string; [key: string]: any };
7 | }
8 |
9 | const LargeScreenTab = (props: LargeScreenTabProps) => {
10 | const { onPress, accessibilityState, route } = props;
11 | const focused = accessibilityState?.selected;
12 |
13 | // Map route names to icon names and titles
14 | const iconMap: Record = {
15 | index: { icon: "home", title: "Home" },
16 | explore: { icon: "send", title: "Explore" },
17 | create: { icon: "create", title: "Create" },
18 | notifications: {
19 | icon: "notifications",
20 | title: "Notifications",
21 | },
22 | profile: { icon: "person", title: "Profile" },
23 | };
24 |
25 | const { icon, title } = iconMap[route.name] || {
26 | icon: "help",
27 | title: route.name,
28 | };
29 |
30 | return (
31 | [
34 | styles.verticalTabButton,
35 | hovered || pressed ? styles.verticalTabHovered : {},
36 | ]}
37 | >
38 |
43 |
49 | {title}
50 |
51 |
52 | );
53 | };
54 |
55 | const styles = StyleSheet.create({
56 | verticalTabButton: {
57 | width: 80,
58 | paddingVertical: 12,
59 | marginVertical: 4,
60 | alignItems: "center",
61 | justifyContent: "center",
62 | },
63 | verticalTabHovered: {
64 | backgroundColor: `rgba(255, 20, 147, 0.1)`,
65 | borderRadius: 10,
66 | },
67 | verticalTabLabel: {
68 | fontSize: 10,
69 | marginTop: 4,
70 | textAlign: "center",
71 | },
72 | });
73 |
74 | export default LargeScreenTab;
75 |
--------------------------------------------------------------------------------
/styles/theme/shadows.ts:
--------------------------------------------------------------------------------
1 | export const shadows = {
2 | sm: {
3 | shadowColor: "#000",
4 | shadowOffset: {
5 | width: 0,
6 | height: 1,
7 | },
8 | shadowOpacity: 0.05,
9 | shadowRadius: 2,
10 | elevation: 1,
11 | },
12 | DEFAULT: {
13 | shadowColor: "#000",
14 | shadowOffset: {
15 | width: 0,
16 | height: 1,
17 | },
18 | shadowOpacity: 0.1,
19 | shadowRadius: 3,
20 | elevation: 2,
21 | },
22 | md: {
23 | shadowColor: "#000",
24 | shadowOffset: {
25 | width: 0,
26 | height: 4,
27 | },
28 | shadowOpacity: 0.1,
29 | shadowRadius: 6,
30 | elevation: 3,
31 | },
32 | lg: {
33 | shadowColor: "#000",
34 | shadowOffset: {
35 | width: 0,
36 | height: 10,
37 | },
38 | shadowOpacity: 0.1,
39 | shadowRadius: 15,
40 | elevation: 4,
41 | },
42 | xl: {
43 | shadowColor: "#000",
44 | shadowOffset: {
45 | width: 0,
46 | height: 20,
47 | },
48 | shadowOpacity: 0.1,
49 | shadowRadius: 25,
50 | elevation: 5,
51 | },
52 | "2xl": {
53 | shadowColor: "#000",
54 | shadowOffset: {
55 | width: 0,
56 | height: 25,
57 | },
58 | shadowOpacity: 0.25,
59 | shadowRadius: 50,
60 | elevation: 6,
61 | },
62 | inner: {
63 | shadowColor: "#000",
64 | shadowOffset: {
65 | width: 0,
66 | height: 2,
67 | },
68 | shadowOpacity: 0.05,
69 | shadowRadius: 4,
70 | elevation: 1,
71 | },
72 | none: {
73 | shadowColor: "#000",
74 | shadowOffset: {
75 | width: 0,
76 | height: 0,
77 | },
78 | shadowOpacity: 0,
79 | shadowRadius: 0,
80 | elevation: 0,
81 | },
82 | };
83 |
84 | export const dropShadows = {
85 | sm: {
86 | shadowColor: "#000",
87 | shadowOffset: {
88 | width: 0,
89 | height: 1,
90 | },
91 | shadowOpacity: 0.2,
92 | shadowRadius: 1.41,
93 | elevation: 2,
94 | },
95 | DEFAULT: {
96 | shadowColor: "#000",
97 | shadowOffset: {
98 | width: 0,
99 | height: 2,
100 | },
101 | shadowOpacity: 0.25,
102 | shadowRadius: 3.84,
103 | elevation: 5,
104 | },
105 | lg: {
106 | shadowColor: "#000",
107 | shadowOffset: {
108 | width: 0,
109 | height: 4,
110 | },
111 | shadowOpacity: 0.3,
112 | shadowRadius: 4.65,
113 | elevation: 8,
114 | },
115 | xl: {
116 | shadowColor: "#000",
117 | shadowOffset: {
118 | width: 0,
119 | height: 6,
120 | },
121 | shadowOpacity: 0.37,
122 | shadowRadius: 7.49,
123 | elevation: 12,
124 | },
125 | };
126 |
--------------------------------------------------------------------------------
/app/(tabs)/notifications.tsx:
--------------------------------------------------------------------------------
1 | import ExternalLink from "@/components/ui/ExternalLink";
2 | import { StyleSheet, Text, View } from "react-native";
3 | import Animated, {
4 | useAnimatedStyle,
5 | useSharedValue,
6 | withSpring,
7 | } from "react-native-reanimated";
8 | import { GestureDetector, Gesture } from "react-native-gesture-handler";
9 |
10 | export default function Notifications({ size = 50 }) {
11 | const scaledSize = useSharedValue(size);
12 | const translateX = useSharedValue(0);
13 | const translateY = useSharedValue(0);
14 |
15 | const doubleTap = Gesture.Tap()
16 | .numberOfTaps(2)
17 | .onStart(() => {
18 | const newSize =
19 | scaledSize.value === 2 * size
20 | ? Math.round(scaledSize.value / 2)
21 | : 2 * size;
22 |
23 | scaledSize.value = withSpring(newSize);
24 | });
25 |
26 | const styledProps = useAnimatedStyle(() => {
27 | return {
28 | width: scaledSize.value,
29 | height: scaledSize.value,
30 | };
31 | });
32 |
33 | const drag = Gesture.Pan()
34 | .onUpdate((event) => {
35 | translateX.value = event.translationX;
36 | translateY.value = event.translationY;
37 | })
38 | .onEnd(() => {
39 | translateX.value = withSpring(0);
40 | translateY.value = withSpring(0);
41 | });
42 |
43 | /*.onChange((e) => {
44 | translateX.value += e.changeX;
45 | translateY.value += e.changeY;
46 | });*/
47 |
48 | const containerStyle = useAnimatedStyle(() => ({
49 | transform: [
50 | { translateX: translateX.value },
51 | { translateY: translateY.value },
52 | ],
53 | }));
54 |
55 | return (
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | Notifications Section
65 |
66 |
67 | Go to Portfolio
68 |
69 |
70 |
71 | );
72 | }
73 |
74 | const styles = StyleSheet.create({
75 | container: {
76 | flex: 1,
77 | justifyContent: "center",
78 | alignItems: "center",
79 | backgroundColor: "#000",
80 | padding: 16,
81 | paddingBottom: 66,
82 | gap: 10,
83 | },
84 | bounceContainer: { backgroundColor: "#fff", padding: 10 },
85 | text: { color: "#fff", fontSize: 24 },
86 | link: { color: "blue", fontSize: 18, textAlign: "center" },
87 | linkContainer: { backgroundColor: "#fff", borderRadius: 10, padding: 10 },
88 | bounce: {
89 | backgroundColor: "indigo",
90 | borderRadius: "50%",
91 | width: 50,
92 | height: 50,
93 | },
94 | });
95 |
--------------------------------------------------------------------------------
/app/about.tsx:
--------------------------------------------------------------------------------
1 | import HelloWave from "@/components/HelloWave";
2 | import ParallaxEffect from "@/components/ParallaxEffect";
3 | import { Platform, StyleSheet, Text, View } from "react-native";
4 | import { Image } from "expo-image";
5 |
6 | export default function About() {
7 | return (
8 |
11 |
16 |
17 | }
18 | >
19 |
20 |
21 | Welcome!
22 |
23 |
24 |
25 | Step 1: Try it
26 |
27 | Edit app/(tabs)/index.tsx to see changes. Press{" "}
28 |
29 | {Platform.select({
30 | ios: "cmd + d",
31 | android: "cmd + m",
32 | web: "F12",
33 | })}
34 | {" "}
35 | to open developer tools.
36 |
37 |
38 |
39 | Step 2: Explore
40 |
41 | Tap the Explore tab to learn more about what's included in this
42 | starter app.
43 |
44 |
45 |
46 | Step 3: Get a fresh start
47 |
48 | When you're ready, run npm run reset-project to get a
49 | fresh app directory. This will move the current{" "}
50 | app to app-example.
51 |
52 |
53 |
54 | Step 4: Try it
55 |
56 | Edit app/(tabs)/index.tsx to see changes. Press{" "}
57 |
58 | {Platform.select({
59 | ios: "cmd + d",
60 | android: "cmd + m",
61 | web: "F12",
62 | })}
63 | {" "}
64 | to open developer tools.
65 |
66 |
67 |
68 | Step 5: Explore
69 |
70 | Tap the Explore tab to learn more about what's included in this
71 | starter app.
72 |
73 |
74 |
75 | Step 6: Get a fresh start
76 |
77 | When you're ready, run npm run reset-project to get a
78 | fresh app directory. This will move the current{" "}
79 | app to app-example.
80 |
81 |
82 |
83 |
84 | );
85 | }
86 |
87 | const styles = StyleSheet.create({
88 | container: { flex: 1, backgroundColor: "#fff", padding: 16, gap: 15 },
89 | title: {
90 | alignItems: "center",
91 | gap: 8,
92 | flexDirection: "row",
93 | },
94 | text: { color: "#000", fontSize: 32, fontWeight: "bold" },
95 | collapsables: {
96 | justifyContent: "center",
97 | alignItems: "center",
98 | gap: 5,
99 | },
100 | header: {
101 | flex: 1,
102 | backgroundColor: "lightblue",
103 | alignItems: "center",
104 | justifyContent: "center",
105 | },
106 | reactLogo: {
107 | height: 178,
108 | width: 290,
109 | bottom: 0,
110 | left: 0,
111 | position: "absolute",
112 | },
113 | stepContainer: { gap: 8, marginBottom: 8 },
114 | stepText: { fontWeight: "bold", fontSize: 18 },
115 | });
116 |
--------------------------------------------------------------------------------
/app/(tabs)/explore.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from "@react-navigation/native";
2 | import { Image } from "expo-image";
3 | import { Link } from "expo-router";
4 | import { useCallback, useRef, useState } from "react";
5 | import { Pressable, StyleSheet, Text, View, Modal, Alert } from "react-native";
6 | import * as imagePicker from "expo-image-picker";
7 | import { BlurView } from "expo-blur";
8 |
9 | export default function Explore() {
10 | const [picked, setPicked] = useState(undefined);
11 | const [isOpen, setIsOpen] = useState(false);
12 | const isPermisssion = useRef(false);
13 |
14 | const {
15 | colors: { primary },
16 | } = useTheme();
17 |
18 | const requestPermissison = useCallback(async () => {
19 | if (isPermisssion.current) return true;
20 | const { status } = await imagePicker.requestMediaLibraryPermissionsAsync();
21 | if (!status) {
22 | Alert.alert(
23 | "Permissions required",
24 | "This app needs camera and media library permissions to work properly!"
25 | );
26 | return false;
27 | } else {
28 | isPermisssion.current = true;
29 | return true;
30 | }
31 | }, []);
32 |
33 | const handleImgPicker = useCallback(async () => {
34 | if (!(await requestPermissison())) return;
35 | const result = await imagePicker.launchImageLibraryAsync({
36 | mediaTypes: ["images", "livePhotos"],
37 | allowsEditing: true,
38 | quality: 1,
39 | });
40 | if (!result.canceled) {
41 | setPicked(result.assets[0].uri);
42 | setIsOpen(true);
43 | } else {
44 | Alert.alert("Image Picking Cancelled");
45 | }
46 | }, []);
47 |
48 | return (
49 |
50 | Explore Section
51 |
52 | Explore Content
53 |
54 |
55 | About
56 |
57 |
58 | Mix Concepts
59 |
60 |
61 | QuranBookk App
62 |
63 |
64 | Pick Image
65 |
66 | setIsOpen(false)}
71 | >
72 | {/* */}
73 |
74 |
75 |
76 |
77 |
78 |
79 | Pick Image
80 | setIsOpen((v) => !v)}
82 | style={styles.close}
83 | >
84 | Close
85 |
86 |
87 |
88 |
93 |
94 |
95 |
96 |
97 | );
98 | }
99 |
100 | const styles = StyleSheet.create({
101 | container: {
102 | flex: 1,
103 | justifyContent: "center",
104 | alignItems: "center",
105 | gap: 20,
106 | backgroundColor: "lightpink",
107 | padding: 16,
108 | paddingBottom: 66,
109 | },
110 | text: { color: "#000", fontSize: 24 },
111 | textExplore: {
112 | fontSize: 20,
113 | backgroundColor: "#fff",
114 | padding: 15,
115 | borderRadius: 5,
116 | },
117 | picker: { padding: 10, borderRadius: 10, backgroundColor: "blue" },
118 | pickerText: { color: "#fff" },
119 | link: {
120 | color: "blue",
121 | fontSize: 18,
122 | padding: 5,
123 | backgroundColor: "#fff",
124 | borderRadius: 5,
125 | },
126 | modalHeader: { flexDirection: "row", gap: 10 },
127 | modalContent: {
128 | backgroundColor: "#fff",
129 | padding: 10,
130 | justifyContent: "center",
131 | alignItems: "center",
132 | },
133 | close: { padding: 10, backgroundColor: "blue" },
134 | closeText: { color: "#fff" },
135 | modal: {
136 | width: "100%",
137 | height: "25%",
138 | backgroundColor: "#fff",
139 | position: "absolute",
140 | bottom: 0,
141 | },
142 | img: {
143 | width: 200,
144 | height: 150,
145 | },
146 | nonModal: {
147 | ...StyleSheet.absoluteFillObject,
148 | backgroundColor: "rgba(0, 0, 0, 0.3)",
149 | },
150 | });
151 |
--------------------------------------------------------------------------------
/app/(tabs)/_layout.tsx:
--------------------------------------------------------------------------------
1 | import HapticButton from "@/components/ui/HapticButton";
2 | import IconSymbol from "@/components/ui/IconSymbol";
3 | import LargeScreenTab from "@/components/ui/LargeScreenTab";
4 | import { Ionicons } from "@expo/vector-icons";
5 | import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
6 | import { BlurView } from "expo-blur";
7 | import { Tabs } from "expo-router";
8 | import { useMemo } from "react";
9 | import { StyleSheet, useWindowDimensions, View } from "react-native";
10 | import { useSafeAreaInsets } from "react-native-safe-area-context";
11 |
12 | export default function RootLayout() {
13 | const insets = useSafeAreaInsets();
14 | const { width } = useWindowDimensions();
15 | const isLargeScreen = useMemo(() => width > 768, [width]);
16 |
17 | if (!width) return null;
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ({
30 | headerShown: false,
31 | tabBarActiveTintColor: "deeppink",
32 | tabBarStyle: {
33 | ...styles.tabBarBase,
34 | ...(isLargeScreen
35 | ? {
36 | paddingTop: insets.top,
37 | paddingBottom: insets.bottom,
38 | ...styles.tabBarVert,
39 | }
40 | : {
41 | //height: 40 + (Platform.OS === "android" ? insets.bottom : 0),//insta
42 | paddingBottom: insets.bottom > 0 ? insets.bottom : 0,
43 | ...styles.tabBarHori,
44 | }),
45 | },
46 | tabBarBackground: () => (
47 |
55 | ),
56 | ...(isLargeScreen
57 | ? {
58 | tabBarPosition: "left",
59 | tabBarItemStyle: {
60 | width: 80,
61 | },
62 | tabBarShowLabel: false,
63 | }
64 | : {
65 | /* tabBarShowLabel: false*/
66 | //insta
67 | }),
68 | tabBarButton: !isLargeScreen
69 | ? HapticButton
70 | : (props: BottomTabBarButtonProps) => (
71 |
72 | ),
73 | })}
74 | >
75 | (
80 |
81 | ),
82 | }}
83 | />
84 | (
89 |
90 | ),
91 | }}
92 | />
93 | (
98 |
99 | ),
100 | }}
101 | />
102 | (
107 |
108 | ),
109 | }}
110 | />
111 | (
116 |
117 | ),
118 | }}
119 | />
120 |
121 |
122 | );
123 | }
124 |
125 | const styles = StyleSheet.create({
126 | container: {
127 | flex: 1,
128 | },
129 | header: {
130 | padding: 10,
131 | flexDirection: "row",
132 | justifyContent: "space-around",
133 | alignItems: "center",
134 | gap: 8,
135 | backgroundColor: `rgba(0, 0, 0, 0.5)`,
136 | color: "#fff",
137 | position: "absolute",
138 | top: 0,
139 | left: 0,
140 | right: 0,
141 | zIndex: 1,
142 | },
143 | tabBarBase: {
144 | position: "absolute",
145 | backgroundColor: "transparent",
146 | shadowOpacity: 0,
147 | elevation: 0,
148 | },
149 | tabBarHori: { borderTopWidth: 0 },
150 | tabBarVert: {
151 | borderRightWidth: 0,
152 | flexDirection: "column",
153 | minWidth: 100,
154 | width: 100,
155 | },
156 | verticalTabButton: {
157 | width: 80,
158 | paddingVertical: 12,
159 | marginVertical: 4,
160 | alignItems: "center",
161 | justifyContent: "center",
162 | },
163 | verticalTabHovered: {
164 | backgroundColor: `rgba(255, 20, 147, 0.1)`,
165 | borderRadius: 10,
166 | },
167 | verticalTabFocused: {
168 | color: "deeppink",
169 | },
170 | verticalTabLabel: {
171 | fontSize: 10,
172 | marginTop: 4,
173 | textAlign: "center",
174 | },
175 | bgStyle: {
176 | width: 100,
177 | borderRightWidth: 1,
178 | borderRightColor: "#888",
179 | },
180 | });
181 |
--------------------------------------------------------------------------------
/app/(tabs)/index.tsx:
--------------------------------------------------------------------------------
1 | import useBottomTabOverflow from "@/hooks/useBottomTabOverflow";
2 | import { useCallback, useMemo, useRef } from "react";
3 | import {
4 | Alert,
5 | FlatList,
6 | Platform,
7 | Pressable,
8 | ScrollView,
9 | StyleSheet,
10 | Text,
11 | useWindowDimensions,
12 | View,
13 | } from "react-native";
14 | import * as MediaLibrary from "expo-media-library";
15 | import { captureRef } from "react-native-view-shot";
16 | import { toJpeg } from "html-to-image";
17 | import { MaterialIcons } from "@expo/vector-icons";
18 |
19 | export default function Home() {
20 | const screenShotViewRef = useRef(null);
21 | const [isAllowed, requestPermission] = MediaLibrary.usePermissions();
22 | const arrayDemo = useMemo(
23 | () => Array.from({ length: 100 }, (_, i) => i + 1),
24 | []
25 | );
26 |
27 | const { width } = useWindowDimensions();
28 | const overflowHeight = useBottomTabOverflow();
29 |
30 | const screenShoter = useCallback(async () => {
31 | if (!screenShotViewRef.current) {
32 | Alert.alert("Can not take taking Screenshot");
33 | return;
34 | }
35 |
36 | try {
37 | let imageUri = "";
38 | if (Platform.OS !== "web") {
39 | imageUri = await captureRef(screenShotViewRef.current, {
40 | width: 440,
41 | height: 320,
42 | quality: 1,
43 | });
44 | } else {
45 | imageUri = await toJpeg(screenShotViewRef.current, {
46 | //width: 440,
47 | //height: 320,
48 | quality: 1,
49 | });
50 | }
51 | if (imageUri) {
52 | if (!isAllowed) {
53 | const newPermission = await requestPermission();
54 | if (!newPermission.granted) {
55 | Alert.alert("Need Permission to take screenshot");
56 | return;
57 | }
58 | }
59 | if (Platform.OS !== "web") {
60 | await MediaLibrary.saveToLibraryAsync(imageUri);
61 | } else {
62 | const link = document.createElement("a");
63 | link.href = imageUri;
64 | link.download = "screenshot-image.jpeg";
65 | link.click();
66 | }
67 | Alert.alert("Screenshot Saved");
68 | } else {
69 | Alert.alert("Failure in taking Screenshot");
70 | }
71 | } catch (e) {
72 | Alert.alert("Error in taking Screenshot");
73 | }
74 | }, [isAllowed]);
75 |
76 | return (
77 |
78 | 768
82 | ? { paddingLeft: 116 }
83 | : {
84 | paddingBottom: overflowHeight + 16,
85 | },
86 | ]}
87 | nestedScrollEnabled={true}
88 | >
89 | Home Section
90 | item.toString()}
93 | contentContainerStyle={[styles.arrayDemoContent, styles.wrapper]}
94 | style={styles.arrayDemo}
95 | nestedScrollEnabled={true}
96 | showsVerticalScrollIndicator={false}
97 | renderItem={({ item }) => (
98 |
99 | Header {item}
100 |
101 | Content of {item}
102 |
103 |
104 | )}
105 | />
106 | Horizontal Scrolling Section
107 | item.toString()}
113 | contentContainerStyle={[styles.arrayDemoContent, styles.wrapperHori]}
114 | style={styles.arrayDemo}
115 | renderItem={({ item }) => (
116 |
117 | Header {item}
118 |
119 |
120 | Content of the Header {item}
121 |
122 |
123 |
124 | )}
125 | />
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | );
135 | }
136 |
137 | const styles = StyleSheet.create({
138 | container: {
139 | flex: 1,
140 | backgroundColor: "lightblue",
141 | },
142 | scrollContainer: {
143 | alignItems: "center",
144 | gap: 16,
145 | padding: 16,
146 | paddingTop: 50,
147 | },
148 | text: { color: "#000", fontSize: 24 },
149 | arrayDemoContent: {
150 | justifyContent: "space-around",
151 | flexDirection: "row",
152 | gap: 12,
153 | paddingBottom: 20,
154 | },
155 | arrayDemo: {
156 | backgroundColor: "white",
157 | borderRadius: 10,
158 | padding: 10,
159 | width: "100%",
160 | maxWidth: 768,
161 | height: 450,
162 | },
163 | card: {
164 | backgroundColor: "#000",
165 | padding: 10,
166 | alignItems: "center",
167 | justifyContent: "center",
168 | borderRadius: 10,
169 | elevation: 5,
170 | shadowColor: "#000",
171 | shadowOffset: { width: 1, height: 1 },
172 | shadowRadius: 4,
173 | },
174 | header: { fontSize: 18, color: "#fff", fontWeight: "medium" },
175 | content: { padding: 10, textAlign: "center" },
176 | contentText: {
177 | fontSize: 16,
178 | color: "lightgray",
179 | },
180 | wrapper: { flexWrap: "wrap" },
181 | wrapperHori: { paddingRight: 20 },
182 | shotContainer: {
183 | borderWidth: 4,
184 | width: 84,
185 | height: 84,
186 | borderRadius: "50%",
187 | borderColor: "yellow",
188 | padding: 3,
189 | backgroundColor: "#000",
190 | },
191 | shotBtn: {
192 | backgroundColor: "#fff",
193 | flex: 1,
194 | borderRadius: "50%",
195 | justifyContent: "center",
196 | alignItems: "center",
197 | },
198 | shotBtnText: {},
199 | });
200 |
--------------------------------------------------------------------------------
/styles/theme/colors.ts:
--------------------------------------------------------------------------------
1 | export const colors = {
2 | inherit: "inherit",
3 | current: "currentColor",
4 | transparent: "transparent",
5 | black: "#000000",
6 | white: "#ffffff",
7 | dark: "#000000",
8 | light: "#ffffff",
9 | primary: {
10 | 50: "#eff6ff",
11 | 100: "#dbeafe",
12 | 200: "#bfdbfe",
13 | 300: "#93c5fd",
14 | 400: "#60a5fa",
15 | 500: "#3b82f6",
16 | 600: "#2563eb",
17 | 700: "#1d4ed8",
18 | 800: "#1e40af",
19 | 900: "#1e3a8a",
20 | },
21 |
22 | // Slate
23 | slate: {
24 | 50: "#f8fafc",
25 | 100: "#f1f5f9",
26 | 200: "#e2e8f0",
27 | 300: "#cbd5e1",
28 | 400: "#94a3b8",
29 | 500: "#64748b",
30 | 600: "#475569",
31 | 700: "#334155",
32 | 800: "#1e293b",
33 | 900: "#0f172a",
34 | },
35 |
36 | // Gray
37 | gray: {
38 | 50: "#f9fafb",
39 | 100: "#f3f4f6",
40 | 200: "#e5e7eb",
41 | 300: "#d1d5db",
42 | 400: "#9ca3af",
43 | 500: "#6b7280",
44 | 600: "#4b5563",
45 | 700: "#374151",
46 | 800: "#1f2937",
47 | 900: "#111827",
48 | },
49 |
50 | // Zinc
51 | zinc: {
52 | 50: "#fafafa",
53 | 100: "#f4f4f5",
54 | 200: "#e4e4e7",
55 | 300: "#d4d4d8",
56 | 400: "#a1a1aa",
57 | 500: "#71717a",
58 | 600: "#52525b",
59 | 700: "#3f3f46",
60 | 800: "#27272a",
61 | 900: "#18181b",
62 | },
63 |
64 | // Neutral
65 | neutral: {
66 | 50: "#fafafa",
67 | 100: "#f5f5f5",
68 | 200: "#e5e5e5",
69 | 300: "#d4d4d4",
70 | 400: "#a3a3a3",
71 | 500: "#737373",
72 | 600: "#525252",
73 | 700: "#404040",
74 | 800: "#262626",
75 | 900: "#171717",
76 | },
77 |
78 | // Stone
79 | stone: {
80 | 50: "#fafaf9",
81 | 100: "#f5f5f4",
82 | 200: "#e7e5e4",
83 | 300: "#d6d3d1",
84 | 400: "#a8a29e",
85 | 500: "#78716c",
86 | 600: "#57534e",
87 | 700: "#44403c",
88 | 800: "#292524",
89 | 900: "#1c1917",
90 | },
91 |
92 | // Red
93 | red: {
94 | 50: "#fef2f2",
95 | 100: "#fee2e2",
96 | 200: "#fecaca",
97 | 300: "#fca5a5",
98 | 400: "#f87171",
99 | 500: "#ef4444",
100 | 600: "#dc2626",
101 | 700: "#b91c1c",
102 | 800: "#991b1b",
103 | 900: "#7f1d1d",
104 | },
105 |
106 | // Orange
107 | orange: {
108 | 50: "#fff7ed",
109 | 100: "#ffedd5",
110 | 200: "#fed7aa",
111 | 300: "#fdba74",
112 | 400: "#fb923c",
113 | 500: "#f97316",
114 | 600: "#ea580c",
115 | 700: "#c2410c",
116 | 800: "#9a3412",
117 | 900: "#7c2d12",
118 | },
119 |
120 | // Amber
121 | amber: {
122 | 50: "#fffbeb",
123 | 100: "#fef3c7",
124 | 200: "#fde68a",
125 | 300: "#fcd34d",
126 | 400: "#fbbf24",
127 | 500: "#f59e0b",
128 | 600: "#d97706",
129 | 700: "#b45309",
130 | 800: "#92400e",
131 | 900: "#78350f",
132 | },
133 |
134 | // Yellow
135 | yellow: {
136 | 50: "#fefce8",
137 | 100: "#fef9c3",
138 | 200: "#fef08a",
139 | 300: "#fde047",
140 | 400: "#facc15",
141 | 500: "#eab308",
142 | 600: "#ca8a04",
143 | 700: "#a16207",
144 | 800: "#854d0e",
145 | 900: "#713f12",
146 | },
147 |
148 | // Lime
149 | lime: {
150 | 50: "#f7fee7",
151 | 100: "#ecfccb",
152 | 200: "#d9f99d",
153 | 300: "#bef264",
154 | 400: "#a3e635",
155 | 500: "#84cc16",
156 | 600: "#65a30d",
157 | 700: "#4d7c0f",
158 | 800: "#3f6212",
159 | 900: "#365314",
160 | },
161 |
162 | // Green
163 | green: {
164 | 50: "#f0fdf4",
165 | 100: "#dcfce7",
166 | 200: "#bbf7d0",
167 | 300: "#86efac",
168 | 400: "#4ade80",
169 | 500: "#22c55e",
170 | 600: "#16a34a",
171 | 700: "#15803d",
172 | 800: "#166534",
173 | 900: "#14532d",
174 | },
175 |
176 | // Emerald
177 | emerald: {
178 | 50: "#ecfdf5",
179 | 100: "#d1fae5",
180 | 200: "#a7f3d0",
181 | 300: "#6ee7b7",
182 | 400: "#34d399",
183 | 500: "#10b981",
184 | 600: "#059669",
185 | 700: "#047857",
186 | 800: "#065f46",
187 | 900: "#064e3b",
188 | },
189 |
190 | // Teal
191 | teal: {
192 | 50: "#f0fdfa",
193 | 100: "#ccfbf1",
194 | 200: "#99f6e4",
195 | 300: "#5eead4",
196 | 400: "#2dd4bf",
197 | 500: "#14b8a6",
198 | 600: "#0d9488",
199 | 700: "#0f766e",
200 | 800: "#115e59",
201 | 900: "#134e4a",
202 | },
203 |
204 | // Cyan
205 | cyan: {
206 | 50: "#ecfeff",
207 | 100: "#cffafe",
208 | 200: "#a5f3fc",
209 | 300: "#67e8f9",
210 | 400: "#22d3ee",
211 | 500: "#06b6d4",
212 | 600: "#0891b2",
213 | 700: "#0e7490",
214 | 800: "#155e75",
215 | 900: "#164e63",
216 | },
217 |
218 | // Sky
219 | sky: {
220 | 50: "#f0f9ff",
221 | 100: "#e0f2fe",
222 | 200: "#bae6fd",
223 | 300: "#7dd3fc",
224 | 400: "#38bdf8",
225 | 500: "#0ea5e9",
226 | 600: "#0284c7",
227 | 700: "#0369a1",
228 | 800: "#075985",
229 | 900: "#0c4a6e",
230 | },
231 |
232 | // Blue
233 | blue: {
234 | 50: "#eff6ff",
235 | 100: "#dbeafe",
236 | 200: "#bfdbfe",
237 | 300: "#93c5fd",
238 | 400: "#60a5fa",
239 | 500: "#3b82f6",
240 | 600: "#2563eb",
241 | 700: "#1d4ed8",
242 | 800: "#1e40af",
243 | 900: "#1e3a8a",
244 | },
245 |
246 | // Indigo
247 | indigo: {
248 | 50: "#eef2ff",
249 | 100: "#e0e7ff",
250 | 200: "#c7d2fe",
251 | 300: "#a5b4fc",
252 | 400: "#818cf8",
253 | 500: "#6366f1",
254 | 600: "#4f46e5",
255 | 700: "#4338ca",
256 | 800: "#3730a3",
257 | 900: "#312e81",
258 | },
259 |
260 | // Violet
261 | violet: {
262 | 50: "#f5f3ff",
263 | 100: "#ede9fe",
264 | 200: "#ddd6fe",
265 | 300: "#c4b5fd",
266 | 400: "#a78bfa",
267 | 500: "#8b5cf6",
268 | 600: "#7c3aed",
269 | 700: "#6d28d9",
270 | 800: "#5b21b6",
271 | 900: "#4c1d95",
272 | },
273 |
274 | // Purple
275 | purple: {
276 | 50: "#faf5ff",
277 | 100: "#f3e8ff",
278 | 200: "#e9d5ff",
279 | 300: "#d8b4fe",
280 | 400: "#c084fc",
281 | 500: "#a855f7",
282 | 600: "#9333ea",
283 | 700: "#7e22ce",
284 | 800: "#6b21a8",
285 | 900: "#581c87",
286 | },
287 |
288 | // Fuchsia
289 | fuchsia: {
290 | 50: "#fdf4ff",
291 | 100: "#fae8ff",
292 | 200: "#f5d0fe",
293 | 300: "#f0abfc",
294 | 400: "#e879f9",
295 | 500: "#d946ef",
296 | 600: "#c026d3",
297 | 700: "#a21caf",
298 | 800: "#86198f",
299 | 900: "#701a75",
300 | },
301 |
302 | // Pink
303 | pink: {
304 | 50: "#fdf2f8",
305 | 100: "#fce7f3",
306 | 200: "#fbcfe8",
307 | 300: "#f9a8d4",
308 | 400: "#f472b6",
309 | 500: "#ec4899",
310 | 600: "#db2777",
311 | 700: "#be185d",
312 | 800: "#9d174d",
313 | 900: "#831843",
314 | },
315 |
316 | // Rose
317 | rose: {
318 | 50: "#fff1f2",
319 | 100: "#ffe4e6",
320 | 200: "#fecdd3",
321 | 300: "#fda4af",
322 | 400: "#fb7185",
323 | 500: "#f43f5e",
324 | 600: "#e11d48",
325 | 700: "#be123c",
326 | 800: "#9f1239",
327 | 900: "#881337",
328 | },
329 | };
330 |
--------------------------------------------------------------------------------
/app/mixture.tsx:
--------------------------------------------------------------------------------
1 | import WebViewContentScrollable from "@/components/ui/WebViewContent";
2 | import {
3 | Alert,
4 | Platform,
5 | Pressable,
6 | ScrollView,
7 | Share,
8 | StyleSheet,
9 | Text,
10 | TextInput,
11 | View,
12 | } from "react-native";
13 | import Constants from "expo-constants";
14 | import { useCallback, useState } from "react";
15 | import { getItemAsync, setItemAsync } from "expo-secure-store";
16 | import * as deepLinking from "expo-linking";
17 | import { Link } from "expo-router";
18 |
19 | export default function Mixture() {
20 | const [username, setUsername] = useState("");
21 | const [password, setPassword] = useState("");
22 | const [link, setLink] = useState("");
23 |
24 | const handleSetToSecureStore = useCallback(async () => {
25 | if (username && password) {
26 | if (Platform.OS === "web") {
27 | localStorage.setItem("username", username);
28 | localStorage.setItem("password", password);
29 | } else {
30 | await setItemAsync("username", username);
31 | await setItemAsync("password", password);
32 | }
33 | setPassword("");
34 | setUsername("");
35 | Alert.alert("Auth details stored");
36 | }
37 | }, [username, password]);
38 |
39 | const handleGetFromSecureStore = useCallback(async () => {
40 | let username, password;
41 | if (Platform.OS === "web") {
42 | username = localStorage.getItem("username");
43 | password = localStorage.getItem("password");
44 | } else {
45 | username = await getItemAsync("username");
46 | password = await getItemAsync("password");
47 | }
48 | if (username && password) {
49 | setPassword(username);
50 | setUsername(password);
51 | Alert.alert("Auth details Retrieved");
52 | }
53 | }, []);
54 |
55 | const handleCreateDeepLink = useCallback(() => {
56 | const link = deepLinking.createURL("mixture", {
57 | queryParams: { id: "first" },
58 | });
59 | setLink(link);
60 | }, []);
61 |
62 | const handleShare = useCallback(async () => {
63 | if (!link) {
64 | Alert.alert("There must be a Link");
65 | return;
66 | }
67 | try {
68 | const result = await Share.share({
69 | message: `See the amazing contents on ${link}`,
70 | });
71 | if (Platform.OS !== "web") {
72 | if (result.action === Share.sharedAction) {
73 | if (result.activityType) {
74 | Alert.alert("Shared with activity type: ", result.activityType);
75 | } else {
76 | Alert.alert("Shared successfully");
77 | }
78 | } else if (result.action === Share.dismissedAction) {
79 | Alert.alert("Shared Dissmissed");
80 | } else {
81 | Alert.alert(JSON.stringify(result, null, 2));
82 | }
83 | }
84 | } catch (e) {
85 | Alert.alert("Error in sharing: ", (e as Error).message);
86 | }
87 | }, [link]);
88 |
89 | return (
90 |
91 |
92 | Go to home
93 |
94 |
95 |
99 |
100 |
104 |
105 |
106 |
107 | Platform: {JSON.stringify(Constants, null, 2)}
108 |
109 |
110 |
111 |
117 |
123 |
124 |
125 | Submit
126 |
127 |
128 | Get Details
129 |
130 |
131 |
132 |
133 |
134 |
141 |
142 | Create Deep Link
143 |
144 |
145 | {link && (
146 |
147 | {link}
148 |
155 |
156 | Share Deep Link
157 |
158 |
159 |
160 | )}
161 |
162 |
163 |
164 | );
165 | }
166 |
167 | const ss = StyleSheet.create({
168 | container: {
169 | flex: 1,
170 | },
171 | scrollContent: {
172 | gap: 15,
173 | backgroundColor: "aliceblue",
174 | },
175 | scrollContainer: {},
176 | webviewContainer: {
177 | marginHorizontal: 15,
178 | height: 440,
179 | },
180 | webview: {
181 | borderWidth: 0,
182 | height: "100%",
183 | },
184 | constantsContainer: {
185 | padding: 15,
186 | backgroundColor: "#fff",
187 | alignItems: "center",
188 | margin: 20,
189 | borderRadius: 10,
190 | },
191 | constantsText: { color: "#000" },
192 | secureContainer: {
193 | margin: 15,
194 | backgroundColor: "#fff",
195 | borderRadius: 10,
196 | padding: 10,
197 | gap: 10,
198 | },
199 | secureInput: { borderRadius: 10, padding: 10, borderWidth: 1 },
200 | secureBtn: { backgroundColor: "violet", borderRadius: 10, padding: 5 },
201 | btnContainer: {
202 | flexDirection: "row",
203 | gap: "10",
204 | justifyContent: "space-between",
205 | },
206 | btnText: { color: "#fff" },
207 | deepContainer: {
208 | backgroundColor: "#fff",
209 | padding: 10,
210 | margin: 20,
211 | borderRadius: 10,
212 | alignItems: "center",
213 | },
214 | deepText: { color: "green", fontSize: 18 },
215 | shareContainer: { gap: 10 },
216 | linkContainer: {
217 | paddingHorizontal: 16,
218 | paddingVertical: 8,
219 | backgroundColor: "#000",
220 | alignItems: "center",
221 | borderRadius: 10,
222 | textAlign: "center",
223 | },
224 | linkText: { color: "#fff" },
225 | });
226 |
--------------------------------------------------------------------------------