@presencenet/create-pnet-stack 0.2.3 → 0.4.0

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.
Files changed (56) hide show
  1. package/bin/create-pnet-stack.js +79 -8
  2. package/package.json +1 -1
  3. package/templates/electron/apps/app/components.json +23 -0
  4. package/templates/electron/apps/app/package.json +7 -0
  5. package/templates/electron/apps/app/src/preload/index.ts +3 -1
  6. package/templates/electron/apps/app/src/renderer/index.html +1 -1
  7. package/templates/electron/apps/app/src/renderer/src/components/ui/button.tsx +63 -0
  8. package/templates/electron/apps/app/src/renderer/src/components/ui/card.tsx +91 -0
  9. package/templates/electron/apps/app/src/renderer/src/lib/utils.ts +1 -0
  10. package/templates/electron/apps/app/src/renderer/src/main.tsx +31 -8
  11. package/templates/electron/apps/app/src/renderer/src/style.css +120 -4
  12. package/templates/electron/apps/app/tsconfig.json +16 -0
  13. package/templates/electron/biome.json +26 -3
  14. package/templates/electron/gitignore +1 -0
  15. package/templates/electron/package.json +0 -1
  16. package/templates/mobile/apps/app/app/_layout.tsx +10 -9
  17. package/templates/mobile/apps/app/app/index.tsx +37 -11
  18. package/templates/mobile/apps/app/app.json +4 -1
  19. package/templates/mobile/apps/app/components/ui/button.tsx +123 -0
  20. package/templates/mobile/apps/app/components/ui/card.tsx +85 -0
  21. package/templates/mobile/apps/app/components/ui/text.tsx +95 -0
  22. package/templates/mobile/apps/app/components.json +19 -0
  23. package/templates/mobile/apps/app/css.d.ts +1 -0
  24. package/templates/mobile/apps/app/global.css +55 -0
  25. package/templates/mobile/apps/app/lib/theme.ts +85 -0
  26. package/templates/mobile/apps/app/lib/utils.ts +6 -0
  27. package/templates/mobile/apps/app/metro.config.js +1 -0
  28. package/templates/mobile/apps/app/package.json +11 -2
  29. package/templates/mobile/apps/app/tailwind.config.js +69 -3
  30. package/templates/mobile/biome.json +26 -3
  31. package/templates/mobile/package.json +0 -1
  32. package/templates/tauri/apps/app/components.json +23 -0
  33. package/templates/tauri/apps/app/index.html +1 -1
  34. package/templates/tauri/apps/app/package.json +8 -1
  35. package/templates/tauri/apps/app/src/components/ui/button.tsx +63 -0
  36. package/templates/tauri/apps/app/src/components/ui/card.tsx +91 -0
  37. package/templates/tauri/apps/app/src/lib/utils.ts +1 -0
  38. package/templates/tauri/apps/app/src/main.tsx +31 -8
  39. package/templates/tauri/apps/app/src/style.css +120 -4
  40. package/templates/tauri/apps/app/src-tauri/tauri.conf.json +7 -1
  41. package/templates/tauri/apps/app/tsconfig.json +6 -2
  42. package/templates/tauri/apps/app/vite.config.ts +4 -0
  43. package/templates/tauri/biome.json +26 -3
  44. package/templates/tauri/package.json +0 -1
  45. package/templates/web/apps/app/components.json +23 -0
  46. package/templates/web/apps/app/package.json +7 -0
  47. package/templates/web/apps/app/src/components/ui/button.tsx +63 -0
  48. package/templates/web/apps/app/src/components/ui/card.tsx +91 -0
  49. package/templates/web/apps/app/src/lib/utils.ts +1 -0
  50. package/templates/web/apps/app/src/routes/__root.tsx +7 -3
  51. package/templates/web/apps/app/src/routes/index.tsx +31 -8
  52. package/templates/web/apps/app/src/styles.css +123 -0
  53. package/templates/web/apps/app/tsconfig.json +4 -1
  54. package/templates/web/apps/app/vite.config.ts +4 -0
  55. package/templates/web/biome.json +29 -3
  56. package/templates/web/package.json +0 -1
