Skip to content

Commit f455f9b

Browse files
committed
fix: convex version bump and better content
1 parent 9da2f9e commit f455f9b

File tree

6 files changed

+210
-32
lines changed

6 files changed

+210
-32
lines changed

frameworks/react-cra/add-ons/convex/assets/convex/products.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import { defineSchema, defineTable } from "convex/server";
2-
import { v } from "convex/values";
1+
import { defineSchema, defineTable } from 'convex/server'
2+
import { v } from 'convex/values'
33

44
export default defineSchema({
55
products: defineTable({
66
title: v.string(),
77
imageId: v.string(),
88
price: v.number(),
99
}),
10-
});
10+
todos: defineTable({
11+
text: v.string(),
12+
completed: v.boolean(),
13+
}),
14+
})
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { mutation, query } from './_generated/server'
2+
import { v } from 'convex/values'
3+
4+
export const list = query({
5+
args: {},
6+
handler: async (ctx) => {
7+
return await ctx.db
8+
.query('todos')
9+
.withIndex('by_creation_time')
10+
.order('desc')
11+
.collect()
12+
},
13+
})
14+
15+
export const add = mutation({
16+
args: { text: v.string() },
17+
handler: async (ctx, args) => {
18+
return await ctx.db.insert('todos', {
19+
text: args.text,
20+
completed: false,
21+
})
22+
},
23+
})
24+
25+
export const toggle = mutation({
26+
args: { id: v.id('todos') },
27+
handler: async (ctx, args) => {
28+
const todo = await ctx.db.get(args.id)
29+
if (!todo) {
30+
throw new Error('Todo not found')
31+
}
32+
return await ctx.db.patch(args.id, {
33+
completed: !todo.completed,
34+
})
35+
},
36+
})
37+
38+
export const remove = mutation({
39+
args: { id: v.id('todos') },
40+
handler: async (ctx, args) => {
41+
return await ctx.db.delete(args.id)
42+
},
43+
})
Lines changed: 157 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,171 @@
1-
import { Suspense } from 'react'
1+
import { useCallback, useState } from 'react'
22
import { createFileRoute } from '@tanstack/react-router'
3-
import { useQuery } from 'convex/react'
3+
import { useQuery, useMutation } from 'convex/react'
4+
import { Trash2, Plus, Check, Circle } from 'lucide-react'
45

56
import { api } from '../../convex/_generated/api'
67

78
export const Route = createFileRoute('/demo/convex')({
8-
component: App,
9+
ssr: false,
10+
component: ConvexTodos,
911
})
1012

