newcandies 0.1.26 → 0.1.28

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newcandies",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Scaffold Expo Router + Uniwind React Native apps with layered templates.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,32 @@
1
+ import { Ionicons } from '@expo/vector-icons';
2
+ import { Link, Stack } from 'expo-router';
3
+ import { Pressable, Text, View } from 'react-native';
4
+ import Screen from '~/components/ui/screen';
5
+ import Squircle from '~/components/ui/squircle';
6
+
7
+
8
+
9
+ export default function NotFoundScreen() {
10
+ return (
11
+ <Screen>
12
+ <Stack.Screen options={{ title: 'Not Found', headerShown: false }} />
13
+ <View className="flex-1 items-center justify-center px-8">
14
+ <Ionicons name="alert-circle-outline" size={80} color="black" />
15
+ <Text className="mt-6 text-2xl font-bold text-foreground">Page Not Found</Text>
16
+ <Text className="mt-2 text-center text-muted-foreground">
17
+ {"The page you're looking for doesn't exist."}
18
+ </Text>
19
+ <Link href="/" asChild>
20
+ <Pressable className="mt-8">
21
+ <Squircle
22
+ cornerSmoothing={1}
23
+ className="bg-primary px-6 py-3"
24
+ style={{ borderRadius: 14 }}>
25
+ <Text className="font-semibold text-primary-foreground">Go to Home</Text>
26
+ </Squircle>
27
+ </Pressable>
28
+ </Link>
29
+ </View>
30
+ </Screen>
31
+ );
32
+ }
@@ -1,18 +1,23 @@
1
1
  import { Ionicons } from '@expo/vector-icons';
2
2
  import { Link } from 'expo-router';
3
3
  import { Pressable, View } from 'react-native';
4
+ import { twMerge } from 'tailwind-merge';
4
5
 
5
6
  import Squircle from '~/components/ui/squircle';
6
7
  import Text from '~/components/ui/text';
7
- import { Note } from '~/lib/constants';
8
8
 
9
- // Rotation patterns for variety
9
+
10
+ /**
11
+ * Get the rotation for the note card
12
+ */
10
13
  const getRotation = (index: number) => {
11
14
  const rotations = [-4, 3, -2, 5, -3, 2, -5, 4];
12
15
  return rotations[index % rotations.length];
13
- };
16
+ };
14
17
 
15
- // Horizontal offset for staggered look (relative to center)
18
+ /**
19
+ * Get the offset for the note card
20
+ */
16
21
  const getOffset = (index: number) => {
17
22
  const offsets = [-50, 60, -40, 70, -55, 50, -35, 65];
18
23
  return offsets[index % offsets.length];
@@ -25,33 +30,23 @@ const NoteCard = ({ note, index }: { note: Note; index: number }) => {
25
30
  return (
26
31
  <Link href={{ pathname: '/note/[id]', params: { id: note.id } }} asChild>
27
32
  <Pressable
33
+ className={twMerge('-mb-[60px] self-center')}
28
34
  style={{
29
- marginBottom: -60,
30
- alignSelf: 'center',
31
35
  marginLeft: offsetX,
32
36
  transform: [{ rotate: `${rotation}deg` }],
33
37
  zIndex: index,
34
38
  }}>
35
39
  <Squircle
36
40
  cornerSmoothing={1}
37
- className="bg-card"
38
- style={{
39
- width: 240,
40
- height: 324,
41
- borderRadius: 24,
42
- padding: 20,
43
- }}>
44
- {/* Menu dots */}
45
- <View style={{ position: 'absolute', top: 16, right: 16 }}>
46
- <Ionicons name="ellipsis-horizontal" size={18} color="var(--color-muted-foreground)" />
41
+ className="h-80 w-60 rounded-3xl bg-card p-5">
42
+ <View className="absolute right-4 top-4">
43
+ <Ionicons name="ellipsis-horizontal" size={18} color="black" />
47
44
  </View>
48
45
 
49
- {/* Title */}
50
46
  <Text variant="subtitle" className="mb-2 mr-10" numberOfLines={2}>
51
47
  {note.title}
52
48
  </Text>
53
49
 
54
- {/* Content */}
55
50
  <Text variant="note" className="opacity-90" numberOfLines={10}>
56
51
  {note.content}
57
52
  </Text>
@@ -13,8 +13,8 @@ const BackButton = ({ icon = 'chevron-back' }: BackButtonProps) => {
13
13
  <Pressable onPress={() => router.back()}>
14
14
  <Squircle
15
15
  cornerSmoothing={1}
16
- className="size-12 items-center justify-center bg-card rounded-[14px]">
17
- <Ionicons name={icon} size={26} color="var(--color-foreground)" />
16
+ className="size-12 items-center justify-center bg-card rounded-xl">
17
+ <Ionicons name={icon} size={26} color="black" />
18
18
  </Squircle>
19
19
  </Pressable>
20
20
  );
@@ -13,9 +13,9 @@ export default function RootLayout() {
13
13
  <KeyboardProvider>
14
14
  <BottomSheetModalProvider>
15
15
  <Stack>
16
- <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
17
- {/* TODO: Add more stack screens like plant/[id] */}
18
- </Stack>
16
+ <Stack>
17
+ <Stack.Screen name="index" />
18
+ </Stack>
19
19
  <Toaster />
20
20
  </BottomSheetModalProvider>
21
21
  </KeyboardProvider>
@@ -0,0 +1,12 @@
1
+ import { Screen } from "~/components/ui/screen";
2
+ import Text from "~/components/ui/text";
3
+
4
+ const Home = () => {
5
+ return (
6
+ <Screen>
7
+ <Text>Home</Text>
8
+ </Screen>
9
+ );
10
+ };
11
+
12
+ export default Home;
@@ -1,71 +0,0 @@
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
-
@@ -1,24 +0,0 @@
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
-
@@ -1,102 +0,0 @@
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
-
@@ -1,25 +0,0 @@
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: Implement the Profile screen
7
- // - Display user avatar and name
8
- // - Show plant stats (plants owned, waterings)
9
- // - Add "Currently..." status card
10
- // - Include Edit Profile button
11
-
12
- return (
13
- <Screen>
14
- <View className="px-5 pt-4">
15
- <Text variant="display" className="text-primary">
16
- Profile
17
- </Text>
18
- <Text className="text-muted-foreground mt-2">
19
- Build this screen to show user profile
20
- </Text>
21
- </View>
22
- </Screen>
23
- );
24
- }
25
-
@@ -1,24 +0,0 @@
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
-
@@ -1,48 +0,0 @@
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
-