@@ -1,17 +1,43 @@
1
- import { Text, View } from "react-native";
1
+ import { Linking, View } from "react-native";
2
+ import { Button } from "@/components/ui/button";
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardFooter,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@/components/ui/card";
11
+ import { Text } from "@/components/ui/text";
12
+
13
+ const app = {
14
+ name: "{{projectName}}",
15
+ };
2
16
 
3
17
  export default function Home() {
4
18
  return (
5
- <View className="flex-1 items-center justify-center bg-slate-950 px-8">
6
- <Text className="text-sm font-bold uppercase tracking-widest text-cyan-300">
7
- Presence-Net starter
8
- </Text>
9
- <Text className="mt-3 text-4xl font-bold text-white">
10
- {"{{projectName}}"}
11
- </Text>
12
- <Text className="mt-4 text-center text-lg text-slate-300">
13
- React Native, NativeWind, and a Bun-powered Turborepo workspace.
14
- </Text>
19
+ <View className="flex-1 items-center justify-center bg-background p-6">
20
+ <Card className="w-full max-w-xl">
21
+ <CardHeader>
22
+ <CardDescription>Presence-Net starter</CardDescription>
23
+ <CardTitle className="text-4xl">{app.name}</CardTitle>
24
+ </CardHeader>
25
+ <CardContent>
26
+ <Text className="text-muted-foreground">
27
+ React Native, React Native Reusables (shadcn/ui), and a Bun-powered
28
+ Turborepo workspace.
29
+ </Text>
30
+ </CardContent>
31
+ <CardFooter>
32
+ <Button
33
+ onPress={() =>
34
+ Linking.openURL("https://reactnativereusables.com/docs")
35
+ }
36
+ >
37
+ <Text>Browse components</Text>
38
+ </Button>
39
+ </CardFooter>
40
+ </Card>
15
41
  </View>
16
42
  );
17
43
  }
@@ -3,9 +3,12 @@
3
3
  "name": "{{projectName}}",
4
4
  "slug": "{{projectName}}",
5
5
  "scheme": "{{projectName}}",
6
+ "userInterfaceStyle": "automatic",
6
7
  "plugins": ["expo-router"],
7
8
  "experiments": { "typedRoutes": true },
8
9
  "ios": { "supportsTablet": true },
9
- "android": { "package": "net.presence.{{projectNameRust}}" }
10
+ "android": {
11
+ "package": "net.presence.{{projectNameRust}}"
12
+ }
10
13
  }
11
14
  }
