create-better-t-stack 3.9.0 → 3.11.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 (77) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.mjs +1 -1
  3. package/dist/index.d.mts +7 -3
  4. package/dist/index.mjs +1 -1
  5. package/dist/{src-DLvUK0Qf.mjs → src-XVvJUQ_h.mjs} +270 -93
  6. package/package.json +44 -44
  7. package/templates/auth/better-auth/convex/backend/convex/auth.config.ts.hbs +5 -7
  8. package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +17 -17
  9. package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +4 -4
  10. package/templates/auth/better-auth/convex/web/react/next/src/app/api/auth/[...all]/route.ts.hbs +2 -2
  11. package/templates/auth/better-auth/convex/web/react/next/src/components/user-menu.tsx.hbs +10 -10
  12. package/templates/auth/better-auth/convex/web/react/next/src/lib/auth-server.ts.hbs +13 -5
  13. package/templates/auth/better-auth/convex/web/react/tanstack-router/src/components/user-menu.tsx.hbs +14 -12
  14. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/components/user-menu.tsx.hbs +13 -16
  15. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs +11 -5
  16. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/routes/api/auth/$.ts.hbs +4 -4
  17. package/templates/auth/better-auth/fullstack/tanstack-start/src/routes/api/auth/$.ts.hbs +1 -1
  18. package/templates/auth/better-auth/web/react/next/src/components/user-menu.tsx.hbs +17 -15
  19. package/templates/auth/better-auth/web/react/react-router/src/components/user-menu.tsx.hbs +16 -15
  20. package/templates/auth/better-auth/web/react/tanstack-router/src/components/{user-menu.tsx → user-menu.tsx.hbs} +16 -15
  21. package/templates/auth/better-auth/web/react/tanstack-start/src/components/{user-menu.tsx → user-menu.tsx.hbs} +16 -15
  22. package/templates/backend/convex/packages/backend/convex/README.md +4 -4
  23. package/templates/backend/convex/packages/backend/convex/convex.config.ts.hbs +17 -0
  24. package/templates/backend/convex/packages/backend/convex/tsconfig.json.hbs +1 -1
  25. package/templates/examples/ai/convex/packages/backend/convex/agent.ts.hbs +9 -0
  26. package/templates/examples/ai/convex/packages/backend/convex/chat.ts.hbs +67 -0
  27. package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +301 -3
  28. package/templates/examples/ai/native/unistyles/app/(drawer)/ai.tsx.hbs +296 -10
  29. package/templates/examples/ai/native/uniwind/app/(drawer)/ai.tsx.hbs +180 -1
  30. package/templates/examples/ai/web/react/next/src/app/ai/page.tsx.hbs +172 -9
  31. package/templates/examples/ai/web/react/react-router/src/routes/ai.tsx.hbs +156 -6
  32. package/templates/examples/ai/web/react/tanstack-router/src/routes/ai.tsx.hbs +156 -4
  33. package/templates/examples/ai/web/react/tanstack-start/src/routes/ai.tsx.hbs +159 -6
  34. package/templates/frontend/react/next/package.json.hbs +8 -7
  35. package/templates/frontend/react/next/src/app/layout.tsx.hbs +28 -1
  36. package/templates/frontend/react/next/src/components/mode-toggle.tsx.hbs +4 -6
  37. package/templates/frontend/react/next/src/components/providers.tsx.hbs +14 -4
  38. package/templates/frontend/react/react-router/package.json.hbs +2 -1
  39. package/templates/frontend/react/{tanstack-router/src/components/mode-toggle.tsx → react-router/src/components/mode-toggle.tsx.hbs} +4 -6
  40. package/templates/frontend/react/tanstack-router/package.json.hbs +2 -1
  41. package/templates/frontend/react/{react-router/src/components/mode-toggle.tsx → tanstack-router/src/components/mode-toggle.tsx.hbs} +4 -6
  42. package/templates/frontend/react/tanstack-start/package.json.hbs +2 -1
  43. package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +6 -0
  44. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +13 -14
  45. package/templates/frontend/react/tanstack-start/vite.config.ts.hbs +5 -0
  46. package/templates/frontend/react/web-base/components.json +5 -2
  47. package/templates/frontend/react/web-base/src/components/ui/button.tsx.hbs +57 -0
  48. package/templates/frontend/react/web-base/src/components/ui/card.tsx.hbs +103 -0
  49. package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx.hbs +26 -0
  50. package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx.hbs +262 -0
  51. package/templates/frontend/react/web-base/src/components/ui/input.tsx.hbs +20 -0
  52. package/templates/frontend/react/web-base/src/components/ui/label.tsx.hbs +20 -0
  53. package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx.hbs +13 -0
  54. package/templates/frontend/react/web-base/src/components/ui/sonner.tsx.hbs +44 -0
  55. package/templates/frontend/react/web-base/src/index.css.hbs +58 -64
  56. package/templates/auth/better-auth/convex/backend/convex/convex.config.ts.hbs +0 -7
  57. package/templates/examples/ai/web/react/base/src/components/response.tsx.hbs +0 -22
  58. package/templates/frontend/react/web-base/src/components/ui/button.tsx +0 -56
  59. package/templates/frontend/react/web-base/src/components/ui/card.tsx +0 -75
  60. package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx +0 -27
  61. package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx +0 -228
  62. package/templates/frontend/react/web-base/src/components/ui/input.tsx +0 -21
  63. package/templates/frontend/react/web-base/src/components/ui/label.tsx +0 -19
  64. package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx +0 -13
  65. package/templates/frontend/react/web-base/src/components/ui/sonner.tsx +0 -25
  66. /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  67. /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  68. /package/templates/auth/better-auth/web/react/tanstack-router/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  69. /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  70. /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  71. /package/templates/auth/better-auth/web/react/tanstack-start/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  72. /package/templates/auth/better-auth/web/solid/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  73. /package/templates/auth/better-auth/web/solid/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  74. /package/templates/auth/better-auth/web/solid/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  75. /package/templates/frontend/react/react-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
  76. /package/templates/frontend/react/tanstack-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
  77. /package/templates/frontend/react/web-base/src/lib/{utils.ts → utils.ts.hbs} +0 -0
