summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-07-16 09:58:34 +0700
committerpolwex <polwex@sortug.com>2025-07-16 09:58:34 +0700
commitdc0ad21f0e857adb87d710dd0f2f9affd0a9cbc9 (patch)
tree3d556ead415654e03b511b007365bcdff6d612ee
parent697ed671f394cbd07ea9751fe17f262744d99a49 (diff)
kinda works
-rw-r--r--app/(tabs)/_layout.tsx54
-rw-r--r--app/(tabs)/explore.tsx110
-rw-r--r--app/(tabs)/index.tsx75
-rw-r--r--app/(tabs)/login.tsx122
-rw-r--r--app/+not-found.tsx36
-rw-r--r--app/_layout.tsx57
-rw-r--r--app/index.tsx203
-rw-r--r--components/Collapsible.tsx33
-rw-r--r--components/ParallaxScrollView.tsx33
-rw-r--r--components/PrimaryButton.tsx1
-rw-r--r--components/ThemedText.tsx29
-rw-r--r--components/ThemedView.tsx17
-rw-r--r--components/login/ShipCredsForm.tsx105
-rw-r--r--constants/config.ts2
14 files changed, 435 insertions, 442 deletions
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
deleted file mode 100644
index a102c45..0000000
--- a/app/(tabs)/_layout.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Tabs } from "expo-router";
-import { Toaster } from "react-hot-toast";
-import React from "react";
-import { Platform } from "react-native";
-
-import { HapticTab } from "@/components/HapticTab";
-import { IconSymbol } from "@/components/ui/IconSymbol";
-import TabBarBackground from "@/components/ui/TabBarBackground";
-import { Colors } from "@/constants/Colors";
-import { useColorScheme } from "@/hooks/useColorScheme";
-
-export default function TabLayout() {
- const colorScheme = useColorScheme();
-
- return (
- <>
- <Tabs
- screenOptions={{
- tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
- headerShown: false,
- tabBarButton: HapticTab,
- tabBarBackground: TabBarBackground,
- tabBarStyle: Platform.select({
- ios: {
- // Use a transparent background on iOS to show the blur effect
- position: "absolute",
- },
- default: {},
- }),
- }}
- >
- <Tabs.Screen
- name="index"
- options={{
- title: "Home",
- tabBarIcon: ({ color }) => (
- <IconSymbol size={28} name="house.fill" color={color} />
- ),
- }}
- />
- <Tabs.Screen
- name="explore"
- options={{
- title: "Explore",
- tabBarIcon: ({ color }) => (
- <IconSymbol size={28} name="paperplane.fill" color={color} />
- ),
- }}
- />
- </Tabs>
- <Toaster position="top-center" />
- </>
- );
-}
diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx
deleted file mode 100644
index d4fbcaa..0000000
--- a/app/(tabs)/explore.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import { Image } from 'expo-image';
-import { Platform, StyleSheet } from 'react-native';
-
-import { Collapsible } from '@/components/Collapsible';
-import { ExternalLink } from '@/components/ExternalLink';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-import { IconSymbol } from '@/components/ui/IconSymbol';
-
-export default function TabTwoScreen() {
- return (
- <ParallaxScrollView
- headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
- headerImage={
- <IconSymbol
- size={310}
- color="#808080"
- name="chevron.left.forwardslash.chevron.right"
- style={styles.headerImage}
- />
- }>
- <ThemedView style={styles.titleContainer}>
- <ThemedText type="title">Explore</ThemedText>
- </ThemedView>
- <ThemedText>This app includes example code to help you get started.</ThemedText>
- <Collapsible title="File-based routing">
- <ThemedText>
- This app has two screens:{' '}
- <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
- <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
- </ThemedText>
- <ThemedText>
- The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
- sets up the tab navigator.
- </ThemedText>
- <ExternalLink href="https://docs.expo.dev/router/introduction">
- <ThemedText type="link">Learn more</ThemedText>
- </ExternalLink>
- </Collapsible>
- <Collapsible title="Android, iOS, and web support">
- <ThemedText>
- You can open this project on Android, iOS, and the web. To open the web version, press{' '}
- <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
- </ThemedText>
- </Collapsible>
- <Collapsible title="Images">
- <ThemedText>
- For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
- <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
- different screen densities
- </ThemedText>
- <Image source={require('@/assets/images/react-logo.png')} style={{ alignSelf: 'center' }} />
- <ExternalLink href="https://reactnative.dev/docs/images">
- <ThemedText type="link">Learn more</ThemedText>
- </ExternalLink>
- </Collapsible>
- <Collapsible title="Custom fonts">
- <ThemedText>
- Open <ThemedText type="defaultSemiBold">app/_layout.tsx</ThemedText> to see how to load{' '}
- <ThemedText style={{ fontFamily: 'SpaceMono' }}>
- custom fonts such as this one.
- </ThemedText>
- </ThemedText>
- <ExternalLink href="https://docs.expo.dev/versions/latest/sdk/font">
- <ThemedText type="link">Learn more</ThemedText>
- </ExternalLink>
- </Collapsible>
- <Collapsible title="Light and dark mode components">
- <ThemedText>
- This template has light and dark mode support. The{' '}
- <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
- what the user&apos;s current color scheme is, and so you can adjust UI colors accordingly.
- </ThemedText>
- <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
- <ThemedText type="link">Learn more</ThemedText>
- </ExternalLink>
- </Collapsible>
- <Collapsible title="Animations">
- <ThemedText>
- This template includes an example of an animated component. The{' '}
- <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
- the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText>{' '}
- library to create a waving hand animation.
- </ThemedText>
- {Platform.select({
- ios: (
- <ThemedText>
- The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
- component provides a parallax effect for the header image.
- </ThemedText>
- ),
- })}
- </Collapsible>
- </ParallaxScrollView>
- );
-}
-
-const styles = StyleSheet.create({
- headerImage: {
- color: '#808080',
- bottom: -90,
- left: -35,
- position: 'absolute',
- },
- titleContainer: {
- flexDirection: 'row',
- gap: 8,
- },
-});
diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
deleted file mode 100644
index 462e8cd..0000000
--- a/app/(tabs)/index.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import { Image } from 'expo-image';
-import { Platform, StyleSheet } from 'react-native';
-
-import { HelloWave } from '@/components/HelloWave';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-
-export default function HomeScreen() {
- return (
- <ParallaxScrollView
- headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
- headerImage={
- <Image
- source={require('@/assets/images/partial-react-logo.png')}
- style={styles.reactLogo}
- />
- }>
- <ThemedView style={styles.titleContainer}>
- <ThemedText type="title">Welcome!</ThemedText>
- <HelloWave />
- </ThemedView>
- <ThemedView style={styles.stepContainer}>
- <ThemedText type="subtitle">Step 1: Try it</ThemedText>
- <ThemedText>
- Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
- Press{' '}
- <ThemedText type="defaultSemiBold">
- {Platform.select({
- ios: 'cmd + d',
- android: 'cmd + m',
- web: 'F12',
- })}
- </ThemedText>{' '}
- to open developer tools.
- </ThemedText>
- </ThemedView>
- <ThemedView style={styles.stepContainer}>
- <ThemedText type="subtitle">Step 2: Explore</ThemedText>
- <ThemedText>
- {`Tap the Explore tab to learn more about what's included in this starter app.`}
- </ThemedText>
- </ThemedView>
- <ThemedView style={styles.stepContainer}>
- <ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
- <ThemedText>
- {`When you're ready, run `}
- <ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
- <ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
- <ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
- <ThemedText type="defaultSemiBold">app-example</ThemedText>.
- </ThemedText>
- </ThemedView>
- </ParallaxScrollView>
- );
-}
-
-const styles = StyleSheet.create({
- titleContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 8,
- },
- stepContainer: {
- gap: 8,
- marginBottom: 8,
- },
- reactLogo: {
- height: 178,
- width: 290,
- bottom: 0,
- left: 0,
- position: 'absolute',
- },
-});
diff --git a/app/(tabs)/login.tsx b/app/(tabs)/login.tsx
deleted file mode 100644
index c5f826d..0000000
--- a/app/(tabs)/login.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React, { useState } from "react";
-import {
- View,
- Text,
- StyleSheet,
- Image,
- KeyboardAvoidingView,
- Platform,
- Alert,
-} from "react-native";
-import PrimaryButton from "../../components/PrimaryButton";
-import ScreenWrapper from "../../components/ScreenWrapper";
-import { useThemeColors, ColorScheme } from "../../constants";
-import { ROUTES } from "../../constants/routes";
-import { Passkee } from "@/components/auth/Auth";
-
-// import { useSettingsStore } from "../store/useSettingsStore";
-// import useAuthStore from "../store/useAuthStore";
-// import { createPasskey, isPasskeySupported } from "../lib/passkey";
-// import { navigationRef } from "../lib/navigationRef";
-
-const PasskeySetupScreen = async () => {
- const [isLoading, setIsLoading] = useState(false);
- // const isDarkMode = useSettingsStore((s) => s.isDarkMode);
- const isDarkMode = false;
- const colors = useThemeColors();
- const styles = getStyles(colors);
- // const { setHasPasskey, setHasSeenPasskeyPrompt } = useAuthStore();
-
- const logoSource = isDarkMode
- ? require("../../assets/urbit-logo-dark.png")
- : require("../../assets/urbit-logo-light.png");
-
- const handleSkip = () => {
- // setHasSeenPasskeyPrompt(true);
- // navigationRef.current?.navigate(ROUTES.LOGIN as never);
- };
-
- return (
- <KeyboardAvoidingView
- style={styles.container}
- behavior={Platform.OS === "ios" ? "padding" : undefined}
- >
- <ScreenWrapper>
- <View style={styles.topSection}>
- <Image
- source={logoSource}
- style={styles.walletIcon}
- resizeMode="contain"
- />
- <Text style={styles.title}>Secure Your Wallet</Text>
- <Text style={styles.subtitle}>
- Create a passkey for easy and secure access to your Urbit wallet
- </Text>
- </View>
-
- <View style={styles.bottomSection}>
- <Passkee />
- <PrimaryButton
- label="Skip for Now"
- onPress={handleSkip}
- style={{
- backgroundColor: colors.card,
- borderWidth: 1,
- borderColor: colors.border,
- }}
- textStyle={{ color: colors.text }}
- />
-
- <Text style={styles.infoText}>
- You can always set up a passkey later in settings
- </Text>
- </View>
- </ScreenWrapper>
- </KeyboardAvoidingView>
- );
-};
-
-export const getStyles = (colors: ColorScheme) =>
- StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: colors.background,
- justifyContent: "space-between",
- padding: 20,
- },
- topSection: {
- flex: 1,
- justifyContent: "center",
- alignItems: "center",
- },
- walletIcon: {
- width: 64,
- height: 64,
- marginBottom: 24,
- },
- title: {
- fontSize: 24,
- color: colors.text,
- fontWeight: "600",
- marginBottom: 12,
- textAlign: "center",
- },
- subtitle: {
- fontSize: 16,
- color: colors.secondary,
- textAlign: "center",
- paddingHorizontal: 20,
- lineHeight: 24,
- },
- bottomSection: {
- marginBottom: 40,
- },
- infoText: {
- color: colors.secondary,
- fontSize: 14,
- textAlign: "center",
- marginTop: 16,
- },
- });
-
-export default PasskeySetupScreen;
diff --git a/app/+not-found.tsx b/app/+not-found.tsx
index 215b0ed..68601c6 100644
--- a/app/+not-found.tsx
+++ b/app/+not-found.tsx
@@ -1,19 +1,19 @@
-import { Link, Stack } from 'expo-router';
-import { StyleSheet } from 'react-native';
+import { Link, Stack } from "expo-router";
+import { View, Text, StyleSheet } from "react-native";
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
+// import { ThemedText } from '@/components/ThemedText';
+// import { ThemedView } from '@/components/ThemedView';
export default function NotFoundScreen() {
return (
<>
- <Stack.Screen options={{ title: 'Oops!' }} />
- <ThemedView style={styles.container}>
- <ThemedText type="title">This screen does not exist.</ThemedText>
+ <Stack.Screen options={{ title: "Oops!" }} />
+ <View style={styles.container}>
+ <Text style={styles.title}>This screen does not exist.</Text>
<Link href="/" style={styles.link}>
- <ThemedText type="link">Go to home screen!</ThemedText>
+ <Text style={styles.linkText}>Go to home screen!</Text>
</Link>
- </ThemedView>
+ </View>
</>
);
}
@@ -21,12 +21,26 @@ export default function NotFoundScreen() {
const styles = StyleSheet.create({
container: {
flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
+ alignItems: "center",
+ justifyContent: "center",
padding: 20,
},
link: {
marginTop: 15,
paddingVertical: 15,
},
+ title: {
+ fontSize: 32,
+ fontWeight: "bold",
+ lineHeight: 32,
+ },
+ subtitle: {
+ fontSize: 20,
+ fontWeight: "bold",
+ },
+ linkText: {
+ lineHeight: 30,
+ fontSize: 16,
+ color: "#0a7ea4",
+ },
});
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 8d506f7..6974539 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,29 +1,38 @@
-import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
-import { useFonts } from 'expo-font';
-import { Stack } from 'expo-router';
-import { StatusBar } from 'expo-status-bar';
-import 'react-native-reanimated';
+// import {
+// DarkTheme,
+// DefaultTheme,
+// ThemeProvider,
+// } from "@react-navigation/native";
+// import { useFonts } from "expo-font";
+// import { Stack } from "expo-router";
+// import { StatusBar } from "expo-status-bar";
+// import "react-native-reanimated";
+// import { Toaster } from "react-hot-toast";
-import { useColorScheme } from '@/hooks/useColorScheme';
+// import { useColorScheme } from "@/hooks/useColorScheme";
-export default function RootLayout() {
- const colorScheme = useColorScheme();
- const [loaded] = useFonts({
- SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
- });
+// export default function RootLayout() {
+// const colorScheme = useColorScheme();
+// const [loaded] = useFonts({
+// SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
+// });
- if (!loaded) {
- // Async font loading only occurs in development.
- return null;
- }
+// if (!loaded) {
+// // Async font loading only occurs in development.
+// return null;
+// }
- return (
- <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
- <Stack>
- <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
- <Stack.Screen name="+not-found" />
- </Stack>
- <StatusBar style="auto" />
- </ThemeProvider>
- );
+// return (
+// <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
+// <Stack>
+// <Stack.Screen name="index" options={{ headerShown: false }} />
+// <Stack.Screen name="+not-found" />
+// </Stack>
+// <StatusBar style="auto" />
+// <Toaster position="top-center" />
+// </ThemeProvider>
+// );
+// }
+export default function RootLayout() {
+ return <></>;
}
diff --git a/app/index.tsx b/app/index.tsx
new file mode 100644
index 0000000..4d13c90
--- /dev/null
+++ b/app/index.tsx
@@ -0,0 +1,203 @@
+import "server-only";
+import {
+ View,
+ Text,
+ StyleSheet,
+ Image,
+ KeyboardAvoidingView,
+ Platform,
+ Alert,
+} from "react-native";
+import PrimaryButton from "@/components/PrimaryButton";
+import ScreenWrapper from "@/components/ScreenWrapper";
+// // import { useThemeColors, ColorScheme } from "../constants";
+// import { ROUTES } from "@/constants/routes";
+// import { Passkee } from "@/components/auth/Auth";
+import { type ColorScheme, lightColors } from "@/constants";
+import { ShipForm } from "@/components/login/ShipCredsForm";
+
+// // import { useSettingsStore } from "../store/useSettingsStore";
+// // import useAuthStore from "../store/useAuthStore";
+// // import { createPasskey, isPasskeySupported } from "../lib/passkey";
+// // import { navigationRef } from "../lib/navigationRef";
+
+// const PasskeySetupScreen = async () => {
+// // const isDarkMode = useSettingsStore((s) => s.isDarkMode);
+// const isDarkMode = false;
+// // const colors = useThemeColors();
+// const colors = lightColors;
+// const styles = getStyles(colors);
+// // const { setHasPasskey, setHasSeenPasskeyPrompt } = useAuthStore();
+
+// const logoSource = isDarkMode
+// ? require("../assets/urbit-logo-dark.png")
+// : require("../assets/urbit-logo-light.png");
+
+// const handleSkip = () => {
+// // setHasSeenPasskeyPrompt(true);
+// // navigationRef.current?.navigate(ROUTES.LOGIN as never);
+// };
+
+// return (
+// <KeyboardAvoidingView
+// style={styles.container}
+// behavior={Platform.OS === "ios" ? "padding" : undefined}
+// >
+// <ScreenWrapper>
+// <View style={styles.topSection}>
+// <Image
+// source={logoSource}
+// style={styles.walletIcon}
+// resizeMode="contain"
+// />
+// <Text style={styles.title}>Secure Your Wallet</Text>
+// <Text style={styles.subtitle}>
+// Create a passkey for easy and secure access to your Urbit wallet
+// </Text>
+// </View>
+
+// <View style={styles.bottomSection}>
+// <Passkee />
+// <PrimaryButton
+// label="Skip for Now"
+// onPress={handleSkip}
+// style={{
+// backgroundColor: colors.card,
+// borderWidth: 1,
+// borderColor: colors.border,
+// }}
+// textStyle={{ color: colors.text }}
+// />
+
+// <Text style={styles.infoText}>
+// You can always set up a passkey later in settings
+// </Text>
+// </View>
+// </ScreenWrapper>
+// </KeyboardAvoidingView>
+// );
+// };
+
+// export const getStyles = (colors: ColorScheme) =>
+// StyleSheet.create({
+// container: {
+// flex: 1,
+// backgroundColor: colors.background,
+// justifyContent: "space-between",
+// padding: 20,
+// },
+// topSection: {
+// flex: 1,
+// justifyContent: "center",
+// alignItems: "center",
+// },
+// walletIcon: {
+// width: 64,
+// height: 64,
+// marginBottom: 24,
+// },
+// title: {
+// fontSize: 24,
+// color: colors.text,
+// fontWeight: "600",
+// marginBottom: 12,
+// textAlign: "center",
+// },
+// subtitle: {
+// fontSize: 16,
+// color: colors.secondary,
+// textAlign: "center",
+// paddingHorizontal: 20,
+// lineHeight: 24,
+// },
+// bottomSection: {
+// marginBottom: 40,
+// },
+// infoText: {
+// color: colors.secondary,
+// fontSize: 14,
+// textAlign: "center",
+// marginTop: 16,
+// },
+// });
+
+// export default PasskeySetupScreen;
+//
+//
+
+// export const unstable_settings = {
+// // This component will be rendered at build-time and never re-rendered in production.
+// render: "static",
+// };
+
+export default async function Index() {
+ async function handleSubmit() {
+ //
+ }
+ return (
+ <View style={styles.container}>
+ <ScreenWrapper>
+ <View style={styles.topSection}>
+ <Image
+ source={require("../assets/urbit-logo-light.png")}
+ style={styles.walletIcon}
+ resizeMode="contain"
+ />
+ <Text style={styles.title}>Secure Your Wallet</Text>
+ <Text style={styles.subtitle}>
+ Create a passkey for easy and secure access to your Urbit wallet
+ </Text>
+ </View>
+ <ShipForm />
+
+ <View style={styles.bottomSection}>
+ <Text style={styles.infoText}>
+ You can always set up a passkey later in settings
+ </Text>
+ </View>
+ </ScreenWrapper>
+ </View>
+ );
+}
+
+export const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#F7F7F7",
+ justifyContent: "space-between",
+ padding: 20,
+ },
+ topSection: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ walletIcon: {
+ width: 64,
+ height: 64,
+ marginBottom: 24,
+ },
+ title: {
+ fontSize: 24,
+ color: "#171717",
+ fontWeight: "600",
+ marginBottom: 12,
+ textAlign: "center",
+ },
+ subtitle: {
+ fontSize: 16,
+ color: "#737373",
+ textAlign: "center",
+ paddingHorizontal: 20,
+ lineHeight: 24,
+ },
+ bottomSection: {
+ marginBottom: 40,
+ },
+ infoText: {
+ color: "#737373",
+ fontSize: 14,
+ textAlign: "center",
+ marginTop: 16,
+ },
+});
diff --git a/components/Collapsible.tsx b/components/Collapsible.tsx
index 55bff2f..5820251 100644
--- a/components/Collapsible.tsx
+++ b/components/Collapsible.tsx
@@ -1,28 +1,33 @@
-import { PropsWithChildren, useState } from 'react';
-import { StyleSheet, TouchableOpacity } from 'react-native';
+"use client";
+import { PropsWithChildren, useState } from "react";
+import { StyleSheet, TouchableOpacity } from "react-native";
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-import { IconSymbol } from '@/components/ui/IconSymbol';
-import { Colors } from '@/constants/Colors';
-import { useColorScheme } from '@/hooks/useColorScheme';
+import { ThemedText } from "@/components/ThemedText";
+import { ThemedView } from "@/components/ThemedView";
+import { IconSymbol } from "@/components/ui/IconSymbol";
+import { Colors } from "@/constants/Colors";
+import { useColorScheme } from "@/hooks/useColorScheme";
-export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
+export function Collapsible({
+ children,
+ title,
+}: PropsWithChildren & { title: string }) {
const [isOpen, setIsOpen] = useState(false);
- const theme = useColorScheme() ?? 'light';
+ const theme = useColorScheme() ?? "light";
return (
<ThemedView>
<TouchableOpacity
style={styles.heading}
onPress={() => setIsOpen((value) => !value)}
- activeOpacity={0.8}>
+ activeOpacity={0.8}
+ >
<IconSymbol
name="chevron.right"
size={18}
weight="medium"
- color={theme === 'light' ? Colors.light.icon : Colors.dark.icon}
- style={{ transform: [{ rotate: isOpen ? '90deg' : '0deg' }] }}
+ color={theme === "light" ? Colors.light.icon : Colors.dark.icon}
+ style={{ transform: [{ rotate: isOpen ? "90deg" : "0deg" }] }}
/>
<ThemedText type="defaultSemiBold">{title}</ThemedText>
@@ -34,8 +39,8 @@ export function Collapsible({ children, title }: PropsWithChildren & { title: st
const styles = StyleSheet.create({
heading: {
- flexDirection: 'row',
- alignItems: 'center',
+ flexDirection: "row",
+ alignItems: "center",
gap: 6,
},
content: {
diff --git a/components/ParallaxScrollView.tsx b/components/ParallaxScrollView.tsx
index 5df1d75..46ed68e 100644
--- a/components/ParallaxScrollView.tsx
+++ b/components/ParallaxScrollView.tsx
@@ -1,15 +1,16 @@
-import type { PropsWithChildren, ReactElement } from 'react';
-import { StyleSheet } from 'react-native';
+"use client";
+import type { PropsWithChildren, ReactElement } from "react";
+import { StyleSheet } from "react-native";
import Animated, {
interpolate,
useAnimatedRef,
useAnimatedStyle,
useScrollViewOffset,
-} from 'react-native-reanimated';
+} from "react-native-reanimated";
-import { ThemedView } from '@/components/ThemedView';
-import { useBottomTabOverflow } from '@/components/ui/TabBarBackground';
-import { useColorScheme } from '@/hooks/useColorScheme';
+import { ThemedView } from "@/components/ThemedView";
+import { useBottomTabOverflow } from "@/components/ui/TabBarBackground";
+import { useColorScheme } from "@/hooks/useColorScheme";
const HEADER_HEIGHT = 250;
@@ -23,7 +24,7 @@ export default function ParallaxScrollView({
headerImage,
headerBackgroundColor,
}: Props) {
- const colorScheme = useColorScheme() ?? 'light';
+ const colorScheme = useColorScheme() ?? "light";
const scrollRef = useAnimatedRef<Animated.ScrollView>();
const scrollOffset = useScrollViewOffset(scrollRef);
const bottom = useBottomTabOverflow();
@@ -34,11 +35,15 @@ export default function ParallaxScrollView({
translateY: interpolate(
scrollOffset.value,
[-HEADER_HEIGHT, 0, HEADER_HEIGHT],
- [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
+ [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75],
),
},
{
- scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
+ scale: interpolate(
+ scrollOffset.value,
+ [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
+ [2, 1, 1],
+ ),
},
],
};
@@ -50,13 +55,15 @@ export default function ParallaxScrollView({
ref={scrollRef}
scrollEventThrottle={16}
scrollIndicatorInsets={{ bottom }}
- contentContainerStyle={{ paddingBottom: bottom }}>
+ contentContainerStyle={{ paddingBottom: bottom }}
+ >
<Animated.View
style={[
styles.header,
{ backgroundColor: headerBackgroundColor[colorScheme] },
headerAnimatedStyle,
- ]}>
+ ]}
+ >
{headerImage}
</Animated.View>
<ThemedView style={styles.content}>{children}</ThemedView>
@@ -71,12 +78,12 @@ const styles = StyleSheet.create({
},
header: {
height: HEADER_HEIGHT,
- overflow: 'hidden',
+ overflow: "hidden",
},
content: {
flex: 1,
padding: 32,
gap: 16,
- overflow: 'hidden',
+ overflow: "hidden",
},
});
diff --git a/components/PrimaryButton.tsx b/components/PrimaryButton.tsx
index 94bd8ce..b515818 100644
--- a/components/PrimaryButton.tsx
+++ b/components/PrimaryButton.tsx
@@ -1,3 +1,4 @@
+"use client";
import React from "react";
import {
TouchableOpacity,
diff --git a/components/ThemedText.tsx b/components/ThemedText.tsx
index 9d214a2..c545b1c 100644
--- a/components/ThemedText.tsx
+++ b/components/ThemedText.tsx
@@ -1,31 +1,32 @@
-import { StyleSheet, Text, type TextProps } from 'react-native';
+"use client";
+import { StyleSheet, Text, type TextProps } from "react-native";
-import { useThemeColor } from '@/hooks/useThemeColor';
+import { useThemeColor } from "@/hooks/useThemeColor";
export type ThemedTextProps = TextProps & {
lightColor?: string;
darkColor?: string;
- type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
+ type?: "default" | "title" | "defaultSemiBold" | "subtitle" | "link";
};
export function ThemedText({
style,
lightColor,
darkColor,
- type = 'default',
+ type = "default",
...rest
}: ThemedTextProps) {
- const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
+ const color = useThemeColor({ light: lightColor, dark: darkColor }, "text");
return (
<Text
style={[
{ color },
- type === 'default' ? styles.default : undefined,
- type === 'title' ? styles.title : undefined,
- type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
- type === 'subtitle' ? styles.subtitle : undefined,
- type === 'link' ? styles.link : undefined,
+ type === "default" ? styles.default : undefined,
+ type === "title" ? styles.title : undefined,
+ type === "defaultSemiBold" ? styles.defaultSemiBold : undefined,
+ type === "subtitle" ? styles.subtitle : undefined,
+ type === "link" ? styles.link : undefined,
style,
]}
{...rest}
@@ -41,20 +42,20 @@ const styles = StyleSheet.create({
defaultSemiBold: {
fontSize: 16,
lineHeight: 24,
- fontWeight: '600',
+ fontWeight: "600",
},
title: {
fontSize: 32,
- fontWeight: 'bold',
+ fontWeight: "bold",
lineHeight: 32,
},
subtitle: {
fontSize: 20,
- fontWeight: 'bold',
+ fontWeight: "bold",
},
link: {
lineHeight: 30,
fontSize: 16,
- color: '#0a7ea4',
+ color: "#0a7ea4",
},
});
diff --git a/components/ThemedView.tsx b/components/ThemedView.tsx
index 4d2cb09..fe06be6 100644
--- a/components/ThemedView.tsx
+++ b/components/ThemedView.tsx
@@ -1,14 +1,23 @@
-import { View, type ViewProps } from 'react-native';
+"use client";
+import { View, type ViewProps } from "react-native";
-import { useThemeColor } from '@/hooks/useThemeColor';
+import { useThemeColor } from "@/hooks/useThemeColor";
export type ThemedViewProps = ViewProps & {
lightColor?: string;
darkColor?: string;
};
-export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
+export function ThemedView({
+ style,
+ lightColor,
+ darkColor,
+ ...otherProps
+}: ThemedViewProps) {
+ const backgroundColor = useThemeColor(
+ { light: lightColor, dark: darkColor },
+ "background",
+ );
return <View style={[{ backgroundColor }, style]} {...otherProps} />;
}
diff --git a/components/login/ShipCredsForm.tsx b/components/login/ShipCredsForm.tsx
new file mode 100644
index 0000000..15712c2
--- /dev/null
+++ b/components/login/ShipCredsForm.tsx
@@ -0,0 +1,105 @@
+"use client";
+import { ColorScheme, lightColors } from "@/constants";
+import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
+import {
+ StyleSheet,
+ TextInput,
+ TouchableOpacity,
+ View,
+ Text,
+} from "react-native";
+import PrimaryButton from "../PrimaryButton";
+import { useState } from "react";
+
+export function ShipForm() {
+ const colors = lightColors;
+ const styles = getStyles(colors);
+ const [patp, setPatp] = useState("~mirtyl-wacdec");
+ const [ticket, setTicket] = useState("~posseg-winnub-fogluc-dirmes");
+ const [isLoading, setIsLoading] = useState(false);
+ async function onSubmit() {
+ console.log({ patp, ticket });
+ }
+ return (
+ <View style={styles.bottomSection}>
+ <TextInput
+ style={styles.input}
+ placeholder="~sampel-palnet"
+ placeholderTextColor={colors.secondary}
+ value={patp}
+ onChangeText={setPatp}
+ autoCapitalize="none"
+ autoCorrect={false}
+ />
+ <TextInput
+ style={styles.input}
+ placeholder="~sampel-ticlyt-migfun-falmel"
+ placeholderTextColor={colors.secondary}
+ value={ticket}
+ onChangeText={setTicket}
+ autoCapitalize="none"
+ autoCorrect={false}
+ secureTextEntry
+ />
+
+ <PrimaryButton
+ label="Log in"
+ onPress={onSubmit}
+ style={{ marginTop: 0 }}
+ isLoading={isLoading}
+ />
+
+ <TouchableOpacity style={styles.footer}>
+ <Text style={styles.footerText}>No Urbit ID? Get yours.</Text>
+ </TouchableOpacity>
+ </View>
+ );
+}
+export const getStyles = (colors: ColorScheme) =>
+ StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: colors.background,
+ justifyContent: "space-between",
+ padding: 20,
+ },
+ topSection: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ walletIcon: {
+ width: 64,
+ height: 64,
+ marginBottom: 12,
+ },
+ logoText: {
+ fontSize: 18,
+ color: colors.text,
+ fontWeight: "400",
+ },
+ bottomSection: {
+ gap: 8,
+ marginBottom: 40,
+ },
+ input: {
+ height: 48,
+ backgroundColor: colors.card,
+ borderColor: colors.border,
+ borderWidth: 1,
+ borderRadius: 8,
+ paddingHorizontal: 16,
+ paddingVertical: 12,
+ color: colors.text,
+ fontWeight: "500",
+ fontSize: 16,
+ },
+ footer: {
+ marginTop: 50,
+ alignItems: "center",
+ },
+ footerText: {
+ color: colors.text,
+ fontSize: 16,
+ },
+ });
diff --git a/constants/config.ts b/constants/config.ts
index 6fa09b6..11379a5 100644
--- a/constants/config.ts
+++ b/constants/config.ts
@@ -1,5 +1,5 @@
import { JsonRpcProvider, WebSocketProvider } from "ethers";
-import { ETHEREUM_NETWORK } from "../constants";
+import { ETHEREUM_NETWORK } from "../constants/constants";
const isLocal = false;