@@ -0,0 +1,123 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import { Platform, Pressable } from "react-native";
3
+ import { TextClassContext } from "@/components/ui/text";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ const buttonVariants = cva(
7
+ cn(
8
+ "group shrink-0 flex-row items-center justify-center gap-2 rounded-md shadow-none",
9
+ Platform.select({
10
+ web: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
11
+ }),
12
+ ),
13
+ {
14
+ variants: {
15
+ variant: {
16
+ default: cn(
17
+ "bg-primary active:bg-primary/90 shadow-sm shadow-black/5",
18
+ Platform.select({ web: "hover:bg-primary/90" }),
19
+ ),
20
+ destructive: cn(
21
+ "bg-destructive active:bg-destructive/90 dark:bg-destructive/60 shadow-sm shadow-black/5",
22
+ Platform.select({
23
+ web: "hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
24
+ }),
25
+ ),
26
+ outline: cn(
27
+ "border-border bg-background active:bg-accent dark:bg-input/30 dark:border-input dark:active:bg-input/50 border shadow-sm shadow-black/5",
28
+ Platform.select({
29
+ web: "hover:bg-accent dark:hover:bg-input/50",
30
+ }),
31
+ ),
32
+ secondary: cn(
33
+ "bg-secondary active:bg-secondary/80 shadow-sm shadow-black/5",
34
+ Platform.select({ web: "hover:bg-secondary/80" }),
35
+ ),
36
+ ghost: cn(
37
+ "active:bg-accent dark:active:bg-accent/50",
38
+ Platform.select({ web: "hover:bg-accent dark:hover:bg-accent/50" }),
39
+ ),
40
+ link: "",
41
+ },
42
+ size: {
43
+ default: cn(
44
+ "h-10 px-4 py-2 sm:h-9",
45
+ Platform.select({ web: "has-[>svg]:px-3" }),
46
+ ),
47
+ sm: cn(
48
+ "h-9 gap-1.5 rounded-md px-3 sm:h-8",
49
+ Platform.select({ web: "has-[>svg]:px-2.5" }),
50
+ ),
51
+ lg: cn(
52
+ "h-11 rounded-md px-6 sm:h-10",
53
+ Platform.select({ web: "has-[>svg]:px-4" }),
54
+ ),
55
+ icon: "h-10 w-10 sm:h-9 sm:w-9",
56
+ },
57
+ },
58
+ defaultVariants: {
59
+ variant: "default",
60
+ size: "default",
61
+ },
62
+ },
63
+ );
64
+
65
+ const buttonTextVariants = cva(
66
+ cn(
67
+ "text-foreground text-sm font-medium",
68
+ Platform.select({ web: "pointer-events-none transition-colors" }),
69
+ ),
70
+ {
71
+ variants: {
72
+ variant: {
73
+ default: "text-primary-foreground",
74
+ destructive: "text-white",
75
+ outline: cn(
76
+ "group-active:text-accent-foreground",
77
+ Platform.select({ web: "group-hover:text-accent-foreground" }),
78
+ ),
79
+ secondary: "text-secondary-foreground",
80
+ ghost: "group-active:text-accent-foreground",
81
+ link: cn(
82
+ "text-primary group-active:underline",
83
+ Platform.select({
84
+ web: "underline-offset-4 hover:underline group-hover:underline",
85
+ }),
86
+ ),
87
+ },
88
+ size: {
89
+ default: "",
90
+ sm: "",
91
+ lg: "",
92
+ icon: "",
93
+ },
94
+ },
95
+ defaultVariants: {
96
+ variant: "default",
97
+ size: "default",
98
+ },
99
+ },
100
+ );
101
+
102
+ type ButtonProps = React.ComponentProps<typeof Pressable> &
103
+ React.RefAttributes<typeof Pressable> &
104
+ VariantProps<typeof buttonVariants>;
105
+
106
+ function Button({ className, variant, size, ...props }: ButtonProps) {
107
+ return (
108
+ <TextClassContext.Provider value={buttonTextVariants({ variant, size })}>
109
+ <Pressable
110
+ className={cn(
111
+ props.disabled && "opacity-50",
112
+ buttonVariants({ variant, size }),
113
+ className,
114
+ )}
115
+ role="button"
116
+ {...props}
117
+ />
118
+ </TextClassContext.Provider>
119
+ );
120
+ }
121
+
122
+ export type { ButtonProps };
123
+ export { Button, buttonTextVariants, buttonVariants };
@@ -0,0 +1,85 @@
1
+ import { View } from "react-native";
2
+ import { Text, TextClassContext } from "@/components/ui/text";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ function Card({
6
+ className,
7
+ ...props
8
+ }: React.ComponentProps<typeof View> & React.RefAttributes<View>) {
9
+ return (
10
+ <TextClassContext.Provider value="text-card-foreground">
11
+ <View
12
+ className={cn(
13
+ "bg-card border-border flex flex-col gap-6 rounded-xl border py-6 shadow-sm shadow-black/5",
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ </TextClassContext.Provider>
19
+ );
20
+ }
21
+
22
+ function CardHeader({
23
+ className,
24
+ ...props
25
+ }: React.ComponentProps<typeof View> & React.RefAttributes<View>) {
26
+ return (
27
+ <View className={cn("flex flex-col gap-1.5 px-6", className)} {...props} />
28
+ );
29
+ }
30
+
31
+ function CardTitle({
32
+ className,
33
+ ref,
34
+ ...props
35
+ }: React.ComponentProps<typeof Text> & React.RefAttributes<typeof Text>) {
36
+ return (
37
+ <Text
38
+ ref={ref}
39
+ role="heading"
40
+ aria-level={3}
41
+ className={cn("font-semibold leading-none", className)}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function CardDescription({
48
+ className,
49
+ ...props
50
+ }: React.ComponentProps<typeof Text> & React.RefAttributes<typeof Text>) {
51
+ return (
52
+ <Text
53
+ className={cn("text-muted-foreground text-sm", className)}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+
59
+ function CardContent({
60
+ className,
61
+ ...props
62
+ }: React.ComponentProps<typeof View> & React.RefAttributes<View>) {
63
+ return <View className={cn("px-6", className)} {...props} />;
64
+ }
65
+
66
+ function CardFooter({
67
+ className,
68
+ ...props
69
+ }: React.ComponentProps<typeof View> & React.RefAttributes<View>) {
70
+ return (
71
+ <View
72
+ className={cn("flex flex-row items-center px-6", className)}
73
+ {...props}
74
+ />
75
+ );
76
+ }
77
+
78
+ export {
79
+ Card,
80
+ CardContent,
81
+ CardDescription,
82
+ CardFooter,
83
+ CardHeader,
84
+ CardTitle,
85
+ };
@@ -0,0 +1,95 @@
1
+ import { Slot } from "@rn-primitives/slot";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import * as React from "react";
4
+ import { Platform, Text as RNText, type Role } from "react-native";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const textVariants = cva(
8
+ cn(
9
+ "text-foreground text-base",
10
+ Platform.select({
11
+ web: "select-text",
12
+ }),
13
+ ),
14
+ {
15
+ variants: {
16
+ variant: {
17
+ default: "",
18
+ h1: cn(
19
+ "text-center text-4xl font-extrabold tracking-tight",
20
+ Platform.select({ web: "scroll-m-20 text-balance" }),
21
+ ),
22
+ h2: cn(
23
+ "border-border border-b pb-2 text-3xl font-semibold tracking-tight",
24
+ Platform.select({ web: "scroll-m-20 first:mt-0" }),
25
+ ),
26
+ h3: cn(
27
+ "text-2xl font-semibold tracking-tight",
28
+ Platform.select({ web: "scroll-m-20" }),
29
+ ),
30
+ h4: cn(
31
+ "text-xl font-semibold tracking-tight",
32
+ Platform.select({ web: "scroll-m-20" }),
33
+ ),
34
+ p: "mt-3 leading-7 sm:mt-6",
35
+ blockquote: "mt-4 border-l-2 pl-3 italic sm:mt-6 sm:pl-6",
36
+ code: cn(
37
+ "bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold",
38
+ ),
39
+ lead: "text-muted-foreground text-xl",
40
+ large: "text-lg font-semibold",
41
+ small: "text-sm font-medium leading-none",
42
+ muted: "text-muted-foreground text-sm",
43
+ },
44
+ },
45
+ defaultVariants: {
46
+ variant: "default",
47
+ },
48
+ },
49
+ );
50
+
51
+ type TextVariantProps = VariantProps<typeof textVariants>;
52
+
53
+ type TextVariant = NonNullable<TextVariantProps["variant"]>;
54
+
55
+ const ROLE: Partial<Record<TextVariant, Role>> = {
56
+ h1: "heading",
57
+ h2: "heading",
58
+ h3: "heading",
59
+ h4: "heading",
60
+ blockquote: Platform.select({ web: "blockquote" as Role }),
61
+ code: Platform.select({ web: "code" as Role }),
62
+ };
63
+
64
+ const ARIA_LEVEL: Partial<Record<TextVariant, string>> = {
65
+ h1: "1",
66
+ h2: "2",
67
+ h3: "3",
68
+ h4: "4",
69
+ };
70
+
71
+ const TextClassContext = React.createContext<string | undefined>(undefined);
72
+
73
+ function Text({
74
+ className,
75
+ asChild = false,
76
+ variant = "default",
77
+ ...props
78
+ }: React.ComponentProps<typeof RNText> &
79
+ React.RefAttributes<typeof RNText> &
80
+ TextVariantProps & {
81
+ asChild?: boolean;
82
+ }) {
83
+ const textClass = React.useContext(TextClassContext);
84
+ const Component = asChild ? Slot : RNText;
85
+ return (
86
+ <Component
87
+ className={cn(textVariants({ variant }), textClass, className)}
88
+ role={variant ? ROLE[variant] : undefined}
89
+ aria-level={variant ? ARIA_LEVEL[variant] : undefined}
90
+ {...props}
91
+ />
92
+ );
93
+ }
94
+
95
+ export { Text, TextClassContext };
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.js",
8
+ "css": "global.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true
11
+ },
12
+ "aliases": {
13
+ "components": "@/components",
14
+ "utils": "@/lib/utils",
15
+ "ui": "@/components/ui",
16
+ "lib": "@/lib",
17
+ "hooks": "@/hooks"
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ declare module "*.css";
@@ -1,3 +1,58 @@
1
1
  @tailwind base;
2
2
  @tailwind components;
3
3
  @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 0 0% 3.9%;
9
+ --card: 0 0% 100%;
10
+ --card-foreground: 0 0% 3.9%;
11
+ --popover: 0 0% 100%;
12
+ --popover-foreground: 0 0% 3.9%;
13
+ --primary: 0 0% 9%;
14
+ --primary-foreground: 0 0% 98%;
15
+ --secondary: 0 0% 96.1%;
16
+ --secondary-foreground: 0 0% 9%;
17
+ --muted: 0 0% 96.1%;
18
+ --muted-foreground: 0 0% 45.1%;
19
+ --accent: 0 0% 96.1%;
20
+ --accent-foreground: 0 0% 9%;
21
+ --destructive: 0 84.2% 60.2%;
22
+ --border: 0 0% 89.8%;
23
+ --input: 0 0% 89.8%;
24
+ --ring: 0 0% 63%;
25
+ --radius: 0.625rem;
26
+ --chart-1: 12 76% 61%;
27
+ --chart-2: 173 58% 39%;
28
+ --chart-3: 197 37% 24%;
29
+ --chart-4: 43 74% 66%;
30
+ --chart-5: 27 87% 67%;
31
+ }
32
+
33
+ .dark:root {
34
+ --background: 0 0% 3.9%;
35
+ --foreground: 0 0% 98%;
36
+ --card: 0 0% 3.9%;
37
+ --card-foreground: 0 0% 98%;
38
+ --popover: 0 0% 3.9%;
39
+ --popover-foreground: 0 0% 98%;
40
+ --primary: 0 0% 98%;
41
+ --primary-foreground: 0 0% 9%;
42
+ --secondary: 0 0% 14.9%;
43
+ --secondary-foreground: 0 0% 98%;
44
+ --muted: 0 0% 14.9%;
45
+ --muted-foreground: 0 0% 63.9%;
46
+ --accent: 0 0% 14.9%;
47
+ --accent-foreground: 0 0% 98%;
48
+ --destructive: 0 70.9% 59.4%;
49
+ --border: 0 0% 14.9%;
50
+ --input: 0 0% 14.9%;
51
+ --ring: 300 0% 45%;
52
+ --chart-1: 220 70% 50%;
53
+ --chart-2: 160 60% 45%;
54
+ --chart-3: 30 80% 55%;
55
+ --chart-4: 280 65% 60%;
56
+ --chart-5: 340 75% 55%;
57
+ }
58
+ }
@@ -0,0 +1,85 @@
1
+ import {
2
+ DarkTheme,
3
+ DefaultTheme,
4
+ type Theme,
5
+ } from "expo-router/react-navigation";
6
+
7
+ export const THEME = {
8
+ light: {
9
+ background: "hsl(0 0% 100%)",
10
+ foreground: "hsl(0 0% 3.9%)",
11
+ card: "hsl(0 0% 100%)",
12
+ cardForeground: "hsl(0 0% 3.9%)",
13
+ popover: "hsl(0 0% 100%)",
14
+ popoverForeground: "hsl(0 0% 3.9%)",
15
+ primary: "hsl(0 0% 9%)",
16
+ primaryForeground: "hsl(0 0% 98%)",
17
+ secondary: "hsl(0 0% 96.1%)",
18
+ secondaryForeground: "hsl(0 0% 9%)",
19
+ muted: "hsl(0 0% 96.1%)",
20
+ mutedForeground: "hsl(0 0% 45.1%)",
21
+ accent: "hsl(0 0% 96.1%)",
22
+ accentForeground: "hsl(0 0% 9%)",
23
+ destructive: "hsl(0 84.2% 60.2%)",
24
+ border: "hsl(0 0% 89.8%)",
25
+ input: "hsl(0 0% 89.8%)",
26
+ ring: "hsl(0 0% 63%)",
27
+ radius: "0.625rem",
28
+ chart1: "hsl(12 76% 61%)",
29
+ chart2: "hsl(173 58% 39%)",
30
+ chart3: "hsl(197 37% 24%)",
31
+ chart4: "hsl(43 74% 66%)",
32
+ chart5: "hsl(27 87% 67%)",
33
+ },
34
+ dark: {
35
+ background: "hsl(0 0% 3.9%)",
36
+ foreground: "hsl(0 0% 98%)",
37
+ card: "hsl(0 0% 3.9%)",
38
+ cardForeground: "hsl(0 0% 98%)",
39
+ popover: "hsl(0 0% 3.9%)",
40
+ popoverForeground: "hsl(0 0% 98%)",
41
+ primary: "hsl(0 0% 98%)",
42
+ primaryForeground: "hsl(0 0% 9%)",
43
+ secondary: "hsl(0 0% 14.9%)",
44
+ secondaryForeground: "hsl(0 0% 98%)",
45
+ muted: "hsl(0 0% 14.9%)",
46
+ mutedForeground: "hsl(0 0% 63.9%)",
47
+ accent: "hsl(0 0% 14.9%)",
48
+ accentForeground: "hsl(0 0% 98%)",
49
+ destructive: "hsl(0 70.9% 59.4%)",
50
+ border: "hsl(0 0% 14.9%)",
51
+ input: "hsl(0 0% 14.9%)",
52
+ ring: "hsl(300 0% 45%)",
53
+ radius: "0.625rem",
54
+ chart1: "hsl(220 70% 50%)",
55
+ chart2: "hsl(160 60% 45%)",
56
+ chart3: "hsl(30 80% 55%)",
57
+ chart4: "hsl(280 65% 60%)",
58
+ chart5: "hsl(340 75% 55%)",
59
+ },
60
+ };
61
+
62
+ export const NAV_THEME: Record<"light" | "dark", Theme> = {
63
+ light: {
64
+ ...DefaultTheme,
65
+ colors: {
66
+ background: THEME.light.background,
67
+ border: THEME.light.border,
68
+ card: THEME.light.card,
69
+ notification: THEME.light.destructive,
70
+ primary: THEME.light.primary,
71
+ text: THEME.light.foreground,
72
+ },
73
+ },
74
+ dark: {
75
+ ...DarkTheme,
76
+ colors: {
77
+ background: THEME.dark.background,
78
+ border: THEME.dark.border,
79
+ card: THEME.dark.card,
80
+ notification: THEME.dark.destructive,
81
+ primary: THEME.dark.primary,
82
+ text: THEME.dark.foreground,
83
+ },
84
+ },
85
+ };
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -3,4 +3,5 @@ const { withNativeWind } = require("nativewind/metro");
3
3
 
4
4
  module.exports = withNativeWind(getDefaultConfig(__dirname), {
5
5
  input: "./global.css",
6
+ inlineRem: 16,
6
7
  });
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@{{projectName}}/app",
3
+ "version": "0.0.0",
3
4
  "private": true,
4
5
  "main": "expo-router/entry",
5
6
  "scripts": {
@@ -8,6 +9,10 @@
8
9
  "check": "biome check ."
9
10
  },
10
11
  "dependencies": {
12
+ "@rn-primitives/portal": "^1.5.3",
13
+ "@rn-primitives/slot": "^1.5.2",
14
+ "class-variance-authority": "^0.7.1",
15
+ "clsx": "^2.1.1",
11
16
  "expo": "~58.0.23",
12
17
  "expo-constants": "~58.0.15",
13
18
  "expo-linking": "~58.0.16",
@@ -17,14 +22,18 @@
17
22
  "nativewind": "^4.2.7",
18
23
  "react": "19.3.0",
19
24
  "react-native": "0.88.1",
20
- "react-native-reanimated": "4.7.1",
25
+ "react-native-css-interop": "^0.2.7",
21
26
  "react-native-gesture-handler": "~3.3.0",
27
+ "react-native-reanimated": "4.7.1",
22
28
  "react-native-safe-area-context": "~5.11.1",
23
29
  "react-native-screens": "~4.30.1",
24
- "react-native-worklets": "0.13.0"
30
+ "react-native-worklets": "0.13.0",
31
+ "tailwind-merge": "^3.7.0",
32
+ "tailwindcss-animate": "^1.0.7"
25
33
  },
26
34
  "devDependencies": {
27
35
  "@babel/core": "^7.29.7",
36
+ "@babel/plugin-transform-react-jsx": "^7.29.7",
28
37
  "@types/react": "~19.3.0",
29
38
  "babel-preset-expo": "~58.0.0",
30
39
  "tailwindcss": "^3.4.17",
@@ -1,7 +1,73 @@
1
+ const { hairlineWidth } = require("nativewind/theme");
2
+
1
3
  /** @type {import('tailwindcss').Config} */
2
4
  module.exports = {
3
- content: ["./app/**/*.{js,jsx,ts,tsx}"],
5
+ darkMode: "class",
6
+ content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
4
7
  presets: [require("nativewind/preset")],
5
- theme: { extend: {} },
6
- plugins: [],
8
+ theme: {
9
+ extend: {
10
+ colors: {
11
+ border: "hsl(var(--border))",
12
+ input: "hsl(var(--input))",
13
+ ring: "hsl(var(--ring))",
14
+ background: "hsl(var(--background))",
15
+ foreground: "hsl(var(--foreground))",
16
+ primary: {
17
+ DEFAULT: "hsl(var(--primary))",
18
+ foreground: "hsl(var(--primary-foreground))",
19
+ },
20
+ secondary: {
21
+ DEFAULT: "hsl(var(--secondary))",
22
+ foreground: "hsl(var(--secondary-foreground))",
23
+ },
24
+ destructive: {
25
+ DEFAULT: "hsl(var(--destructive))",
26
+ foreground: "hsl(var(--destructive-foreground))",
27
+ },
28
+ muted: {
29
+ DEFAULT: "hsl(var(--muted))",
30
+ foreground: "hsl(var(--muted-foreground))",
31
+ },
32
+ accent: {
33
+ DEFAULT: "hsl(var(--accent))",
34
+ foreground: "hsl(var(--accent-foreground))",
35
+ },
36
+ popover: {
37
+ DEFAULT: "hsl(var(--popover))",
38
+ foreground: "hsl(var(--popover-foreground))",
39
+ },
40
+ card: {
41
+ DEFAULT: "hsl(var(--card))",
42
+ foreground: "hsl(var(--card-foreground))",
43
+ },
44
+ },
45
+ borderRadius: {
46
+ lg: "var(--radius)",
47
+ md: "calc(var(--radius) - 2px)",
48
+ sm: "calc(var(--radius) - 4px)",
49
+ },
50
+ borderWidth: {
51
+ hairline: hairlineWidth(),
52
+ },
53
+ keyframes: {
54
+ "accordion-down": {
55
+ from: { height: "0" },
56
+ to: { height: "var(--radix-accordion-content-height)" },
57
+ },
58
+ "accordion-up": {
59
+ from: { height: "var(--radix-accordion-content-height)" },
60
+ to: { height: "0" },
61
+ },
62
+ },
63
+ animation: {
64
+ "accordion-down": "accordion-down 0.2s ease-out",
65
+ "accordion-up": "accordion-up 0.2s ease-out",
66
+ },
67
+ },
68
+ },
69
+ future: {
70
+ hoverOnlyWhenSupported: true,
71
+ },
72
+ plugins: [require("tailwindcss-animate")],
7
73
  };