@@ -1,3 +1,297 @@
1
+ {{#if (eq backend "convex")}}
2
+ import { Ionicons } from "@expo/vector-icons";
3
+ import {
4
+ useUIMessages,
5
+ useSmoothText,
6
+ type UIMessage,
7
+ } from "@convex-dev/agent/react";
8
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
9
+ import { useMutation } from "convex/react";
10
+ import React, { useRef, useEffect, useState } from "react";
11
+ import {
12
+ View,
13
+ Text,
14
+ TextInput,
15
+ TouchableOpacity,
16
+ ScrollView,
17
+ KeyboardAvoidingView,
18
+ Platform,
19
+ ActivityIndicator,
20
+ } from "react-native";
21
+ import { StyleSheet, useUnistyles } from "react-native-unistyles";
22
+
23
+ import { Container } from "@/components/container";
24
+
25
+ function MessageContent({
26
+ text,
27
+ isStreaming,
28
+ style,
29
+ }: {
30
+ text: string;
31
+ isStreaming: boolean;
32
+ style: object;
33
+ }) {
34
+ const [visibleText] = useSmoothText(text, {
35
+ startStreaming: isStreaming,
36
+ });
37
+ return <Text style={style}>{visibleText}</Text>;
38
+ }
39
+
40
+ export default function AIScreen() {
41
+ const { theme } = useUnistyles();
42
+ const [input, setInput] = useState("");
43
+ const [threadId, setThreadId] = useState<string | null>(null);
44
+ const [isLoading, setIsLoading] = useState(false);
45
+ const scrollViewRef = useRef<ScrollView>(null);
46
+
47
+ const createThread = useMutation(api.chat.createNewThread);
48
+ const sendMessage = useMutation(api.chat.sendMessage);
49
+
50
+ const { results: messages } = useUIMessages(
51
+ api.chat.listMessages,
52
+ threadId ? { threadId } : "skip",
53
+ { initialNumItems: 50, stream: true },
54
+ );
55
+
56
+ const hasStreamingMessage = messages?.some(
57
+ (m: UIMessage) => m.status === "streaming",
58
+ );
59
+
60
+ useEffect(() => {
61
+ scrollViewRef.current?.scrollToEnd({ animated: true });
62
+ }, [messages]);
63
+
64
+ const onSubmit = async () => {
65
+ const value = input.trim();
66
+ if (!value || isLoading) return;
67
+
68
+ setIsLoading(true);
69
+ setInput("");
70
+
71
+ try {
72
+ let currentThreadId = threadId;
73
+ if (!currentThreadId) {
74
+ currentThreadId = await createThread();
75
+ setThreadId(currentThreadId);
76
+ }
77
+
78
+ await sendMessage({ threadId: currentThreadId, prompt: value });
79
+ } catch (error) {
80
+ console.error("Failed to send message:", error);
81
+ } finally {
82
+ setIsLoading(false);
83
+ }
84
+ };
85
+
86
+ return (
87
+ <Container>
88
+ <KeyboardAvoidingView
89
+ style={styles.container}
90
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
91
+ >
92
+ <View style={styles.content}>
93
+ <View style={styles.header}>
94
+ <Text style={styles.headerTitle}>AI Chat</Text>
95
+ <Text style={styles.headerSubtitle}>
96
+ Chat with our AI assistant
97
+ </Text>
98
+ </View>
99
+
100
+ <ScrollView
101
+ ref={scrollViewRef}
102
+ style={styles.messagesContainer}
103
+ showsVerticalScrollIndicator={false}
104
+ >
105
+ {!messages || messages.length === 0 ? (
106
+ <View style={styles.emptyContainer}>
107
+ <Text style={styles.emptyText}>
108
+ Ask me anything to get started!
109
+ </Text>
110
+ </View>
111
+ ) : (
112
+ <View style={styles.messagesWrapper}>
113
+ {messages.map((message: UIMessage) => (
114
+ <View
115
+ key={message.key}
116
+ style={[
117
+ styles.messageContainer,
118
+ message.role === "user"
119
+ ? styles.userMessage
120
+ : styles.assistantMessage,
121
+ ]}
122
+ >
123
+ <Text style={styles.messageRole}>
124
+ {message.role === "user" ? "You" : "AI Assistant"}
125
+ </Text>
126
+ <MessageContent
127
+ text={message.text ?? ""}
128
+ isStreaming={message.status === "streaming"}
129
+ style={styles.messageContent}
130
+ />
131
+ </View>
132
+ ))}
133
+ {isLoading && !hasStreamingMessage && (
134
+ <View style={[styles.messageContainer, styles.assistantMessage]}>
135
+ <Text style={styles.messageRole}>AI Assistant</Text>
136
+ <View style={styles.loadingContainer}>
137
+ <ActivityIndicator size="small" color={theme.colors.primary} />
138
+ <Text style={styles.loadingText}>Thinking...</Text>
139
+ </View>
140
+ </View>
141
+ )}
142
+ </View>
143
+ )}
144
+ </ScrollView>
145
+
146
+ <View style={styles.inputSection}>
147
+ <View style={styles.inputContainer}>
148
+ <TextInput
149
+ value={input}
150
+ onChangeText={setInput}
151
+ placeholder="Type your message..."
152
+ placeholderTextColor={theme.colors.border}
153
+ style={styles.textInput}
154
+ onSubmitEditing={(e) => {
155
+ e.preventDefault();
156
+ onSubmit();
157
+ }}
158
+ editable={!isLoading}
159
+ autoFocus={true}
160
+ />
161
+ <TouchableOpacity
162
+ onPress={onSubmit}
163
+ disabled={!input.trim() || isLoading}
164
+ style={[
165
+ styles.sendButton,
166
+ (!input.trim() || isLoading) && styles.sendButtonDisabled,
167
+ ]}
168
+ >
169
+ <Ionicons
170
+ name="send"
171
+ size={20}
172
+ color={
173
+ input.trim() && !isLoading
174
+ ? theme.colors.background
175
+ : theme.colors.border
176
+ }
177
+ />
178
+ </TouchableOpacity>
179
+ </View>
180
+ </View>
181
+ </View>
182
+ </KeyboardAvoidingView>
183
+ </Container>
184
+ );
185
+ }
186
+
187
+ const styles = StyleSheet.create((theme) => ({
188
+ container: {
189
+ flex: 1,
190
+ },
191
+ content: {
192
+ flex: 1,
193
+ paddingHorizontal: theme.spacing.md,
194
+ paddingVertical: theme.spacing.lg,
195
+ },
196
+ header: {
197
+ marginBottom: theme.spacing.lg,
198
+ },
199
+ headerTitle: {
200
+ fontSize: 28,
201
+ fontWeight: "bold",
202
+ color: theme.colors.typography,
203
+ marginBottom: theme.spacing.sm,
204
+ },
205
+ headerSubtitle: {
206
+ fontSize: 16,
207
+ color: theme.colors.typography,
208
+ },
209
+ messagesContainer: {
210
+ flex: 1,
211
+ marginBottom: theme.spacing.md,
212
+ },
213
+ emptyContainer: {
214
+ flex: 1,
215
+ justifyContent: "center",
216
+ alignItems: "center",
217
+ },
218
+ emptyText: {
219
+ textAlign: "center",
220
+ color: theme.colors.typography,
221
+ fontSize: 18,
222
+ },
223
+ messagesWrapper: {
224
+ gap: theme.spacing.md,
225
+ },
226
+ messageContainer: {
227
+ padding: theme.spacing.md,
228
+ borderRadius: 8,
229
+ },
230
+ userMessage: {
231
+ backgroundColor: theme.colors.primary + "20",
232
+ marginLeft: theme.spacing.xl,
233
+ alignSelf: "flex-end",
234
+ },
235
+ assistantMessage: {
236
+ backgroundColor: theme.colors.background,
237
+ marginRight: theme.spacing.xl,
238
+ borderWidth: 1,
239
+ borderColor: theme.colors.border,
240
+ },
241
+ messageRole: {
242
+ fontSize: 14,
243
+ fontWeight: "600",
244
+ marginBottom: theme.spacing.sm,
245
+ color: theme.colors.typography,
246
+ },
247
+ messageContent: {
248
+ color: theme.colors.typography,
249
+ lineHeight: 20,
250
+ },
251
+ loadingContainer: {
252
+ flexDirection: "row",
253
+ alignItems: "center",
254
+ gap: theme.spacing.sm,
255
+ },
256
+ loadingText: {
257
+ color: theme.colors.typography,
258
+ opacity: 0.7,
259
+ },
260
+ inputSection: {
261
+ borderTopWidth: 1,
262
+ borderTopColor: theme.colors.border,
263
+ paddingTop: theme.spacing.md,
264
+ },
265
+ inputContainer: {
266
+ flexDirection: "row",
267
+ alignItems: "flex-end",
268
+ gap: theme.spacing.sm,
269
+ },
270
+ textInput: {
271
+ flex: 1,
272
+ borderWidth: 1,
273
+ borderColor: theme.colors.border,
274
+ borderRadius: 8,
275
+ paddingHorizontal: theme.spacing.md,
276
+ paddingVertical: theme.spacing.sm,
277
+ color: theme.colors.typography,
278
+ backgroundColor: theme.colors.background,
279
+ fontSize: 16,
280
+ minHeight: 40,
281
+ maxHeight: 120,
282
+ },
283
+ sendButton: {
284
+ backgroundColor: theme.colors.primary,
285
+ padding: theme.spacing.sm,
286
+ borderRadius: 8,
287
+ justifyContent: "center",
288
+ alignItems: "center",
289
+ },
290
+ sendButtonDisabled: {
291
+ backgroundColor: theme.colors.border,
292
+ },
293
+ }));
294
+ {{else}}
1
295
  import React, { useRef, useEffect, useState } from "react";
2
296
  import {
3
297
  View,
@@ -256,15 +550,6 @@ const styles = StyleSheet.create((theme) => ({
256
550
  color: theme.colors.typography,
257
551
  lineHeight: 20,
258
552
  },
259
- toolInvocations: {
260
- fontSize: 12,
261
- color: theme.colors.typography,
262
- fontFamily: "monospace",
263
- backgroundColor: theme.colors.border + "40",
264
- padding: theme.spacing.sm,
265
- borderRadius: 4,
266
- marginTop: theme.spacing.sm,
267
- },
268
553
  inputSection: {
269
554
  borderTopWidth: 1,
270
555
  borderTopColor: theme.colors.border,
@@ -298,4 +583,5 @@ const styles = StyleSheet.create((theme) => ({
298
583
  sendButtonDisabled: {
299
584
  backgroundColor: theme.colors.border,
300
585
  },
301
- }));
586
+ }));
587
+ {{/if}}
@@ -1,3 +1,181 @@
1
+ {{#if (eq backend "convex")}}
2
+ import { Ionicons } from "@expo/vector-icons";
3
+ import {
4
+ useUIMessages,
5
+ useSmoothText,
6
+ type UIMessage,
7
+ } from "@convex-dev/agent/react";
8
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
9
+ import { useMutation } from "convex/react";
10
+ import { Card, useThemeColor } from "heroui-native";
11
+ import { useRef, useEffect, useState } from "react";
12
+ import {
13
+ View,
14
+ Text,
15
+ TextInput,
16
+ Pressable,
17
+ ScrollView,
18
+ KeyboardAvoidingView,
19
+ Platform,
20
+ ActivityIndicator,
21
+ } from "react-native";
22
+
23
+ import { Container } from "@/components/container";
24
+
25
+ function MessageContent({
26
+ text,
27
+ isStreaming,
28
+ }: {
29
+ text: string;
30
+ isStreaming: boolean;
31
+ }) {
32
+ const [visibleText] = useSmoothText(text, {
33
+ startStreaming: isStreaming,
34
+ });
35
+ return <Text className="text-foreground leading-relaxed">{visibleText}</Text>;
36
+ }
37
+
38
+ export default function AIScreen() {
39
+ const [input, setInput] = useState("");
40
+ const [threadId, setThreadId] = useState<string | null>(null);
41
+ const [isLoading, setIsLoading] = useState(false);
42
+ const scrollViewRef = useRef<ScrollView>(null);
43
+ const mutedColor = useThemeColor("muted");
44
+ const accentColor = useThemeColor("accent");
45
+ const foregroundColor = useThemeColor("foreground");
46
+
47
+ const createThread = useMutation(api.chat.createNewThread);
48
+ const sendMessage = useMutation(api.chat.sendMessage);
49
+
50
+ const { results: messages } = useUIMessages(
51
+ api.chat.listMessages,
52
+ threadId ? { threadId } : "skip",
53
+ { initialNumItems: 50, stream: true },
54
+ );
55
+
56
+ const hasStreamingMessage = messages?.some(
57
+ (m: UIMessage) => m.status === "streaming",
58
+ );
59
+
60
+ useEffect(() => {
61
+ scrollViewRef.current?.scrollToEnd({ animated: true });
62
+ }, [messages]);
63
+
64
+ const onSubmit = async () => {
65
+ const value = input.trim();
66
+ if (!value || isLoading) return;
67
+
68
+ setIsLoading(true);
69
+ setInput("");
70
+
71
+ try {
72
+ let currentThreadId = threadId;
73
+ if (!currentThreadId) {
74
+ currentThreadId = await createThread();
75
+ setThreadId(currentThreadId);
76
+ }
77
+
78
+ await sendMessage({ threadId: currentThreadId, prompt: value });
79
+ } catch (error) {
80
+ console.error("Failed to send message:", error);
81
+ } finally {
82
+ setIsLoading(false);
83
+ }
84
+ };
85
+
86
+ return (
87
+ <Container>
88
+ <KeyboardAvoidingView
89
+ className="flex-1"
90
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
91
+ >
92
+ <View className="flex-1 px-4 py-6">
93
+ <View className="mb-6">
94
+ <Text className="text-foreground text-2xl font-bold mb-2">
95
+ AI Chat
96
+ </Text>
97
+ <Text className="text-muted">Chat with our AI assistant</Text>
98
+ </View>
99
+ <ScrollView
100
+ ref={scrollViewRef}
101
+ className="flex-1 mb-4"
102
+ showsVerticalScrollIndicator={false}
103
+ >
104
+ {!messages || messages.length === 0 ? (
105
+ <View className="flex-1 justify-center items-center">
106
+ <Text className="text-center text-muted text-lg">
107
+ Ask me anything to get started!
108
+ </Text>
109
+ </View>
110
+ ) : (
111
+ <View className="gap-3">
112
+ {messages.map((message: UIMessage) => (
113
+ <Card
114
+ key={message.key}
115
+ variant="secondary"
116
+ className={`p-3 ${message.role === "user" ? "ml-8 bg-accent/10" : "mr-8"}`}
117
+ >
118
+ <Text className="text-sm font-semibold mb-1 text-foreground">
119
+ {message.role === "user" ? "You" : "AI Assistant"}
120
+ </Text>
121
+ <MessageContent
122
+ text={message.text ?? ""}
123
+ isStreaming={message.status === "streaming"}
124
+ />
125
+ </Card>
126
+ ))}
127
+ {isLoading && !hasStreamingMessage && (
128
+ <Card variant="secondary" className="p-3 mr-8">
129
+ <Text className="text-sm font-semibold mb-1 text-foreground">
130
+ AI Assistant
131
+ </Text>
132
+ <View className="flex-row items-center gap-2">
133
+ <ActivityIndicator size="small" color={accentColor} />
134
+ <Text className="text-muted">Thinking...</Text>
135
+ </View>
136
+ </Card>
137
+ )}
138
+ </View>
139
+ )}
140
+ </ScrollView>
141
+ <View className="border-t border-divider pt-4">
142
+ <View className="flex-row items-end gap-2">
143
+ <TextInput
144
+ value={input}
145
+ onChangeText={setInput}
146
+ placeholder="Type your message..."
147
+ placeholderTextColor={mutedColor}
148
+ className="flex-1 border border-divider rounded-lg px-3 py-2 text-foreground bg-surface min-h-10 max-h-30"
149
+ onSubmitEditing={(e) => {
150
+ e.preventDefault();
151
+ onSubmit();
152
+ }}
153
+ editable={!isLoading}
154
+ autoFocus={true}
155
+ />
156
+ <Pressable
157
+ onPress={onSubmit}
158
+ disabled={!input.trim() || isLoading}
159
+ className={`p-2 rounded-lg active:opacity-70 ${
160
+ input.trim() && !isLoading ? "bg-accent" : "bg-surface"
161
+ }`}
162
+ >
163
+ <Ionicons
164
+ name="send"
165
+ size={20}
166
+ color={
167
+ input.trim() && !isLoading ? foregroundColor : mutedColor
168
+ }
169
+ />
170
+ </Pressable>
171
+ </View>
172
+ </View>
173
+ </View>
174
+ </KeyboardAvoidingView>
175
+ </Container>
176
+ );
177
+ }
178
+ {{else}}
1
179
  import { useRef, useEffect, useState } from "react";
2
180
  import {
3
181
  View,
@@ -168,4 +346,5 @@ export default function AIScreen() {
168
346
  </KeyboardAvoidingView>
169
347
  </Container>
170
348
  );
171
- }
349
+ }
350
+ {{/if}}