11-
function Products() {
12-
const products = useQuery(api.products.get)
13+
function ConvexTodos() {
14+
const todos = useQuery(api.todos.list)
15+
const addTodo = useMutation(api.todos.add)
16+
const toggleTodo = useMutation(api.todos.toggle)
17+
const removeTodo = useMutation(api.todos.remove)
1318

14-
return (
15-
<ul>
16-
{(products || []).map((p) => (
17-
<li key={p._id}>
18-
{p.title} - {p.price}
19-
</li>
20-
))}
21-
</ul>
19+
const [newTodo, setNewTodo] = useState('')
20+
21+
const handleAddTodo = useCallback(async () => {
22+
if (newTodo.trim()) {
23+
await addTodo({ text: newTodo.trim() })
24+
setNewTodo('')
25+
}
26+
}, [addTodo, newTodo])
27+
28+
const handleToggleTodo = useCallback(
29+
async (id: string) => {
30+
await toggleTodo({ id })
31+
},
32+
[toggleTodo],
33+
)
34+
35+
const handleRemoveTodo = useCallback(
36+
async (id: string) => {
37+
await removeTodo({ id })
38+
},
39+
[removeTodo],
2240
)
23-
}
2441

25-
function App() {
42+
const completedCount = todos?.filter((todo) => todo.completed).length || 0
43+
const totalCount = todos?.length || 0
44+
2645
return (
27-
<div className="p-4">
28-
<Suspense fallback={<div>Loading...</div>}>
29-
<Products />
30-
</Suspense>
46+
<div
47+
className="min-h-screen flex items-center justify-center p-4"
48+
style={{
49+
background:
50+
'linear-gradient(135deg, #667a56 0%, #8fbc8f 25%, #90ee90 50%, #98fb98 75%, #f0fff0 100%)',
51+
}}
52+
>
53+
<div className="w-full max-w-2xl">
54+
{/* Header Card */}
55+
<div className="bg-white/95 backdrop-blur-sm rounded-2xl shadow-2xl border border-green-200/50 p-8 mb-6">
56+
<div className="text-center">
57+
<h1 className="text-4xl font-bold text-green-800 mb-2">
58+
Convex Todos
59+
</h1>
60+
<p className="text-green-600 text-lg">Powered by real-time sync</p>
61+
{totalCount > 0 && (
62+
<div className="mt-4 flex justify-center space-x-6 text-sm">
63+
<span className="text-green-700 font-medium">
64+
{completedCount} completed
65+
</span>
66+
<span className="text-gray-600">
67+
{totalCount - completedCount} remaining
68+
</span>
69+
</div>
70+
)}
71+
</div>
72+
</div>
73+
74+
{/* Add Todo Card */}
75+
<div className="bg-white/95 backdrop-blur-sm rounded-2xl shadow-xl border border-green-200/50 p-6 mb-6">
76+
<div className="flex gap-3">
77+
<input
78+
type="text"
79+
value={newTodo}
80+
onChange={(e) => setNewTodo(e.target.value)}
81+
onKeyDown={(e) => {
82+
if (e.key === 'Enter') {
83+
handleAddTodo()
84+
}
85+
}}
86+
placeholder="What needs to be done?"
87+
className="flex-1 px-4 py-3 rounded-xl border-2 border-green-200 focus:border-green-400 focus:outline-none text-gray-800 placeholder-gray-500 bg-white/80 transition-colors"
88+
/>
89+
<button
90+
onClick={handleAddTodo}
91+
disabled={!newTodo.trim()}
92+
className="bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 disabled:from-gray-300 disabled:to-gray-400 disabled:cursor-not-allowed text-white font-semibold py-3 px-6 rounded-xl transition-all duration-200 flex items-center gap-2 shadow-lg hover:shadow-xl"
93+
>
94+
<Plus size={20} />
95+
Add
96+
</button>
97+
</div>
98+
</div>
99+
100+
{/* Todos List */}
101+
<div className="bg-white/95 backdrop-blur-sm rounded-2xl shadow-xl border border-green-200/50 overflow-hidden">
102+
{!todos ? (
103+
<div className="p-8 text-center">
104+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-green-500 mx-auto mb-4"></div>
105+
<p className="text-green-600">Loading todos...</p>
106+
</div>
107+
) : todos.length === 0 ? (
108+
<div className="p-12 text-center">
109+
<Circle size={48} className="text-green-300 mx-auto mb-4" />
110+
<h3 className="text-xl font-semibold text-green-800 mb-2">
111+
No todos yet
112+
</h3>
113+
<p className="text-green-600">
114+
Add your first todo above to get started!
115+
</p>
116+
</div>
117+
) : (
118+
<div className="divide-y divide-green-100">
119+
{todos.map((todo, index) => (
120+
<div
121+
key={todo._id}
122+
className={`p-4 flex items-center gap-4 hover:bg-green-50/50 transition-colors ${
123+
todo.completed ? 'opacity-75' : ''
124+
}`}
125+
style={{
126+
animationDelay: `${index * 50}ms`,
127+
}}
128+
>
129+
<button
130+
onClick={() => handleToggleTodo(todo._id)}
131+
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all duration-200 ${
132+
todo.completed
133+
? 'bg-green-500 border-green-500 text-white'
134+
: 'border-green-300 hover:border-green-400 text-transparent hover:text-green-400'
135+
}`}
136+
>
137+
<Check size={14} />
138+
</button>
139+
140+
<span
141+
className={`flex-1 text-lg transition-all duration-200 ${
142+
todo.completed
143+
? 'line-through text-gray-500'
144+
: 'text-gray-800'
145+
}`}
146+
>
147+
{todo.text}
148+
</span>
149+
150+
<button
151+
onClick={() => handleRemoveTodo(todo._id)}
152+
className="flex-shrink-0 p-2 text-red-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors"
153+
>
154+
<Trash2 size={18} />
155+
</button>
156+
</div>
157+
))}
158+
</div>
159+
)}
160+
</div>
161+
162+
{/* Footer */}
163+
<div className="text-center mt-6">
164+
<p className="text-green-700/80 text-sm">
165+
Built with Convex • Real-time updates • Always in sync
166+
</p>
167+
</div>
168+
</div>
31169
</div>
32170
)
33171
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"dependencies": {
33
"@convex-dev/react-query": "0.0.0-alpha.8",
4-
"convex": "^1.19.2"
4+
"convex": "^1.27.3",
5+
"lucide-react": "^0.544.0"
56
}
67
}

packages/cta-engine/src/create-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ Use the following commands to start your app:
234234
getPackageManagerScriptCommand(options.packageManager, ['dev']),
235235
)}
236236
237-
Please check the README.md for information on testing, styling, adding routes, etc.${errorStatement}`,
237+
Please read the README.md for information on testing, styling, adding routes, etc.${errorStatement}`,
238238
)
239239
}
240240

0 commit comments

Comments
 (0)