newcandies 0.1.24 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/app-briefs/expo-router/cozynotes/README.md +79 -0
- package/templates/app-briefs/expo-router/cozynotes/app.json +51 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/fonts/Caveat-Bold.ttf +0 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/fonts/Caveat-Regular.ttf +0 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/images/adaptive-icon.png +0 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/images/favicon.png +0 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/images/icon.png +0 -0
- package/templates/app-briefs/expo-router/cozynotes/assets/images/splash-icon.png +0 -0
- package/templates/app-briefs/expo-router/cozynotes/babel.config.js +8 -0
- package/templates/app-briefs/expo-router/cozynotes/eas.json +22 -0
- package/templates/app-briefs/expo-router/cozynotes/env +2 -0
- package/templates/app-briefs/expo-router/cozynotes/expo-env.d.ts +3 -0
- package/templates/app-briefs/expo-router/cozynotes/global.css +37 -0
- package/templates/app-briefs/expo-router/cozynotes/metro.config.js +15 -0
- package/templates/app-briefs/expo-router/cozynotes/package.json +53 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/_layout.tsx +24 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/about.tsx +25 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/index.tsx +62 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/note/[id].tsx +39 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/note/edit.tsx +30 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/note/new.tsx +26 -0
- package/templates/app-briefs/expo-router/cozynotes/src/app/settings.tsx +24 -0
- package/templates/app-briefs/expo-router/cozynotes/src/components/screens/home/note-card.tsx +65 -0
- package/templates/app-briefs/expo-router/cozynotes/src/components/ui/back-button.tsx +24 -0
- package/templates/app-briefs/expo-router/cozynotes/src/components/ui/screen.tsx +20 -0
- package/templates/app-briefs/expo-router/cozynotes/src/components/ui/squircle.tsx +7 -0
- package/templates/app-briefs/expo-router/cozynotes/src/components/ui/text.tsx +48 -0
- package/templates/app-briefs/expo-router/cozynotes/src/lib/constants/index.ts +2 -0
- package/templates/app-briefs/expo-router/cozynotes/src/lib/constants/notes.ts +136 -0
- package/templates/app-briefs/expo-router/cozynotes/src/types/note.d.ts +9 -0
- package/templates/app-briefs/expo-router/cozynotes/tsconfig.json +17 -0
- package/templates/app-briefs/expo-router/flourish/README.md +100 -0
- package/templates/app-briefs/expo-router/flourish/app.json +42 -0
- package/templates/app-briefs/expo-router/flourish/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/templates/app-briefs/expo-router/flourish/assets/images/adaptive-icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish/assets/images/favicon.png +0 -0
- package/templates/app-briefs/expo-router/flourish/assets/images/icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish/assets/images/splash-icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish/babel.config.js +8 -0
- package/templates/app-briefs/expo-router/flourish/eas.json +22 -0
- package/templates/app-briefs/expo-router/flourish/env +2 -0
- package/templates/app-briefs/expo-router/flourish/expo-env.d.ts +3 -0
- package/templates/app-briefs/expo-router/flourish/global.css +53 -0
- package/templates/app-briefs/expo-router/flourish/metro.config.js +15 -0
- package/templates/app-briefs/expo-router/flourish/package.json +54 -0
- package/templates/app-briefs/expo-router/flourish/src/app/(tabs)/_layout.tsx +71 -0
- package/templates/app-briefs/expo-router/flourish/src/app/(tabs)/explore.tsx +24 -0
- package/templates/app-briefs/expo-router/flourish/src/app/(tabs)/index.tsx +102 -0
- package/templates/app-briefs/expo-router/flourish/src/app/(tabs)/profile.tsx +25 -0
- package/templates/app-briefs/expo-router/flourish/src/app/(tabs)/search.tsx +24 -0
- package/templates/app-briefs/expo-router/flourish/src/app/_layout.tsx +31 -0
- package/templates/app-briefs/expo-router/flourish/src/app/plant/[id].tsx +48 -0
- package/templates/app-briefs/expo-router/flourish/src/components/ui/screen.tsx +20 -0
- package/templates/app-briefs/expo-router/flourish/src/components/ui/squircle.tsx +5 -0
- package/templates/app-briefs/expo-router/flourish/src/components/ui/text.tsx +55 -0
- package/templates/app-briefs/expo-router/flourish/src/lib/constants/index.ts +148 -0
- package/templates/app-briefs/expo-router/flourish/src/lib/utils/index.ts +8 -0
- package/templates/app-briefs/expo-router/flourish/src/types/plant.d.ts +38 -0
- package/templates/app-briefs/expo-router/flourish/tsconfig.json +17 -0
- package/templates/app-briefs/expo-router/flourish-auth/README.md +153 -0
- package/templates/app-briefs/expo-router/flourish-auth/app.json +42 -0
- package/templates/app-briefs/expo-router/flourish-auth/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/templates/app-briefs/expo-router/flourish-auth/assets/images/adaptive-icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish-auth/assets/images/favicon.png +0 -0
- package/templates/app-briefs/expo-router/flourish-auth/assets/images/icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish-auth/assets/images/splash-icon.png +0 -0
- package/templates/app-briefs/expo-router/flourish-auth/babel.config.js +8 -0
- package/templates/app-briefs/expo-router/flourish-auth/eas.json +22 -0
- package/templates/app-briefs/expo-router/flourish-auth/env +2 -0
- package/templates/app-briefs/expo-router/flourish-auth/expo-env.d.ts +3 -0
- package/templates/app-briefs/expo-router/flourish-auth/global.css +53 -0
- package/templates/app-briefs/expo-router/flourish-auth/metro.config.js +15 -0
- package/templates/app-briefs/expo-router/flourish-auth/package.json +55 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(auth)/_layout.tsx +14 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(auth)/sign-in.tsx +25 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(auth)/sign-up.tsx +26 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(auth)/welcome.tsx +22 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(tabs)/_layout.tsx +71 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(tabs)/explore.tsx +24 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(tabs)/index.tsx +102 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(tabs)/profile.tsx +27 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/(tabs)/search.tsx +24 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/_layout.tsx +48 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/app/plant/[id].tsx +48 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/components/ui/screen.tsx +20 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/components/ui/squircle.tsx +5 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/components/ui/text.tsx +55 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/lib/constants/index.ts +148 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/lib/stores/README.md +31 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/lib/utils/index.ts +8 -0
- package/templates/app-briefs/expo-router/flourish-auth/src/types/plant.d.ts +38 -0
- package/templates/app-briefs/expo-router/flourish-auth/tsconfig.json +17 -0
- package/templates/app-briefs/react-query/sproutsy/global.css +23 -0
- package/templates/app-briefs/zustand/yummy/README.md +63 -0
- package/templates/app-briefs/zustand/yummy/app.json +42 -0
- package/templates/app-briefs/zustand/yummy/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/templates/app-briefs/zustand/yummy/assets/images/adaptive-icon.png +0 -0
- package/templates/app-briefs/zustand/yummy/assets/images/favicon.png +0 -0
- package/templates/app-briefs/zustand/yummy/assets/images/icon.png +0 -0
- package/templates/app-briefs/zustand/yummy/assets/images/splash-icon.png +0 -0
- package/templates/app-briefs/zustand/yummy/babel.config.js +8 -0
- package/templates/app-briefs/zustand/yummy/eas.json +22 -0
- package/templates/app-briefs/zustand/yummy/env +2 -0
- package/templates/app-briefs/zustand/yummy/expo-env.d.ts +3 -0
- package/templates/app-briefs/zustand/yummy/global.css +69 -0
- package/templates/app-briefs/zustand/yummy/metro.config.js +15 -0
- package/templates/app-briefs/zustand/yummy/package.json +55 -0
- package/templates/app-briefs/zustand/yummy/src/app/(tabs)/_layout.tsx +63 -0
- package/templates/app-briefs/zustand/yummy/src/app/(tabs)/cart.tsx +146 -0
- package/templates/app-briefs/zustand/yummy/src/app/(tabs)/index.tsx +76 -0
- package/templates/app-briefs/zustand/yummy/src/app/_layout.tsx +37 -0
- package/templates/app-briefs/zustand/yummy/src/components/ui/screen.tsx +18 -0
- package/templates/app-briefs/zustand/yummy/src/components/ui/squircle.tsx +5 -0
- package/templates/app-briefs/zustand/yummy/src/components/ui/text.tsx +55 -0
- package/templates/app-briefs/zustand/yummy/src/lib/constants/index.ts +45 -0
- package/templates/app-briefs/zustand/yummy/src/store/README.md +45 -0
- package/templates/app-briefs/zustand/yummy/src/types/product.d.ts +12 -0
- package/templates/app-briefs/zustand/yummy/tsconfig.json +17 -0
- package/templates/registry.json +38 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "Flourish Auth",
|
|
4
|
+
"slug": "flourish-auth",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/images/icon.png",
|
|
8
|
+
"scheme": "flourish-auth",
|
|
9
|
+
"userInterfaceStyle": "automatic",
|
|
10
|
+
"newArchEnabled": true,
|
|
11
|
+
"splash": {
|
|
12
|
+
"image": "./assets/images/splash-icon.png",
|
|
13
|
+
"resizeMode": "contain",
|
|
14
|
+
"backgroundColor": "#ffffff"
|
|
15
|
+
},
|
|
16
|
+
"ios": {
|
|
17
|
+
"supportsTablet": true,
|
|
18
|
+
"bundleIdentifier": "com.example.flourishauth"
|
|
19
|
+
},
|
|
20
|
+
"android": {
|
|
21
|
+
"adaptiveIcon": {
|
|
22
|
+
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
23
|
+
"backgroundColor": "#ffffff"
|
|
24
|
+
},
|
|
25
|
+
"edgeToEdgeEnabled": true,
|
|
26
|
+
"predictiveBackGestureEnabled": false,
|
|
27
|
+
"package": "com.example.flourishauth"
|
|
28
|
+
},
|
|
29
|
+
"web": {
|
|
30
|
+
"bundler": "metro",
|
|
31
|
+
"output": "static",
|
|
32
|
+
"favicon": "./assets/images/favicon.png"
|
|
33
|
+
},
|
|
34
|
+
"plugins": [
|
|
35
|
+
"expo-router"
|
|
36
|
+
],
|
|
37
|
+
"experiments": {
|
|
38
|
+
"typedRoutes": true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cli": {
|
|
3
|
+
"version": ">= 7.0.0"
|
|
4
|
+
},
|
|
5
|
+
"build": {
|
|
6
|
+
"development": {
|
|
7
|
+
"android": {
|
|
8
|
+
"buildType": "apk"
|
|
9
|
+
},
|
|
10
|
+
"developmentClient": true,
|
|
11
|
+
"distribution": "internal"
|
|
12
|
+
},
|
|
13
|
+
"preview": {
|
|
14
|
+
"distribution": "internal"
|
|
15
|
+
},
|
|
16
|
+
"production": {}
|
|
17
|
+
},
|
|
18
|
+
"submit": {
|
|
19
|
+
"production": {}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "uniwind";
|
|
3
|
+
|
|
4
|
+
@layer theme {
|
|
5
|
+
:root {
|
|
6
|
+
@variant light {
|
|
7
|
+
--color-background: #e7edde;
|
|
8
|
+
--color-foreground: #111827;
|
|
9
|
+
|
|
10
|
+
--color-primary: #234823;
|
|
11
|
+
--color-primary-foreground: #e8ede1;
|
|
12
|
+
|
|
13
|
+
--color-secondary: #e0ffc2;
|
|
14
|
+
--color-secondary-foreground: #234823;
|
|
15
|
+
|
|
16
|
+
--color-accent: #ffce47;
|
|
17
|
+
--color-accent-foreground: #234823;
|
|
18
|
+
|
|
19
|
+
--color-muted: #c4dea9;
|
|
20
|
+
--color-muted-foreground: #739265;
|
|
21
|
+
|
|
22
|
+
--color-card: #234823;
|
|
23
|
+
--color-card-foreground: #e8ede1;
|
|
24
|
+
|
|
25
|
+
--color-overlay: #ffffff33;
|
|
26
|
+
--color-overlay-muted: #ffffff1a;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@variant dark {
|
|
30
|
+
--color-background: #0f1a0f;
|
|
31
|
+
--color-foreground: #e8ede1;
|
|
32
|
+
|
|
33
|
+
--color-primary: #4a9c4a;
|
|
34
|
+
--color-primary-foreground: #0f1a0f;
|
|
35
|
+
|
|
36
|
+
--color-secondary: #1e3a1e;
|
|
37
|
+
--color-secondary-foreground: #c4dea9;
|
|
38
|
+
|
|
39
|
+
--color-accent: #ffce47;
|
|
40
|
+
--color-accent-foreground: #0f1a0f;
|
|
41
|
+
|
|
42
|
+
--color-muted: #1a2e1a;
|
|
43
|
+
--color-muted-foreground: #739265;
|
|
44
|
+
|
|
45
|
+
--color-card: #162516;
|
|
46
|
+
--color-card-foreground: #e8ede1;
|
|
47
|
+
|
|
48
|
+
--color-overlay: #0000004d;
|
|
49
|
+
--color-overlay-muted: #0000001a;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { withRozenite } = require("@rozenite/metro");
|
|
2
|
+
const { getDefaultConfig } = require("expo/metro-config");
|
|
3
|
+
const { withUniwindConfig } = require("uniwind/metro");
|
|
4
|
+
|
|
5
|
+
const config = getDefaultConfig(__dirname);
|
|
6
|
+
|
|
7
|
+
module.exports = withRozenite(
|
|
8
|
+
withUniwindConfig(config, {
|
|
9
|
+
cssEntryFile: "./global.css",
|
|
10
|
+
dtsFile: "./uniwind-types.d.ts",
|
|
11
|
+
extraThemes: [],
|
|
12
|
+
}),
|
|
13
|
+
{ enabled: process.env.WITH_ROZENITE === "true" }
|
|
14
|
+
);
|
|
15
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flourish-auth",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "expo-router/entry",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "expo start --dev-client",
|
|
8
|
+
"android": "expo run:android",
|
|
9
|
+
"ios": "expo run:ios",
|
|
10
|
+
"prebuild": "expo prebuild"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@expo/vector-icons": "^15.0.3",
|
|
14
|
+
"@gorhom/bottom-sheet": "latest",
|
|
15
|
+
"@rozenite/mmkv-plugin": "^1.0.0-alpha.16",
|
|
16
|
+
"@rozenite/performance-monitor-plugin": "^1.0.0-alpha.16",
|
|
17
|
+
"@shopify/flash-list": "^2.2.0",
|
|
18
|
+
"date-fns": "^4.1.0",
|
|
19
|
+
"expo": "54.0.23",
|
|
20
|
+
"expo-constants": "~18.0.10",
|
|
21
|
+
"expo-font": "~14.0.9",
|
|
22
|
+
"expo-linear-gradient": "^15.0.7",
|
|
23
|
+
"expo-linking": "~8.0.8",
|
|
24
|
+
"expo-router": "~6.0.14",
|
|
25
|
+
"expo-splash-screen": "~31.0.10",
|
|
26
|
+
"expo-status-bar": "~3.0.8",
|
|
27
|
+
"expo-system-ui": "~6.0.8",
|
|
28
|
+
"expo-web-browser": "~15.0.9",
|
|
29
|
+
"react": "19.1.0",
|
|
30
|
+
"react-dom": "19.1.0",
|
|
31
|
+
"react-native": "0.81.5",
|
|
32
|
+
"react-native-fast-squircle": "^1.0.11",
|
|
33
|
+
"react-native-gesture-handler": "~2.28.0",
|
|
34
|
+
"react-native-keyboard-controller": "latest",
|
|
35
|
+
"react-native-mmkv": "^4.0.0",
|
|
36
|
+
"react-native-reanimated": "~4.1.1",
|
|
37
|
+
"react-native-safe-area-context": "~5.6.0",
|
|
38
|
+
"react-native-screens": "~4.16.0",
|
|
39
|
+
"react-native-svg": "^15.14.0",
|
|
40
|
+
"react-native-web": "~0.21.0",
|
|
41
|
+
"react-native-worklets": "0.5.1",
|
|
42
|
+
"sonner-native": "latest",
|
|
43
|
+
"tailwind-merge": "latest",
|
|
44
|
+
"tailwindcss": "^4.1.16",
|
|
45
|
+
"uniwind": "^1.0.0",
|
|
46
|
+
"zustand": "^5.0.9"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@rozenite/metro": "^1.0.0-alpha.16",
|
|
50
|
+
"@types/react": "~19.1.0",
|
|
51
|
+
"babel-plugin-module-resolver": "latest",
|
|
52
|
+
"typescript": "~5.9.2"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Stack } from "expo-router";
|
|
2
|
+
|
|
3
|
+
export default function AuthLayout() {
|
|
4
|
+
// This is the auth stack navigator
|
|
5
|
+
// It wraps the welcome, sign-in, and sign-up screens
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<Stack screenOptions={{ headerShown: false }}>
|
|
9
|
+
<Stack.Screen name="welcome" />
|
|
10
|
+
<Stack.Screen name="sign-in" />
|
|
11
|
+
<Stack.Screen name="sign-up" />
|
|
12
|
+
</Stack>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function SignIn() {
|
|
6
|
+
// TODO: Build the sign-in screen
|
|
7
|
+
// - Add back button to go back
|
|
8
|
+
// - Add email input field
|
|
9
|
+
// - Add password input field
|
|
10
|
+
// - Add "Sign In" button that calls login() from auth store
|
|
11
|
+
// - Add link to sign-up screen
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Screen>
|
|
15
|
+
<View className="flex-1 px-6 justify-center">
|
|
16
|
+
<Text variant="display" className="text-primary">
|
|
17
|
+
Sign In
|
|
18
|
+
</Text>
|
|
19
|
+
<Text className="text-muted-foreground mt-2">
|
|
20
|
+
Build this screen with email/password form
|
|
21
|
+
</Text>
|
|
22
|
+
</View>
|
|
23
|
+
</Screen>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function SignUp() {
|
|
6
|
+
// TODO: Build the sign-up screen
|
|
7
|
+
// - Add back button to go back
|
|
8
|
+
// - Add name input field
|
|
9
|
+
// - Add email input field
|
|
10
|
+
// - Add password input field
|
|
11
|
+
// - Add "Create Account" button that calls login() from auth store
|
|
12
|
+
// - Add link to sign-in screen
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Screen>
|
|
16
|
+
<View className="flex-1 px-6 justify-center">
|
|
17
|
+
<Text variant="display" className="text-primary">
|
|
18
|
+
Sign Up
|
|
19
|
+
</Text>
|
|
20
|
+
<Text className="text-muted-foreground mt-2">
|
|
21
|
+
Build this screen with registration form
|
|
22
|
+
</Text>
|
|
23
|
+
</View>
|
|
24
|
+
</Screen>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function Welcome() {
|
|
6
|
+
// TODO: Build the welcome/landing screen
|
|
7
|
+
// - Display app logo/icon (use MaterialCommunityIcons "flower")
|
|
8
|
+
// - Show app name "Flourish" and tagline
|
|
9
|
+
// - Add "Get Started" button → navigates to sign-up
|
|
10
|
+
// - Add "Already have an account? Sign In" link → navigates to sign-in
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Screen className="justify-center items-center">
|
|
14
|
+
<Text variant="display" className="text-primary">
|
|
15
|
+
Welcome
|
|
16
|
+
</Text>
|
|
17
|
+
<Text className="text-muted-foreground mt-2">
|
|
18
|
+
Build this screen with login/signup buttons
|
|
19
|
+
</Text>
|
|
20
|
+
</Screen>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import IonIcons from "@expo/vector-icons/Ionicons";
|
|
2
|
+
import { Tabs } from "expo-router";
|
|
3
|
+
import { useCSSVariable } from "uniwind";
|
|
4
|
+
|
|
5
|
+
function TabBarIcon(props: {
|
|
6
|
+
name: React.ComponentProps<typeof IonIcons>["name"];
|
|
7
|
+
color: string;
|
|
8
|
+
}) {
|
|
9
|
+
return <IonIcons size={28} style={{ marginBottom: -4 }} {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function TabLayout() {
|
|
13
|
+
const backgroundColor = useCSSVariable("--color-muted") as string;
|
|
14
|
+
const primaryColor = useCSSVariable("--color-primary") as string;
|
|
15
|
+
const tabBarActiveTintColor = useCSSVariable(
|
|
16
|
+
"--color-muted-foreground"
|
|
17
|
+
) as string;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Tabs
|
|
21
|
+
screenOptions={{
|
|
22
|
+
headerShown: false,
|
|
23
|
+
tabBarActiveTintColor: primaryColor,
|
|
24
|
+
tabBarInactiveTintColor: tabBarActiveTintColor,
|
|
25
|
+
tabBarStyle: {
|
|
26
|
+
backgroundColor,
|
|
27
|
+
},
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
<Tabs.Screen
|
|
31
|
+
name="index"
|
|
32
|
+
options={{
|
|
33
|
+
title: "Home",
|
|
34
|
+
headerShown: false,
|
|
35
|
+
tabBarShowLabel: false,
|
|
36
|
+
tabBarIcon: ({ color }) => (
|
|
37
|
+
<TabBarIcon name="partly-sunny" color={color} />
|
|
38
|
+
),
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
<Tabs.Screen
|
|
42
|
+
name="explore"
|
|
43
|
+
options={{
|
|
44
|
+
title: "Explore",
|
|
45
|
+
headerShown: false,
|
|
46
|
+
tabBarShowLabel: false,
|
|
47
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="grid" color={color} />,
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
<Tabs.Screen
|
|
51
|
+
name="search"
|
|
52
|
+
options={{
|
|
53
|
+
title: "Search",
|
|
54
|
+
headerShown: false,
|
|
55
|
+
tabBarShowLabel: false,
|
|
56
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="search" color={color} />,
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
<Tabs.Screen
|
|
60
|
+
name="profile"
|
|
61
|
+
options={{
|
|
62
|
+
title: "Profile",
|
|
63
|
+
headerShown: false,
|
|
64
|
+
tabBarShowLabel: false,
|
|
65
|
+
tabBarIcon: ({ color }) => <TabBarIcon name="person" color={color} />,
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
</Tabs>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function Explore() {
|
|
6
|
+
// TODO: Implement the Explore screen
|
|
7
|
+
// - Add category filters (Indoor, Outdoor, Low Water, Pet Safe, Beginner)
|
|
8
|
+
// - Display plants in a vertical list with larger cards
|
|
9
|
+
// - Navigate to plant detail on press
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Screen>
|
|
13
|
+
<View className="px-5 pt-4 pb-4">
|
|
14
|
+
<Text variant="display" className="text-primary">
|
|
15
|
+
Explore
|
|
16
|
+
</Text>
|
|
17
|
+
<Text className="text-muted-foreground mt-2">
|
|
18
|
+
Build this screen to browse plants by category
|
|
19
|
+
</Text>
|
|
20
|
+
</View>
|
|
21
|
+
</Screen>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { View, Image, Pressable, FlatList } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
import { Squircle } from "~/components/ui/squircle";
|
|
5
|
+
import { customPlants } from "~/lib/constants";
|
|
6
|
+
import { useRouter } from "expo-router";
|
|
7
|
+
import { format } from "date-fns";
|
|
8
|
+
import { getWeekDays } from "~/lib/utils";
|
|
9
|
+
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const weekDays = getWeekDays(now);
|
|
12
|
+
|
|
13
|
+
const HomeHeader = () => {
|
|
14
|
+
return (
|
|
15
|
+
<View className="px-5 pt-4 pb-4">
|
|
16
|
+
<View className="flex-row justify-between items-start mb-5">
|
|
17
|
+
<View className="flex-row items-center gap-2">
|
|
18
|
+
<Text variant="display" className="text-4xl">{format(now, "EEE")}</Text>
|
|
19
|
+
<View className="w-3 h-3 rounded-full bg-accent" />
|
|
20
|
+
</View>
|
|
21
|
+
|
|
22
|
+
<View className="items-end">
|
|
23
|
+
<Text variant="subtitle">{format(now, "MMMM d")}</Text>
|
|
24
|
+
<Text className="text-lg text-foreground/70">{format(now, "yyyy")}</Text>
|
|
25
|
+
</View>
|
|
26
|
+
</View>
|
|
27
|
+
|
|
28
|
+
<View className="flex-row justify-between">
|
|
29
|
+
{weekDays.map((day, index) => (
|
|
30
|
+
<View key={index} className="items-center">
|
|
31
|
+
{day.isToday ? (
|
|
32
|
+
<Squircle
|
|
33
|
+
className="bg-primary px-2 py-2 items-center rounded-xl"
|
|
34
|
+
cornerSmoothing={1}
|
|
35
|
+
>
|
|
36
|
+
<Text className="text-lg font-bold text-primary-foreground">
|
|
37
|
+
{day.date}
|
|
38
|
+
</Text>
|
|
39
|
+
<Text className="text-xs font-medium text-secondary mt-1">
|
|
40
|
+
{day.day}
|
|
41
|
+
</Text>
|
|
42
|
+
</Squircle>
|
|
43
|
+
) : (
|
|
44
|
+
<View className="px-2 py-2 items-center">
|
|
45
|
+
<Text className="text-lg font-medium text-primary/40">
|
|
46
|
+
{day.date}
|
|
47
|
+
</Text>
|
|
48
|
+
<Text className="text-xs font-medium text-primary/30 mt-1">
|
|
49
|
+
{day.day}
|
|
50
|
+
</Text>
|
|
51
|
+
</View>
|
|
52
|
+
)}
|
|
53
|
+
</View>
|
|
54
|
+
))}
|
|
55
|
+
</View>
|
|
56
|
+
</View>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const PlantCard = ({ item, onPress }: { item: Plant; onPress?: () => void }) => (
|
|
61
|
+
<Pressable onPress={onPress} className="flex-1">
|
|
62
|
+
<Squircle className="bg-primary overflow-hidden rounded-3xl p-2" cornerSmoothing={1}>
|
|
63
|
+
<Squircle className="overflow-hidden rounded-2xl w-full aspect-square" cornerSmoothing={1}>
|
|
64
|
+
<Image source={{ uri: item.coverImg }} className="w-full h-full" resizeMode="cover" />
|
|
65
|
+
</Squircle>
|
|
66
|
+
<View className="px-1 py-2">
|
|
67
|
+
<Text variant="body-secondary" className="text-primary-foreground">{item.name}</Text>
|
|
68
|
+
</View>
|
|
69
|
+
</Squircle>
|
|
70
|
+
</Pressable>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const ListHeader = () => (
|
|
74
|
+
<>
|
|
75
|
+
<HomeHeader />
|
|
76
|
+
<View className="px-5 pb-4">
|
|
77
|
+
<Text variant="subtitle" className="text-primary">Our Plants</Text>
|
|
78
|
+
</View>
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
export default function Index() {
|
|
83
|
+
const router = useRouter();
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Screen>
|
|
87
|
+
<FlatList
|
|
88
|
+
data={customPlants}
|
|
89
|
+
numColumns={2}
|
|
90
|
+
keyExtractor={(item) => item.id}
|
|
91
|
+
renderItem={({ item }) => (
|
|
92
|
+
<PlantCard item={item} onPress={() => router.push(`/plant/${item.id}`)} />
|
|
93
|
+
)}
|
|
94
|
+
ListHeaderComponent={ListHeader}
|
|
95
|
+
columnWrapperClassName="gap-4 px-5"
|
|
96
|
+
contentContainerClassName="gap-4 pb-8"
|
|
97
|
+
showsVerticalScrollIndicator={false}
|
|
98
|
+
/>
|
|
99
|
+
</Screen>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function Profile() {
|
|
6
|
+
// TODO: Build the profile screen
|
|
7
|
+
// - Import useAuth from ~/lib/stores/auth
|
|
8
|
+
// - Get logout function from auth store
|
|
9
|
+
// - Display user avatar and name
|
|
10
|
+
// - Show plant stats (plants owned, waterings)
|
|
11
|
+
// - Add "Currently..." status card
|
|
12
|
+
// - Add Edit Profile button
|
|
13
|
+
// - Add Sign Out button that calls logout()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Screen>
|
|
17
|
+
<View className="px-5 pt-4">
|
|
18
|
+
<Text variant="display" className="text-primary">
|
|
19
|
+
Profile
|
|
20
|
+
</Text>
|
|
21
|
+
<Text className="text-muted-foreground mt-2">
|
|
22
|
+
Build this screen with user info and Sign Out button
|
|
23
|
+
</Text>
|
|
24
|
+
</View>
|
|
25
|
+
</Screen>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Screen } from "~/components/ui/screen";
|
|
3
|
+
import Text from "~/components/ui/text";
|
|
4
|
+
|
|
5
|
+
export default function Search() {
|
|
6
|
+
// TODO: Implement the Search screen
|
|
7
|
+
// - Add a search input with icon
|
|
8
|
+
// - Filter plants by name as user types
|
|
9
|
+
// - Display matching results
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Screen>
|
|
13
|
+
<View className="px-5 pt-4">
|
|
14
|
+
<Text variant="display" className="text-primary">
|
|
15
|
+
Search
|
|
16
|
+
</Text>
|
|
17
|
+
<Text className="text-muted-foreground mt-2">
|
|
18
|
+
Build this screen to search for plants
|
|
19
|
+
</Text>
|
|
20
|
+
</View>
|
|
21
|
+
</Screen>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
|
2
|
+
import { Stack } from "expo-router";
|
|
3
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
4
|
+
import { KeyboardProvider } from "react-native-keyboard-controller";
|
|
5
|
+
import "react-native-reanimated";
|
|
6
|
+
import { Toaster } from "sonner-native";
|
|
7
|
+
import "../../global.css";
|
|
8
|
+
import { StyleSheet } from "react-native";
|
|
9
|
+
|
|
10
|
+
export default function RootLayout() {
|
|
11
|
+
// TODO: Import useAuth from ~/lib/stores/auth
|
|
12
|
+
// TODO: Get isLoggedIn from the auth store
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<GestureHandlerRootView style={styles.container}>
|
|
16
|
+
<KeyboardProvider>
|
|
17
|
+
<BottomSheetModalProvider>
|
|
18
|
+
{/*
|
|
19
|
+
TODO: Implement Protected Routes
|
|
20
|
+
|
|
21
|
+
Use Stack.Protected to show different screens based on auth state:
|
|
22
|
+
|
|
23
|
+
<Stack.Protected guard={!isLoggedIn}>
|
|
24
|
+
<Stack.Screen name="(auth)" />
|
|
25
|
+
</Stack.Protected>
|
|
26
|
+
|
|
27
|
+
<Stack.Protected guard={isLoggedIn}>
|
|
28
|
+
<Stack.Screen name="(tabs)" />
|
|
29
|
+
<Stack.Screen name="plant/[id]" />
|
|
30
|
+
</Stack.Protected>
|
|
31
|
+
*/}
|
|
32
|
+
<Stack screenOptions={{ headerShown: false }}>
|
|
33
|
+
<Stack.Screen name="(auth)" />
|
|
34
|
+
<Stack.Screen name="(tabs)" />
|
|
35
|
+
<Stack.Screen name="plant/[id]" />
|
|
36
|
+
</Stack>
|
|
37
|
+
<Toaster />
|
|
38
|
+
</BottomSheetModalProvider>
|
|
39
|
+
</KeyboardProvider>
|
|
40
|
+
</GestureHandlerRootView>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const styles = StyleSheet.create({
|
|
45
|
+
container: {
|
|
46
|
+
flex: 1,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import { Stack, useLocalSearchParams } from "expo-router";
|
|
3
|
+
import { Screen } from "~/components/ui/screen";
|
|
4
|
+
import Text from "~/components/ui/text";
|
|
5
|
+
import { customPlants } from "~/lib/constants";
|
|
6
|
+
|
|
7
|
+
export default function PlantDetails() {
|
|
8
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
9
|
+
|
|
10
|
+
const plant = customPlants.find((p) => p.id === id);
|
|
11
|
+
|
|
12
|
+
if (!plant) {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<Stack.Screen options={{ headerShown: false }} />
|
|
16
|
+
<Screen className="flex-1 items-center justify-center bg-background">
|
|
17
|
+
<Text>Plant not found</Text>
|
|
18
|
+
</Screen>
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// TODO: Implement the Plant Details screen
|
|
24
|
+
// - Add back button navigation
|
|
25
|
+
// - Display plant image in a stacked card design
|
|
26
|
+
// - Show plant name and scientific name
|
|
27
|
+
// - Add quick info pills (water needs, light needs)
|
|
28
|
+
// - Display "About this plant" card with description
|
|
29
|
+
// - Show care details (water frequency, growth rate, maintenance)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<Stack.Screen options={{ headerShown: false }} />
|
|
34
|
+
<Screen className="flex-1 bg-background">
|
|
35
|
+
<View className="px-5 pt-4">
|
|
36
|
+
<Text variant="display">{plant.name}</Text>
|
|
37
|
+
<Text className="text-muted-foreground mt-1">
|
|
38
|
+
{plant.scientificName}
|
|
39
|
+
</Text>
|
|
40
|
+
<Text className="text-muted-foreground mt-4">
|
|
41
|
+
Build this screen to show plant details
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
</Screen>
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|