aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/mobile/.eslintrc.js4
-rw-r--r--packages/mobile/.gitignore35
-rw-r--r--packages/mobile/.npmrc1
-rw-r--r--packages/mobile/app.json34
-rw-r--r--packages/mobile/app/_layout.tsx14
-rw-r--r--packages/mobile/app/index.tsx12
-rw-r--r--packages/mobile/app/signin.tsx24
-rw-r--r--packages/mobile/assets/adaptive-icon.pngbin0 -> 17547 bytes
-rw-r--r--packages/mobile/assets/favicon.pngbin0 -> 1466 bytes
-rw-r--r--packages/mobile/assets/icon.pngbin0 -> 22380 bytes
-rw-r--r--packages/mobile/assets/splash.pngbin0 -> 47346 bytes
-rw-r--r--packages/mobile/babel.config.js9
-rwxr-xr-xpackages/mobile/bun.lockbbin0 -> 478034 bytes
-rw-r--r--packages/mobile/components/Logo.tsx11
-rw-r--r--packages/mobile/components/ui/Button.tsx81
-rw-r--r--packages/mobile/components/ui/Input.tsx28
-rw-r--r--packages/mobile/globals.css80
-rw-r--r--packages/mobile/lib/utils.ts6
-rw-r--r--packages/mobile/metro.config.js7
-rw-r--r--packages/mobile/nativewind-env.d.ts1
-rw-r--r--packages/mobile/package.json41
-rw-r--r--packages/mobile/tailwind.config.js71
-rw-r--r--packages/mobile/tsconfig.json10
23 files changed, 469 insertions, 0 deletions
diff --git a/packages/mobile/.eslintrc.js b/packages/mobile/.eslintrc.js
new file mode 100644
index 00000000..53beac49
--- /dev/null
+++ b/packages/mobile/.eslintrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ["universe/native"],
+};
diff --git a/packages/mobile/.gitignore b/packages/mobile/.gitignore
new file mode 100644
index 00000000..05647d55
--- /dev/null
+++ b/packages/mobile/.gitignore
@@ -0,0 +1,35 @@
+# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
+
+# dependencies
+node_modules/
+
+# Expo
+.expo/
+dist/
+web-build/
+
+# Native
+*.orig.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+
+# Metro
+.metro-health-check*
+
+# debug
+npm-debug.*
+yarn-debug.*
+yarn-error.*
+
+# macOS
+.DS_Store
+*.pem
+
+# local env files
+.env*.local
+
+# typescript
+*.tsbuildinfo
diff --git a/packages/mobile/.npmrc b/packages/mobile/.npmrc
new file mode 100644
index 00000000..d67f3748
--- /dev/null
+++ b/packages/mobile/.npmrc
@@ -0,0 +1 @@
+node-linker=hoisted
diff --git a/packages/mobile/app.json b/packages/mobile/app.json
new file mode 100644
index 00000000..9ebea4ea
--- /dev/null
+++ b/packages/mobile/app.json
@@ -0,0 +1,34 @@
+{
+ "expo": {
+ "name": "hoarder-mobile",
+ "slug": "hoarder-mobile",
+ "scheme": "hoarder",
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "userInterfaceStyle": "light",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "ios": {
+ "supportsTablet": true
+ },
+ "android": {
+ "adaptiveIcon": {
+ "foregroundImage": "./assets/adaptive-icon.png",
+ "backgroundColor": "#ffffff"
+ }
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "plugins": [
+ "expo-router"
+ ]
+ }
+}
diff --git a/packages/mobile/app/_layout.tsx b/packages/mobile/app/_layout.tsx
new file mode 100644
index 00000000..7403c6ff
--- /dev/null
+++ b/packages/mobile/app/_layout.tsx
@@ -0,0 +1,14 @@
+import "@/globals.css";
+
+import { Slot } from "expo-router";
+import { StatusBar } from "expo-status-bar";
+import { View } from "react-native";
+
+export default function RootLayout() {
+ return (
+ <View className="w-full h-full bg-white">
+ <Slot />
+ <StatusBar style="auto" />
+ </View>
+ );
+}
diff --git a/packages/mobile/app/index.tsx b/packages/mobile/app/index.tsx
new file mode 100644
index 00000000..e352ba54
--- /dev/null
+++ b/packages/mobile/app/index.tsx
@@ -0,0 +1,12 @@
+import { Link } from "expo-router";
+import { View } from "react-native";
+
+export default function App() {
+ return (
+ <View className="flex-1 items-center justify-center bg-white">
+ <Link href="/signin" className="">
+ Signin
+ </Link>
+ </View>
+ );
+}
diff --git a/packages/mobile/app/signin.tsx b/packages/mobile/app/signin.tsx
new file mode 100644
index 00000000..f500e36e
--- /dev/null
+++ b/packages/mobile/app/signin.tsx
@@ -0,0 +1,24 @@
+import { View, Text } from "react-native";
+
+import Logo from "@/components/Logo";
+import { Button } from "@/components/ui/Button";
+import { Input } from "@/components/ui/Input";
+
+export default function Signin() {
+ return (
+ <View className="container justify-center h-full flex flex-col gap-2">
+ <View className="items-center">
+ <Logo />
+ </View>
+ <View className="gap-2">
+ <Text className="font-bold">Email</Text>
+ <Input className="w-full" placeholder="Email" />
+ </View>
+ <View className="gap-2">
+ <Text className="font-bold">Password</Text>
+ <Input className="w-full" placeholder="Password" secureTextEntry />
+ </View>
+ <Button className="w-full" label="Sign In" />
+ </View>
+ );
+}
diff --git a/packages/mobile/assets/adaptive-icon.png b/packages/mobile/assets/adaptive-icon.png
new file mode 100644
index 00000000..03d6f6b6
--- /dev/null
+++ b/packages/mobile/assets/adaptive-icon.png
Binary files differ
diff --git a/packages/mobile/assets/favicon.png b/packages/mobile/assets/favicon.png
new file mode 100644
index 00000000..e75f697b
--- /dev/null
+++ b/packages/mobile/assets/favicon.png
Binary files differ
diff --git a/packages/mobile/assets/icon.png b/packages/mobile/assets/icon.png
new file mode 100644
index 00000000..a0b1526f
--- /dev/null
+++ b/packages/mobile/assets/icon.png
Binary files differ
diff --git a/packages/mobile/assets/splash.png b/packages/mobile/assets/splash.png
new file mode 100644
index 00000000..0e89705a
--- /dev/null
+++ b/packages/mobile/assets/splash.png
Binary files differ
diff --git a/packages/mobile/babel.config.js b/packages/mobile/babel.config.js
new file mode 100644
index 00000000..f3c649bb
--- /dev/null
+++ b/packages/mobile/babel.config.js
@@ -0,0 +1,9 @@
+module.exports = function (api) {
+ api.cache(true);
+ return {
+ presets: [
+ ["babel-preset-expo", { jsxImportSource: "nativewind" }],
+ "nativewind/babel",
+ ],
+ };
+};
diff --git a/packages/mobile/bun.lockb b/packages/mobile/bun.lockb
new file mode 100755
index 00000000..219082f9
--- /dev/null
+++ b/packages/mobile/bun.lockb
Binary files differ
diff --git a/packages/mobile/components/Logo.tsx b/packages/mobile/components/Logo.tsx
new file mode 100644
index 00000000..a15d8561
--- /dev/null
+++ b/packages/mobile/components/Logo.tsx
@@ -0,0 +1,11 @@
+import { PackageOpen } from "lucide-react-native";
+import { View, Text } from "react-native";
+
+export default function Logo() {
+ return (
+ <View className="flex flex-row gap-2 justify-center items-center ">
+ <PackageOpen color="black" size={70} />
+ <Text className="text-5xl">Hoarder</Text>
+ </View>
+ );
+}
diff --git a/packages/mobile/components/ui/Button.tsx b/packages/mobile/components/ui/Button.tsx
new file mode 100644
index 00000000..4c3cbc69
--- /dev/null
+++ b/packages/mobile/components/ui/Button.tsx
@@ -0,0 +1,81 @@
+import { type VariantProps, cva } from "class-variance-authority";
+import { Text, TouchableOpacity } from "react-native";
+
+import { cn } from "@/lib/utils";
+
+const buttonVariants = cva(
+ "flex flex-row items-center justify-center rounded-md",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary",
+ secondary: "bg-secondary",
+ destructive: "bg-destructive",
+ ghost: "bg-slate-700",
+ link: "text-primary underline-offset-4",
+ },
+ size: {
+ default: "h-10 px-4",
+ sm: "h-8 px-2",
+ lg: "h-12 px-8",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
+);
+
+const buttonTextVariants = cva("text-center font-medium", {
+ variants: {
+ variant: {
+ default: "text-primary-foreground",
+ secondary: "text-secondary-foreground",
+ destructive: "text-destructive-foreground",
+ ghost: "text-primary-foreground",
+ link: "text-primary-foreground underline",
+ },
+ size: {
+ default: "text-base",
+ sm: "text-sm",
+ lg: "text-xl",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+});
+
+interface ButtonProps
+ extends React.ComponentPropsWithoutRef<typeof TouchableOpacity>,
+ VariantProps<typeof buttonVariants> {
+ label: string;
+ labelClasses?: string;
+}
+function Button({
+ label,
+ labelClasses,
+ className,
+ variant,
+ size,
+ ...props
+}: ButtonProps) {
+ return (
+ <TouchableOpacity
+ className={cn(buttonVariants({ variant, size, className }))}
+ {...props}
+ >
+ <Text
+ className={cn(
+ buttonTextVariants({ variant, size, className: labelClasses }),
+ )}
+ >
+ {label}
+ </Text>
+ </TouchableOpacity>
+ );
+}
+
+export { Button, buttonVariants, buttonTextVariants };
diff --git a/packages/mobile/components/ui/Input.tsx b/packages/mobile/components/ui/Input.tsx
new file mode 100644
index 00000000..6fc90b8f
--- /dev/null
+++ b/packages/mobile/components/ui/Input.tsx
@@ -0,0 +1,28 @@
+import { forwardRef } from "react";
+import { Text, TextInput, View } from "react-native";
+
+import { cn } from "@/lib/utils";
+
+export interface InputProps
+ extends React.ComponentPropsWithoutRef<typeof TextInput> {
+ label?: string;
+ labelClasses?: string;
+ inputClasses?: string;
+}
+
+const Input = forwardRef<React.ElementRef<typeof TextInput>, InputProps>(
+ ({ className, label, labelClasses, inputClasses, ...props }, ref) => (
+ <View className={cn("flex flex-col gap-1.5", className)}>
+ {label && <Text className={cn("text-base", labelClasses)}>{label}</Text>}
+ <TextInput
+ className={cn(
+ inputClasses,
+ "border border-input py-2.5 px-4 rounded-lg",
+ )}
+ {...props}
+ />
+ </View>
+ ),
+);
+
+export { Input };
diff --git a/packages/mobile/globals.css b/packages/mobile/globals.css
new file mode 100644
index 00000000..de1cf559
--- /dev/null
+++ b/packages/mobile/globals.css
@@ -0,0 +1,80 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 222.2 47.4% 11.2%;
+
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 47.4% 11.2%;
+
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 47.4% 11.2%;
+
+ --primary: 222.2 47.4% 11.2%;
+ --primary-foreground: 210 40% 98%;
+
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+
+ --destructive: 0 100% 50%;
+ --destructive-foreground: 210 40% 98%;
+
+ --ring: 215 20.2% 65.1%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark:root {
+ --background: 224 71% 4%;
+ --foreground: 213 31% 91%;
+
+ --muted: 223 47% 11%;
+ --muted-foreground: 215.4 16.3% 56.9%;
+
+ --accent: 216 34% 17%;
+ --accent-foreground: 210 40% 98%;
+
+ --popover: 224 71% 4%;
+ --popover-foreground: 215 20.2% 65.1%;
+
+ --border: 216 34% 17%;
+ --input: 216 34% 17%;
+
+ --card: 224 71% 4%;
+ --card-foreground: 213 31% 91%;
+
+ --primary: 210 40% 98%;
+ --primary-foreground: 222.2 47.4% 1.2%;
+
+ --secondary: 222.2 47.4% 11.2%;
+ --secondary-foreground: 210 40% 98%;
+
+ --destructive: 0 63% 31%;
+ --destructive-foreground: 210 40% 98%;
+
+ --ring: 216 34% 17%;
+
+ --radius: 0.5rem;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/packages/mobile/lib/utils.ts b/packages/mobile/lib/utils.ts
new file mode 100644
index 00000000..365058ce
--- /dev/null
+++ b/packages/mobile/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/packages/mobile/metro.config.js b/packages/mobile/metro.config.js
new file mode 100644
index 00000000..bbd30d1d
--- /dev/null
+++ b/packages/mobile/metro.config.js
@@ -0,0 +1,7 @@
+const { getDefaultConfig } = require("expo/metro-config");
+const { withNativeWind } = require("nativewind/metro");
+
+/** @type {import('expo/metro-config').MetroConfig} */
+const config = getDefaultConfig(__dirname);
+
+module.exports = withNativeWind(config, { input: "./globals.css" });
diff --git a/packages/mobile/nativewind-env.d.ts b/packages/mobile/nativewind-env.d.ts
new file mode 100644
index 00000000..a13e3136
--- /dev/null
+++ b/packages/mobile/nativewind-env.d.ts
@@ -0,0 +1 @@
+/// <reference types="nativewind/types" />
diff --git a/packages/mobile/package.json b/packages/mobile/package.json
new file mode 100644
index 00000000..4dbd0cf5
--- /dev/null
+++ b/packages/mobile/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "hoarder-mobile",
+ "version": "1.0.0",
+ "main": "expo-router/entry",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web",
+ "lint": "eslint ."
+ },
+ "dependencies": {
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.0",
+ "expo": "~50.0.11",
+ "expo-constants": "~15.4.5",
+ "expo-linking": "~6.2.2",
+ "expo-router": "~3.4.8",
+ "expo-status-bar": "~1.11.1",
+ "lucide-react-native": "^0.354.0",
+ "nativewind": "^4.0.1",
+ "react": "18.2.0",
+ "react-native": "0.73.4",
+ "react-native-reanimated": "^3.8.0",
+ "react-native-safe-area-context": "4.8.2",
+ "react-native-screens": "~3.29.0",
+ "react-native-svg": "^15.1.0",
+ "tailwind-merge": "^2.2.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.20.0",
+ "@types/react": "~18.2.45",
+ "ajv": "latest",
+ "eslint": "^8.57.0",
+ "eslint-config-universe": "^12.0.0",
+ "prettier": "^3.2.5",
+ "tailwindcss": "3.3.2",
+ "typescript": "^5.1.3"
+ },
+ "private": true
+}
diff --git a/packages/mobile/tailwind.config.js b/packages/mobile/tailwind.config.js
new file mode 100644
index 00000000..b49f9598
--- /dev/null
+++ b/packages/mobile/tailwind.config.js
@@ -0,0 +1,71 @@
+const { hairlineWidth } = require("nativewind/theme");
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
+ plugins: [],
+ presets: [require("nativewind/preset")],
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderWidth: {
+ hairline: hairlineWidth(),
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
+ },
+};
diff --git a/packages/mobile/tsconfig.json b/packages/mobile/tsconfig.json
new file mode 100644
index 00000000..84d97cb0
--- /dev/null
+++ b/packages/mobile/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "expo/tsconfig.base",
+ "compilerOptions": {
+ "strict": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./*"]
+ }
+ }
+}