create-aron-app 0.1.0 → 0.1.1
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 +5 -2
- package/templates/_base/.cursor/agents/skills/clerk/SKILL.md +89 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/SKILL.md +142 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +30 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +88 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +165 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +208 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +14 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/SKILL.md +157 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +224 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +190 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +314 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +259 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +125 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +94 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +50 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +56 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +68 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +56 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +104 -0
- package/templates/_base/.cursor/agents/skills/clerk/clerk-webhooks/SKILL.md +131 -0
- package/templates/_base/.cursor/agents/skills/shadcn/SKILL.md +241 -0
- package/templates/_base/.cursor/agents/skills/shadcn/agents/openai.yml +5 -0
- package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn.png +0 -0
- package/templates/_base/.cursor/agents/skills/shadcn/cli.md +257 -0
- package/templates/_base/.cursor/agents/skills/shadcn/customization.md +202 -0
- package/templates/_base/.cursor/agents/skills/shadcn/evals/evals.json +47 -0
- package/templates/_base/.cursor/agents/skills/shadcn/mcp.md +94 -0
- package/templates/_base/.cursor/agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/templates/_base/.cursor/agents/skills/shadcn/rules/composition.md +195 -0
- package/templates/_base/.cursor/agents/skills/shadcn/rules/forms.md +192 -0
- package/templates/_base/.cursor/agents/skills/shadcn/rules/icons.md +101 -0
- package/templates/_base/.cursor/agents/skills/shadcn/rules/styling.md +162 -0
- package/templates/_base/.cursor/commands/builder.md +0 -0
- package/templates/_base/.cursor/commands/pr.md +7 -0
- package/templates/_base/.cursor/rules/api_architecture.mdc +268 -0
- package/templates/_base/.cursor/rules/coding_standards.mdc +64 -0
- package/templates/_base/.cursor/rules/convex_rules.mdc +675 -0
- package/templates/_base/.cursor/rules/frontend_rules.mdc +268 -0
- package/templates/_base/.env.convex.example +3 -0
- package/templates/_base/.github/workflows/ci.yml +29 -0
- package/templates/_base/.nvmrc +1 -0
- package/templates/_base/.vscode/settings.json +9 -0
- package/templates/_base/apps/api/auth.config.ts +18 -0
- package/templates/_base/apps/api/functions.ts +99 -0
- package/templates/_base/apps/api/project.json +22 -0
- package/templates/_base/apps/api/schema.ts +11 -0
- package/templates/_base/apps/api/todos/crud.ts +81 -0
- package/templates/_base/apps/api/todos/schema.ts +11 -0
- package/templates/_base/apps/api/todos/types.ts +22 -0
- package/templates/_base/apps/api/tsconfig.json +23 -0
- package/templates/_base/apps/api/types.ts +16 -0
- package/templates/_base/biome.json +114 -0
- package/templates/_base/convex.json +4 -0
- package/templates/_base/emails/project.json +16 -0
- package/templates/_base/emails/tsconfig.json +5 -0
- package/templates/_base/emails/welcome_email.tsx +53 -0
- package/templates/_base/nx.json +29 -0
- package/templates/_base/package.json +73 -0
- package/templates/_base/scripts/sync_convex_env.ts +63 -0
- package/templates/_base/shared/assets/image.d.ts +4 -0
- package/templates/_base/shared/assets/src/styles/global.css +73 -0
- package/templates/_base/shared/assets/tsconfig.json +5 -0
- package/templates/_base/shared/ui/src/base/alert_dialog.tsx +139 -0
- package/templates/_base/shared/ui/src/base/badge.tsx +33 -0
- package/templates/_base/shared/ui/src/base/basic_data_table.tsx +61 -0
- package/templates/_base/shared/ui/src/base/button.tsx +69 -0
- package/templates/_base/shared/ui/src/base/button_group.tsx +82 -0
- package/templates/_base/shared/ui/src/base/card.tsx +79 -0
- package/templates/_base/shared/ui/src/base/checkbox.tsx +26 -0
- package/templates/_base/shared/ui/src/base/command.tsx +165 -0
- package/templates/_base/shared/ui/src/base/dialog.tsx +129 -0
- package/templates/_base/shared/ui/src/base/dropdown_menu.tsx +232 -0
- package/templates/_base/shared/ui/src/base/form.tsx +161 -0
- package/templates/_base/shared/ui/src/base/input.tsx +129 -0
- package/templates/_base/shared/ui/src/base/label.tsx +19 -0
- package/templates/_base/shared/ui/src/base/popover.tsx +46 -0
- package/templates/_base/shared/ui/src/base/radio_group.tsx +49 -0
- package/templates/_base/shared/ui/src/base/resizable.tsx +55 -0
- package/templates/_base/shared/ui/src/base/scroll_area.tsx +44 -0
- package/templates/_base/shared/ui/src/base/select.tsx +151 -0
- package/templates/_base/shared/ui/src/base/separator.tsx +32 -0
- package/templates/_base/shared/ui/src/base/sheet.tsx +130 -0
- package/templates/_base/shared/ui/src/base/side_bar.tsx +688 -0
- package/templates/_base/shared/ui/src/base/skeleton.tsx +7 -0
- package/templates/_base/shared/ui/src/base/spinner.tsx +20 -0
- package/templates/_base/shared/ui/src/base/switch.tsx +27 -0
- package/templates/_base/shared/ui/src/base/table.tsx +91 -0
- package/templates/_base/shared/ui/src/base/text_area.tsx +21 -0
- package/templates/_base/shared/ui/src/base/tooltip.tsx +31 -0
- package/templates/_base/shared/ui/src/base/utils.ts +17 -0
- package/templates/_base/shared/ui/src/hooks/use_keyboard_press.tsx +48 -0
- package/templates/_base/shared/ui/src/hooks/use_keyboard_release.tsx +48 -0
- package/templates/_base/shared/ui/src/hooks/use_mobile.tsx +25 -0
- package/templates/_base/shared/ui/src/hooks/use_mouse_click.tsx +44 -0
- package/templates/_base/shared/ui/src/hooks/use_mouse_location.tsx +55 -0
- package/templates/_base/shared/ui/src/hooks/use_outside_click.tsx +29 -0
- package/templates/_base/shared/ui/src/hooks/use_query_params.tsx +33 -0
- package/templates/_base/shared/ui/tsconfig.json +8 -0
- package/templates/_base/shared/utils/src/convex.ts +3 -0
- package/templates/_base/shared/utils/src/time.ts +12 -0
- package/templates/_base/shared/utils/tsconfig.json +5 -0
- package/templates/_base/skills-lock.json +35 -0
- package/templates/_base/tsconfig.base.json +34 -0
- package/templates/nextjs/.env.example +8 -0
- package/templates/nextjs/index.d.ts +6 -0
- package/templates/nextjs/next-env.d.ts +5 -0
- package/templates/nextjs/next.config.js +22 -0
- package/templates/nextjs/postcss.config.js +17 -0
- package/templates/nextjs/project.json +22 -0
- package/templates/nextjs/src/app/(auth)/layout.tsx +21 -0
- package/templates/nextjs/src/app/(auth)/not-allowed/page.tsx +22 -0
- package/templates/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +15 -0
- package/templates/nextjs/src/app/(dashboard)/layout.tsx +27 -0
- package/templates/nextjs/src/app/(dashboard)/page.tsx +5 -0
- package/templates/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +23 -0
- package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +16 -0
- package/templates/nextjs/src/app/app.css +3 -0
- package/templates/nextjs/src/app/layout.tsx +26 -0
- package/templates/nextjs/src/convex.ts +11 -0
- package/templates/nextjs/src/middleware.ts +18 -0
- package/templates/nextjs/src/providers/convex_provider.tsx +44 -0
- package/templates/nextjs/src/surfaces/home_surface.tsx +22 -0
- package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +97 -0
- package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +107 -0
- package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +90 -0
- package/templates/nextjs/src/ui/sidebar/nav_link.tsx +36 -0
- package/templates/nextjs/src/ui/sidebar/sidebar.tsx +125 -0
- package/templates/nextjs/src/utils/font.ts +9 -0
- package/templates/nextjs/tsconfig.json +42 -0
- package/templates/react-router/.env.example +8 -0
- package/templates/react-router/postcss.config.js +15 -0
- package/templates/react-router/project.json +23 -0
- package/templates/react-router/public/favicon.ico +0 -0
- package/templates/react-router/react-router.config.ts +9 -0
- package/templates/react-router/src/app.css +3 -0
- package/templates/react-router/src/components/error_boundary.tsx +33 -0
- package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +76 -0
- package/templates/react-router/src/layouts/sidebar/sidebar_aside/user_menu.tsx +36 -0
- package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +22 -0
- package/templates/react-router/src/providers/api_auth_provider.tsx +38 -0
- package/templates/react-router/src/root.tsx +37 -0
- package/templates/react-router/src/routes/auth/layout.tsx +13 -0
- package/templates/react-router/src/routes/auth/sign-in.tsx +13 -0
- package/templates/react-router/src/routes/index.tsx +9 -0
- package/templates/react-router/src/routes/layout.tsx +26 -0
- package/templates/react-router/src/routes/todos/[id].tsx +22 -0
- package/templates/react-router/src/routes/todos/index.tsx +13 -0
- package/templates/react-router/src/routes.ts +12 -0
- package/templates/react-router/src/surfaces/home_surface.tsx +20 -0
- package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +87 -0
- package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +102 -0
- package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +81 -0
- package/templates/react-router/tsconfig.json +20 -0
- package/templates/react-router/vite.config.ts +40 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { convexQuery, useConvexMutation } from "@convex-dev/react-query";
|
|
6
|
+
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
7
|
+
import { Trash2 } from "lucide-react";
|
|
8
|
+
import { Link } from "react-router";
|
|
9
|
+
|
|
10
|
+
import { api } from "@/api/_generated/api";
|
|
11
|
+
import type { Id } from "@/api/_generated/dataModel";
|
|
12
|
+
import { Button } from "@/ui/base/button";
|
|
13
|
+
import { Checkbox } from "@/ui/base/checkbox";
|
|
14
|
+
import { Spinner } from "@/ui/base/spinner";
|
|
15
|
+
import { CreateTodoSheet } from "@/web/surfaces/todos/create_todo_sheet";
|
|
16
|
+
|
|
17
|
+
export const AllTodosSurface = () => {
|
|
18
|
+
const { data: todos, isPending } = useQuery(convexQuery(api.todos.crud.listTodos, {}));
|
|
19
|
+
|
|
20
|
+
const { mutate: updateTodo } = useMutation({
|
|
21
|
+
mutationFn: useConvexMutation(api.todos.crud.updateTodo),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const { mutate: deleteTodo } = useMutation({
|
|
25
|
+
mutationFn: useConvexMutation(api.todos.crud.deleteTodo),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<main className="flex flex-1 flex-col overflow-auto p-6">
|
|
30
|
+
<div className="flex items-center justify-between mb-6">
|
|
31
|
+
<h1 className="text-2xl font-semibold">Todos</h1>
|
|
32
|
+
<CreateTodoSheet />
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
{isPending && (
|
|
36
|
+
<div className="flex flex-1 items-center justify-center">
|
|
37
|
+
<Spinner />
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
|
|
41
|
+
{!isPending && todos?.length === 0 && (
|
|
42
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-2 text-muted-foreground">
|
|
43
|
+
<p>No todos yet.</p>
|
|
44
|
+
<CreateTodoSheet />
|
|
45
|
+
</div>
|
|
46
|
+
)}
|
|
47
|
+
|
|
48
|
+
{todos && todos.length > 0 && (
|
|
49
|
+
<ul className="flex flex-col gap-2 max-w-2xl">
|
|
50
|
+
{todos.map((todo) => (
|
|
51
|
+
<li
|
|
52
|
+
key={todo._id}
|
|
53
|
+
className="flex items-center gap-3 rounded-lg border bg-card px-4 py-3"
|
|
54
|
+
>
|
|
55
|
+
<Checkbox
|
|
56
|
+
checked={todo.isCompleted}
|
|
57
|
+
onCheckedChange={(checked) =>
|
|
58
|
+
updateTodo({
|
|
59
|
+
todoId: todo._id as Id<"todos">,
|
|
60
|
+
isCompleted: !!checked,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
/>
|
|
64
|
+
<Link
|
|
65
|
+
to={`/todos/${todo._id}`}
|
|
66
|
+
className="flex-1 truncate text-sm hover:underline"
|
|
67
|
+
style={{
|
|
68
|
+
textDecoration: todo.isCompleted ? "line-through" : undefined,
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{todo.title}
|
|
72
|
+
</Link>
|
|
73
|
+
<Button
|
|
74
|
+
variant="ghost"
|
|
75
|
+
size="icon"
|
|
76
|
+
className="size-7 shrink-0 text-muted-foreground hover:text-destructive"
|
|
77
|
+
onClick={() => deleteTodo({ todoId: todo._id as Id<"todos"> })}
|
|
78
|
+
>
|
|
79
|
+
<Trash2 className="size-4" />
|
|
80
|
+
</Button>
|
|
81
|
+
</li>
|
|
82
|
+
))}
|
|
83
|
+
</ul>
|
|
84
|
+
)}
|
|
85
|
+
</main>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useConvexMutation } from "@convex-dev/react-query";
|
|
6
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
7
|
+
import { useMutation } from "@tanstack/react-query";
|
|
8
|
+
import { Plus } from "lucide-react";
|
|
9
|
+
import { useForm } from "react-hook-form";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
import { api } from "@/api/_generated/api";
|
|
13
|
+
import { Button } from "@/ui/base/button";
|
|
14
|
+
import { DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/ui/base/dialog";
|
|
15
|
+
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/ui/base/form";
|
|
16
|
+
import { Input } from "@/ui/base/input";
|
|
17
|
+
import { Sheet, SheetContent, SheetTrigger } from "@/ui/base/sheet";
|
|
18
|
+
import { TextArea } from "@/ui/base/text_area";
|
|
19
|
+
|
|
20
|
+
const createTodoSchema = z.object({
|
|
21
|
+
title: z.string().min(1, "Title is required"),
|
|
22
|
+
description: z.string().optional(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
type CreateTodoSchema = z.infer<typeof createTodoSchema>;
|
|
26
|
+
|
|
27
|
+
export const CreateTodoSheet = () => {
|
|
28
|
+
const form = useForm<CreateTodoSchema>({
|
|
29
|
+
resolver: zodResolver(createTodoSchema),
|
|
30
|
+
defaultValues: { title: "", description: "" },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { mutate: createTodo, isPending } = useMutation({
|
|
34
|
+
mutationFn: useConvexMutation(api.todos.crud.createTodo),
|
|
35
|
+
onSuccess: () => form.reset(),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const handleSubmit = form.handleSubmit((values) => {
|
|
39
|
+
createTodo(values);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Sheet>
|
|
44
|
+
<SheetTrigger asChild>
|
|
45
|
+
<Button size="sm">
|
|
46
|
+
<Plus className="mr-2 size-4" />
|
|
47
|
+
New Todo
|
|
48
|
+
</Button>
|
|
49
|
+
</SheetTrigger>
|
|
50
|
+
<SheetContent className="sm:max-w-[480px]">
|
|
51
|
+
<DialogHeader>
|
|
52
|
+
<DialogTitle>New Todo</DialogTitle>
|
|
53
|
+
<DialogDescription>Add a new todo to your list.</DialogDescription>
|
|
54
|
+
</DialogHeader>
|
|
55
|
+
<Form {...form}>
|
|
56
|
+
<form
|
|
57
|
+
onSubmit={handleSubmit}
|
|
58
|
+
className="flex flex-col gap-4 pt-4"
|
|
59
|
+
onKeyDown={(e) => {
|
|
60
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
handleSubmit();
|
|
63
|
+
}
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<FormField
|
|
67
|
+
control={form.control}
|
|
68
|
+
name="title"
|
|
69
|
+
render={({ field }) => (
|
|
70
|
+
<FormItem>
|
|
71
|
+
<FormLabel>Title</FormLabel>
|
|
72
|
+
<FormControl>
|
|
73
|
+
<Input placeholder="Buy groceries" {...field} />
|
|
74
|
+
</FormControl>
|
|
75
|
+
<FormMessage />
|
|
76
|
+
</FormItem>
|
|
77
|
+
)}
|
|
78
|
+
/>
|
|
79
|
+
<FormField
|
|
80
|
+
control={form.control}
|
|
81
|
+
name="description"
|
|
82
|
+
render={({ field }) => (
|
|
83
|
+
<FormItem>
|
|
84
|
+
<FormLabel>Description</FormLabel>
|
|
85
|
+
<FormControl>
|
|
86
|
+
<TextArea placeholder="Optional details..." rows={3} {...field} />
|
|
87
|
+
</FormControl>
|
|
88
|
+
<FormMessage />
|
|
89
|
+
</FormItem>
|
|
90
|
+
)}
|
|
91
|
+
/>
|
|
92
|
+
<DialogFooter>
|
|
93
|
+
<Button type="submit" disabled={isPending}>
|
|
94
|
+
{isPending ? "Creating…" : "Create Todo"}
|
|
95
|
+
</Button>
|
|
96
|
+
</DialogFooter>
|
|
97
|
+
</form>
|
|
98
|
+
</Form>
|
|
99
|
+
</SheetContent>
|
|
100
|
+
</Sheet>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { convexQuery, useConvexMutation } from "@convex-dev/react-query";
|
|
6
|
+
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
7
|
+
import { ArrowLeft } from "lucide-react";
|
|
8
|
+
import { Link } from "react-router";
|
|
9
|
+
|
|
10
|
+
import { api } from "@/api/_generated/api";
|
|
11
|
+
import type { TodoId } from "@/api/todos/types";
|
|
12
|
+
import { Badge } from "@/ui/base/badge";
|
|
13
|
+
import { Button } from "@/ui/base/button";
|
|
14
|
+
import { Checkbox } from "@/ui/base/checkbox";
|
|
15
|
+
import { Spinner } from "@/ui/base/spinner";
|
|
16
|
+
|
|
17
|
+
type SingleTodoSurfaceProps = {
|
|
18
|
+
todoId: TodoId;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const SingleTodoSurface = ({ todoId }: SingleTodoSurfaceProps) => {
|
|
22
|
+
const { data: todo, isPending } = useQuery(convexQuery(api.todos.crud.getTodo, { todoId }));
|
|
23
|
+
|
|
24
|
+
const { mutate: updateTodo } = useMutation({
|
|
25
|
+
mutationFn: useConvexMutation(api.todos.crud.updateTodo),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (isPending) {
|
|
29
|
+
return (
|
|
30
|
+
<main className="flex flex-1 items-center justify-center">
|
|
31
|
+
<Spinner />
|
|
32
|
+
</main>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!todo) {
|
|
37
|
+
return (
|
|
38
|
+
<main className="flex flex-1 flex-col items-center justify-center gap-4">
|
|
39
|
+
<p className="text-muted-foreground">Todo not found.</p>
|
|
40
|
+
<Button variant="outline" asChild>
|
|
41
|
+
<Link to="/todos">
|
|
42
|
+
<ArrowLeft className="mr-2 size-4" />
|
|
43
|
+
Back to todos
|
|
44
|
+
</Link>
|
|
45
|
+
</Button>
|
|
46
|
+
</main>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<main className="flex flex-1 flex-col gap-6 overflow-auto p-6 max-w-2xl">
|
|
52
|
+
<Button variant="ghost" className="w-fit -ml-2 text-muted-foreground" asChild>
|
|
53
|
+
<Link to="/todos">
|
|
54
|
+
<ArrowLeft className="mr-2 size-4" />
|
|
55
|
+
Back
|
|
56
|
+
</Link>
|
|
57
|
+
</Button>
|
|
58
|
+
|
|
59
|
+
<div className="flex items-start gap-3">
|
|
60
|
+
<Checkbox
|
|
61
|
+
className="mt-1"
|
|
62
|
+
checked={todo.isCompleted}
|
|
63
|
+
onCheckedChange={(checked) => updateTodo({ todoId, isCompleted: !!checked })}
|
|
64
|
+
/>
|
|
65
|
+
<div className="flex flex-col gap-2">
|
|
66
|
+
<h1
|
|
67
|
+
className="text-2xl font-semibold"
|
|
68
|
+
style={{ textDecoration: todo.isCompleted ? "line-through" : undefined }}
|
|
69
|
+
>
|
|
70
|
+
{todo.title}
|
|
71
|
+
</h1>
|
|
72
|
+
<Badge variant={todo.isCompleted ? "secondary" : "default"}>
|
|
73
|
+
{todo.isCompleted ? "Completed" : "In progress"}
|
|
74
|
+
</Badge>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
{todo.description && <p className="text-muted-foreground">{todo.description}</p>}
|
|
79
|
+
</main>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
5
|
+
"types": ["node", "vite/client"],
|
|
6
|
+
"target": "ES2022",
|
|
7
|
+
"module": "ES2022",
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"jsx": "react-jsx",
|
|
10
|
+
"rootDirs": [".", "./.react-router/types"],
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"strict": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["**/*", "**/.server/**/*", "**/.client/**/*", ".react-router/types/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "build", "public"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
4
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
5
|
+
import { defineConfig, type PluginOption } from "vite";
|
|
6
|
+
import devtoolsJson from "vite-plugin-devtools-json";
|
|
7
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
8
|
+
|
|
9
|
+
const workspaceRoot = path.resolve(__dirname, "../..");
|
|
10
|
+
|
|
11
|
+
if (!process.env.VITE_CLERK_PUBLISHABLE_KEY) {
|
|
12
|
+
throw new Error("VITE_CLERK_PUBLISHABLE_KEY is not set");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!process.env.CLERK_SECRET_KEY) {
|
|
16
|
+
throw new Error("CLERK_SECRET_KEY is not set");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default defineConfig({
|
|
20
|
+
plugins: [
|
|
21
|
+
tailwindcss(),
|
|
22
|
+
reactRouter(),
|
|
23
|
+
tsconfigPaths(),
|
|
24
|
+
devtoolsJson({ uuid: "my-app" }) as PluginOption,
|
|
25
|
+
],
|
|
26
|
+
server: {
|
|
27
|
+
fs: {
|
|
28
|
+
allow: [workspaceRoot],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
resolve: {
|
|
32
|
+
alias: {
|
|
33
|
+
"@/api": path.resolve(__dirname, "../../apps/api"),
|
|
34
|
+
"@/assets": path.resolve(__dirname, "../../shared/assets/src"),
|
|
35
|
+
"@/ui": path.resolve(__dirname, "../../shared/ui/src"),
|
|
36
|
+
"@/utils": path.resolve(__dirname, "../../shared/utils/src"),
|
|
37
|
+
"@/web": path.resolve(__dirname, "src"),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|