create-croissant 0.1.39 → 0.1.41
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/dist/index.js +5 -5
- package/package.json +7 -10
- package/template/.oxlintignore +11 -0
- package/template/README.md +6 -6
- package/template/apps/desktop/README.md +1 -1
- package/template/apps/desktop/electron-builder.yml +6 -6
- package/template/apps/desktop/electron.vite.config.ts +8 -8
- package/template/apps/desktop/package.json +4 -13
- package/template/apps/desktop/src/main/index.ts +32 -32
- package/template/apps/desktop/src/preload/index.d.ts +3 -3
- package/template/apps/desktop/src/preload/index.ts +8 -8
- package/template/apps/desktop/src/renderer/src/App.tsx +5 -5
- package/template/apps/desktop/src/renderer/src/assets/base.css +4 -4
- package/template/apps/desktop/src/renderer/src/assets/main.css +3 -3
- package/template/apps/desktop/src/renderer/src/components/Versions.tsx +4 -4
- package/template/apps/desktop/src/renderer/src/main.tsx +7 -7
- package/template/apps/desktop/tsconfig.json +1 -4
- package/template/apps/desktop/tsconfig.node.json +1 -1
- package/template/apps/desktop/tsconfig.web.json +4 -11
- package/template/apps/mobile/app/(tabs)/_layout.tsx +11 -10
- package/template/apps/mobile/app/(tabs)/explore.tsx +29 -27
- package/template/apps/mobile/app/(tabs)/index.tsx +25 -24
- package/template/apps/mobile/app/_layout.tsx +8 -8
- package/template/apps/mobile/app/modal.tsx +6 -6
- package/template/apps/mobile/components/external-link.tsx +5 -5
- package/template/apps/mobile/components/haptic-tab.tsx +4 -4
- package/template/apps/mobile/components/hello-wave.tsx +5 -4
- package/template/apps/mobile/components/parallax-scroll-view.tsx +15 -13
- package/template/apps/mobile/components/themed-text.tsx +14 -14
- package/template/apps/mobile/components/themed-view.tsx +3 -3
- package/template/apps/mobile/components/ui/collapsible.tsx +14 -13
- package/template/apps/mobile/components/ui/icon-symbol.ios.tsx +4 -4
- package/template/apps/mobile/components/ui/icon-symbol.tsx +9 -9
- package/template/apps/mobile/constants/theme.ts +19 -19
- package/template/apps/mobile/hooks/use-color-scheme.ts +1 -1
- package/template/apps/mobile/hooks/use-color-scheme.web.ts +3 -3
- package/template/apps/mobile/hooks/use-theme-color.ts +4 -4
- package/template/apps/mobile/package.json +3 -6
- package/template/apps/mobile/scripts/reset-project.js +2 -2
- package/template/apps/mobile/tsconfig.json +2 -9
- package/template/apps/platform/drizzle.config.ts +5 -5
- package/template/apps/platform/package.json +2 -6
- package/template/apps/platform/src/components/app-sidebar.tsx +60 -69
- package/template/apps/platform/src/components/login-form.tsx +32 -39
- package/template/apps/platform/src/components/search-form.tsx +5 -13
- package/template/apps/platform/src/components/signup-form.tsx +39 -49
- package/template/apps/platform/src/components/version-switcher.tsx +11 -21
- package/template/apps/platform/src/lib/auth-utils.ts +12 -14
- package/template/apps/platform/src/lib/orpc.ts +17 -17
- package/template/apps/platform/src/routeTree.gen.ts +264 -267
- package/template/apps/platform/src/router.tsx +5 -5
- package/template/apps/platform/src/routes/__root.tsx +13 -15
- package/template/apps/platform/src/routes/_auth/account.tsx +61 -50
- package/template/apps/platform/src/routes/_auth/dashboard.tsx +17 -17
- package/template/apps/platform/src/routes/_auth/examples/client-orpc-auth.tsx +13 -13
- package/template/apps/platform/src/routes/_auth/examples/ssr-orpc-auth.tsx +17 -17
- package/template/apps/platform/src/routes/_auth.tsx +5 -5
- package/template/apps/platform/src/routes/_public/examples/client-orpc.tsx +108 -88
- package/template/apps/platform/src/routes/_public/examples/isr.tsx +14 -14
- package/template/apps/platform/src/routes/_public/examples/ssr-orpc.tsx +92 -75
- package/template/apps/platform/src/routes/_public/index.tsx +22 -19
- package/template/apps/platform/src/routes/_public/login.tsx +4 -4
- package/template/apps/platform/src/routes/_public/signup.tsx +6 -5
- package/template/apps/platform/src/routes/_public.tsx +5 -5
- package/template/apps/platform/src/routes/api/auth/$.ts +13 -13
- package/template/apps/platform/src/routes/api/rpc.$.ts +13 -13
- package/template/apps/platform/tsconfig.json +1 -1
- package/template/apps/platform/vite.config.ts +8 -8
- package/template/docker-compose.yml +1 -1
- package/template/package.json +24 -22
- package/template/packages/auth/package.json +8 -12
- package/template/packages/auth/src/lib/auth.ts +1 -1
- package/template/packages/auth/tsconfig.json +1 -1
- package/template/packages/db/package.json +6 -10
- package/template/packages/db/src/index.ts +4 -4
- package/template/packages/db/src/schema.ts +2 -2
- package/template/packages/db/tsconfig.json +1 -1
- package/template/packages/orpc/package.json +6 -10
- package/template/packages/orpc/src/lib/planets.ts +39 -43
- package/template/packages/orpc/src/lib/router.ts +15 -15
- package/template/packages/orpc/tsconfig.json +1 -1
- package/template/packages/ui/package.json +8 -12
- package/template/packages/ui/src/components/accordion.tsx +20 -22
- package/template/packages/ui/src/components/alert-dialog.tsx +31 -56
- package/template/packages/ui/src/components/alert.tsx +15 -23
- package/template/packages/ui/src/components/aspect-ratio.tsx +3 -3
- package/template/packages/ui/src/components/avatar.tsx +19 -35
- package/template/packages/ui/src/components/badge.tsx +13 -17
- package/template/packages/ui/src/components/breadcrumb.tsx +22 -44
- package/template/packages/ui/src/components/button-group.tsx +16 -25
- package/template/packages/ui/src/components/button.tsx +8 -9
- package/template/packages/ui/src/components/calendar.tsx +43 -82
- package/template/packages/ui/src/components/card.tsx +15 -26
- package/template/packages/ui/src/components/carousel.tsx +70 -78
- package/template/packages/ui/src/components/chart.tsx +84 -117
- package/template/packages/ui/src/components/checkbox.tsx +8 -9
- package/template/packages/ui/src/components/collapsible.tsx +5 -9
- package/template/packages/ui/src/components/combobox.tsx +44 -68
- package/template/packages/ui/src/components/command.tsx +32 -47
- package/template/packages/ui/src/components/context-menu.tsx +45 -71
- package/template/packages/ui/src/components/dialog.tsx +29 -51
- package/template/packages/ui/src/components/direction.tsx +1 -4
- package/template/packages/ui/src/components/drawer.tsx +24 -38
- package/template/packages/ui/src/components/dropdown-menu.tsx +45 -55
- package/template/packages/ui/src/components/empty.tsx +16 -27
- package/template/packages/ui/src/components/field.tsx +49 -63
- package/template/packages/ui/src/components/hover-card.tsx +9 -14
- package/template/packages/ui/src/components/input-group.tsx +40 -52
- package/template/packages/ui/src/components/input-otp.tsx +17 -18
- package/template/packages/ui/src/components/input.tsx +6 -6
- package/template/packages/ui/src/components/item.tsx +31 -44
- package/template/packages/ui/src/components/kbd.tsx +5 -5
- package/template/packages/ui/src/components/label.tsx +6 -6
- package/template/packages/ui/src/components/menubar.tsx +51 -64
- package/template/packages/ui/src/components/mode-toggle.tsx +9 -15
- package/template/packages/ui/src/components/native-select.tsx +18 -24
- package/template/packages/ui/src/components/navigation-menu.tsx +28 -35
- package/template/packages/ui/src/components/pagination.tsx +19 -31
- package/template/packages/ui/src/components/popover.tsx +13 -26
- package/template/packages/ui/src/components/progress.tsx +13 -30
- package/template/packages/ui/src/components/radio-group.tsx +7 -7
- package/template/packages/ui/src/components/resizable.tsx +12 -20
- package/template/packages/ui/src/components/scroll-area.tsx +8 -12
- package/template/packages/ui/src/components/select.tsx +31 -42
- package/template/packages/ui/src/components/separator.tsx +6 -10
- package/template/packages/ui/src/components/sheet.tsx +25 -38
- package/template/packages/ui/src/components/sidebar.tsx +137 -170
- package/template/packages/ui/src/components/skeleton.tsx +3 -3
- package/template/packages/ui/src/components/slider.tsx +5 -5
- package/template/packages/ui/src/components/sonner.tsx +20 -24
- package/template/packages/ui/src/components/spinner.tsx +10 -5
- package/template/packages/ui/src/components/switch.tsx +6 -6
- package/template/packages/ui/src/components/table.tsx +18 -45
- package/template/packages/ui/src/components/tabs.tsx +14 -22
- package/template/packages/ui/src/components/textarea.tsx +5 -5
- package/template/packages/ui/src/components/theme-provider.tsx +43 -48
- package/template/packages/ui/src/components/toggle-group.tsx +18 -20
- package/template/packages/ui/src/components/toggle.tsx +9 -10
- package/template/packages/ui/src/components/tooltip.tsx +10 -22
- package/template/packages/ui/src/hooks/use-mobile.ts +11 -11
- package/template/packages/ui/src/lib/utils.ts +4 -4
- package/template/packages/ui/src/styles/globals.css +106 -106
- package/template/packages/ui/tsconfig.json +1 -1
- package/template/turbo.json +15 -6
- package/template/.prettierignore +0 -10
- package/template/apps/desktop/.prettierignore +0 -6
- package/template/apps/desktop/eslint.config.ts +0 -11
- package/template/apps/desktop/prettier.config.ts +0 -3
- package/template/apps/mobile/eslint.config.js +0 -10
- package/template/apps/platform/eslint.config.ts +0 -11
- package/template/apps/platform/prettier.config.ts +0 -3
- package/template/packages/auth/eslint.config.ts +0 -3
- package/template/packages/auth/prettier.config.ts +0 -3
- package/template/packages/config-eslint/index.ts +0 -24
- package/template/packages/config-eslint/package.json +0 -11
- package/template/packages/config-prettier/index.ts +0 -14
- package/template/packages/config-prettier/package.json +0 -7
- package/template/packages/db/eslint.config.ts +0 -3
- package/template/packages/db/prettier.config.ts +0 -3
- package/template/packages/orpc/eslint.config.ts +0 -3
- package/template/packages/orpc/prettier.config.ts +0 -3
- package/template/packages/ui/eslint.config.ts +0 -3
- package/template/packages/ui/prettier.config.ts +0 -3
- package/template/prettier.config.ts +0 -15
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { createFileRoute, useRouter } from "@tanstack/react-router"
|
|
3
|
-
import { createServerFn } from "@tanstack/react-start"
|
|
4
|
-
import { Check, Pencil, Plus, Trash2 } from "lucide-react"
|
|
5
|
-
import { toast } from "sonner"
|
|
6
|
-
import { useForm } from "@tanstack/react-form"
|
|
7
|
-
import { type } from "arktype"
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { createFileRoute, useRouter } from "@tanstack/react-router";
|
|
3
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
4
|
+
import { Check, Pencil, Plus, Trash2 } from "lucide-react";
|
|
5
|
+
import { toast } from "sonner";
|
|
6
|
+
import { useForm } from "@tanstack/react-form";
|
|
7
|
+
import { type } from "arktype";
|
|
8
8
|
|
|
9
|
-
import { Button } from "@workspace/ui/components/button"
|
|
10
|
-
import { Input } from "@workspace/ui/components/input"
|
|
11
|
-
import {
|
|
12
|
-
Field,
|
|
13
|
-
FieldError,
|
|
14
|
-
FieldLabel,
|
|
15
|
-
} from "@workspace/ui/components/field"
|
|
9
|
+
import { Button } from "@workspace/ui/components/button";
|
|
10
|
+
import { Input } from "@workspace/ui/components/input";
|
|
11
|
+
import { Field, FieldError, FieldLabel } from "@workspace/ui/components/field";
|
|
16
12
|
|
|
17
|
-
import type { router } from "@workspace/orpc/router"
|
|
18
|
-
import type { InferRouterOutputs } from "@orpc/server"
|
|
19
|
-
import { orpc } from "@/lib/orpc"
|
|
13
|
+
import type { router } from "@workspace/orpc/router";
|
|
14
|
+
import type { InferRouterOutputs } from "@orpc/server";
|
|
15
|
+
import { orpc } from "@/lib/orpc";
|
|
20
16
|
|
|
21
|
-
type Outputs = InferRouterOutputs<typeof router
|
|
22
|
-
type Planet = Outputs["planets"]["getPlanets"][number]
|
|
17
|
+
type Outputs = InferRouterOutputs<typeof router>;
|
|
18
|
+
type Planet = Outputs["planets"]["getPlanets"][number];
|
|
23
19
|
|
|
24
20
|
const planetSchema = type({
|
|
25
21
|
name: "string>0",
|
|
@@ -28,18 +24,18 @@ const planetSchema = type({
|
|
|
28
24
|
diameter: "string",
|
|
29
25
|
}).narrow((data, ctx) => {
|
|
30
26
|
if (isNaN(parseFloat(data.distance))) {
|
|
31
|
-
ctx.error({ message: "Must be a number", path: ["distance"] })
|
|
27
|
+
ctx.error({ message: "Must be a number", path: ["distance"] });
|
|
32
28
|
}
|
|
33
29
|
if (isNaN(parseFloat(data.diameter))) {
|
|
34
|
-
ctx.error({ message: "Must be a number", path: ["diameter"] })
|
|
30
|
+
ctx.error({ message: "Must be a number", path: ["diameter"] });
|
|
35
31
|
}
|
|
36
|
-
return true
|
|
37
|
-
})
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
38
34
|
|
|
39
35
|
const getPlanets = createServerFn({ method: "GET" }).handler(async () => {
|
|
40
|
-
const planets = await orpc.planets.getPlanets()
|
|
41
|
-
return { planets }
|
|
42
|
-
})
|
|
36
|
+
const planets = await orpc.planets.getPlanets();
|
|
37
|
+
return { planets };
|
|
38
|
+
});
|
|
43
39
|
|
|
44
40
|
export const Route = createFileRoute("/_public/examples/ssr-orpc")({
|
|
45
41
|
head: () => ({
|
|
@@ -49,20 +45,19 @@ export const Route = createFileRoute("/_public/examples/ssr-orpc")({
|
|
|
49
45
|
},
|
|
50
46
|
{
|
|
51
47
|
name: "description",
|
|
52
|
-
content:
|
|
53
|
-
"Learn how to use Server-Side Rendering (SSR) with oRPC in Croissant Stack.",
|
|
48
|
+
content: "Learn how to use Server-Side Rendering (SSR) with oRPC in Croissant Stack.",
|
|
54
49
|
},
|
|
55
50
|
],
|
|
56
51
|
}),
|
|
57
52
|
loader: () => getPlanets(),
|
|
58
53
|
component: SSRORPC,
|
|
59
|
-
})
|
|
54
|
+
});
|
|
60
55
|
|
|
61
56
|
function SSRORPC() {
|
|
62
|
-
const { planets } = Route.useLoaderData()
|
|
63
|
-
const router = useRouter()
|
|
64
|
-
const [editingId, setEditingId] = React.useState<number | null>(null)
|
|
65
|
-
|
|
57
|
+
const { planets } = Route.useLoaderData();
|
|
58
|
+
const router = useRouter();
|
|
59
|
+
const [editingId, setEditingId] = React.useState<number | null>(null);
|
|
60
|
+
|
|
66
61
|
const form = useForm({
|
|
67
62
|
defaultValues: {
|
|
68
63
|
name: "",
|
|
@@ -74,7 +69,7 @@ function SSRORPC() {
|
|
|
74
69
|
onChange: planetSchema,
|
|
75
70
|
},
|
|
76
71
|
onSubmit: async ({ value }) => {
|
|
77
|
-
const toastId = toast.loading(editingId ? "Updating planet..." : "Adding planet...")
|
|
72
|
+
const toastId = toast.loading(editingId ? "Updating planet..." : "Adding planet...");
|
|
78
73
|
try {
|
|
79
74
|
if (editingId) {
|
|
80
75
|
await orpc.planets.updatePlanet({
|
|
@@ -84,8 +79,8 @@ function SSRORPC() {
|
|
|
84
79
|
distanceFromSun: parseFloat(value.distance),
|
|
85
80
|
diameter: parseFloat(value.diameter),
|
|
86
81
|
hasRings: false,
|
|
87
|
-
})
|
|
88
|
-
toast.success("Planet updated successfully", { id: toastId })
|
|
82
|
+
});
|
|
83
|
+
toast.success("Planet updated successfully", { id: toastId });
|
|
89
84
|
} else {
|
|
90
85
|
await orpc.planets.createPlanet({
|
|
91
86
|
name: value.name,
|
|
@@ -93,49 +88,51 @@ function SSRORPC() {
|
|
|
93
88
|
distanceFromSun: parseFloat(value.distance),
|
|
94
89
|
diameter: parseFloat(value.diameter),
|
|
95
90
|
hasRings: false,
|
|
96
|
-
})
|
|
97
|
-
toast.success("Planet added successfully", { id: toastId })
|
|
91
|
+
});
|
|
92
|
+
toast.success("Planet added successfully", { id: toastId });
|
|
98
93
|
}
|
|
99
|
-
await router.invalidate()
|
|
100
|
-
resetForm()
|
|
94
|
+
await router.invalidate();
|
|
95
|
+
resetForm();
|
|
101
96
|
} catch (err: any) {
|
|
102
|
-
console.error(err)
|
|
103
|
-
toast.error(err.message || "Operation failed", { id: toastId })
|
|
97
|
+
console.error(err);
|
|
98
|
+
toast.error(err.message || "Operation failed", { id: toastId });
|
|
104
99
|
}
|
|
105
100
|
},
|
|
106
|
-
})
|
|
101
|
+
});
|
|
107
102
|
|
|
108
103
|
const resetForm = () => {
|
|
109
|
-
form.reset()
|
|
110
|
-
setEditingId(null)
|
|
111
|
-
}
|
|
104
|
+
form.reset();
|
|
105
|
+
setEditingId(null);
|
|
106
|
+
};
|
|
112
107
|
|
|
113
108
|
const handleDelete = async (id: number) => {
|
|
114
|
-
if (!confirm("Are you sure you want to delete this planet?")) return
|
|
115
|
-
const toastId = toast.loading("Deleting planet...")
|
|
109
|
+
if (!confirm("Are you sure you want to delete this planet?")) return;
|
|
110
|
+
const toastId = toast.loading("Deleting planet...");
|
|
116
111
|
try {
|
|
117
|
-
await orpc.planets.deletePlanet({ id })
|
|
118
|
-
await router.invalidate()
|
|
119
|
-
toast.success("Planet deleted successfully", { id: toastId })
|
|
112
|
+
await orpc.planets.deletePlanet({ id });
|
|
113
|
+
await router.invalidate();
|
|
114
|
+
toast.success("Planet deleted successfully", { id: toastId });
|
|
120
115
|
} catch (err: any) {
|
|
121
|
-
console.error(err)
|
|
122
|
-
toast.error(err.message || "Failed to delete planet", { id: toastId })
|
|
116
|
+
console.error(err);
|
|
117
|
+
toast.error(err.message || "Failed to delete planet", { id: toastId });
|
|
123
118
|
}
|
|
124
|
-
}
|
|
119
|
+
};
|
|
125
120
|
|
|
126
121
|
const startEdit = (planet: Planet) => {
|
|
127
|
-
setEditingId(planet.id)
|
|
128
|
-
form.setFieldValue("name", planet.name)
|
|
129
|
-
form.setFieldValue("description", planet.description || "")
|
|
130
|
-
form.setFieldValue("distance", planet.distanceFromSun.toString())
|
|
131
|
-
form.setFieldValue("diameter", planet.diameter.toString())
|
|
132
|
-
}
|
|
122
|
+
setEditingId(planet.id);
|
|
123
|
+
form.setFieldValue("name", planet.name);
|
|
124
|
+
form.setFieldValue("description", planet.description || "");
|
|
125
|
+
form.setFieldValue("distance", planet.distanceFromSun.toString());
|
|
126
|
+
form.setFieldValue("diameter", planet.diameter.toString());
|
|
127
|
+
};
|
|
133
128
|
|
|
134
129
|
return (
|
|
135
130
|
<div className="flex flex-col gap-8">
|
|
136
131
|
<div>
|
|
137
132
|
<h1 className="text-2xl font-bold mb-2">SSR + oRPC CRUD</h1>
|
|
138
|
-
<p className="text-muted-foreground">
|
|
133
|
+
<p className="text-muted-foreground">
|
|
134
|
+
Manage planets using SSR loaders for fetching and oRPC mutations for actions.
|
|
135
|
+
</p>
|
|
139
136
|
</div>
|
|
140
137
|
|
|
141
138
|
<div className="rounded-lg border p-6 bg-muted/30">
|
|
@@ -145,16 +142,18 @@ function SSRORPC() {
|
|
|
145
142
|
</h2>
|
|
146
143
|
<form
|
|
147
144
|
onSubmit={(e) => {
|
|
148
|
-
e.preventDefault()
|
|
149
|
-
e.stopPropagation()
|
|
150
|
-
form.handleSubmit()
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
e.stopPropagation();
|
|
147
|
+
form.handleSubmit();
|
|
151
148
|
}}
|
|
152
149
|
>
|
|
153
150
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
154
151
|
<form.Field
|
|
155
152
|
name="name"
|
|
156
153
|
children={(field) => (
|
|
157
|
-
<Field
|
|
154
|
+
<Field
|
|
155
|
+
data-invalid={field.state.meta.isTouched && field.state.meta.errors.length > 0}
|
|
156
|
+
>
|
|
158
157
|
<FieldLabel htmlFor={field.name}>Name</FieldLabel>
|
|
159
158
|
<Input
|
|
160
159
|
id={field.name}
|
|
@@ -171,7 +170,9 @@ function SSRORPC() {
|
|
|
171
170
|
<form.Field
|
|
172
171
|
name="description"
|
|
173
172
|
children={(field) => (
|
|
174
|
-
<Field
|
|
173
|
+
<Field
|
|
174
|
+
data-invalid={field.state.meta.isTouched && field.state.meta.errors.length > 0}
|
|
175
|
+
>
|
|
175
176
|
<FieldLabel htmlFor={field.name}>Description</FieldLabel>
|
|
176
177
|
<Input
|
|
177
178
|
id={field.name}
|
|
@@ -188,7 +189,9 @@ function SSRORPC() {
|
|
|
188
189
|
<form.Field
|
|
189
190
|
name="distance"
|
|
190
191
|
children={(field) => (
|
|
191
|
-
<Field
|
|
192
|
+
<Field
|
|
193
|
+
data-invalid={field.state.meta.isTouched && field.state.meta.errors.length > 0}
|
|
194
|
+
>
|
|
192
195
|
<FieldLabel htmlFor={field.name}>Distance (M km)</FieldLabel>
|
|
193
196
|
<Input
|
|
194
197
|
id={field.name}
|
|
@@ -205,7 +208,9 @@ function SSRORPC() {
|
|
|
205
208
|
<form.Field
|
|
206
209
|
name="diameter"
|
|
207
210
|
children={(field) => (
|
|
208
|
-
<Field
|
|
211
|
+
<Field
|
|
212
|
+
data-invalid={field.state.meta.isTouched && field.state.meta.errors.length > 0}
|
|
213
|
+
>
|
|
209
214
|
<FieldLabel htmlFor={field.name}>Diameter (km)</FieldLabel>
|
|
210
215
|
<Input
|
|
211
216
|
id={field.name}
|
|
@@ -227,19 +232,24 @@ function SSRORPC() {
|
|
|
227
232
|
<>
|
|
228
233
|
{editingId ? (
|
|
229
234
|
<>
|
|
230
|
-
<Button
|
|
235
|
+
<Button
|
|
231
236
|
type="submit"
|
|
232
237
|
className="flex items-center gap-2"
|
|
233
238
|
disabled={!canSubmit || isSubmitting}
|
|
234
239
|
>
|
|
235
240
|
<Check className="h-4 w-4" /> {isSubmitting ? "Saving..." : "Save Changes"}
|
|
236
241
|
</Button>
|
|
237
|
-
<Button
|
|
242
|
+
<Button
|
|
243
|
+
variant="outline"
|
|
244
|
+
type="button"
|
|
245
|
+
onClick={resetForm}
|
|
246
|
+
disabled={isSubmitting}
|
|
247
|
+
>
|
|
238
248
|
Cancel
|
|
239
249
|
</Button>
|
|
240
250
|
</>
|
|
241
251
|
) : (
|
|
242
|
-
<Button
|
|
252
|
+
<Button
|
|
243
253
|
type="submit"
|
|
244
254
|
className="flex items-center gap-2"
|
|
245
255
|
disabled={!canSubmit || isSubmitting}
|
|
@@ -261,13 +271,20 @@ function SSRORPC() {
|
|
|
261
271
|
) : (
|
|
262
272
|
<div className="grid grid-cols-1 gap-3">
|
|
263
273
|
{planets.map((planet) => (
|
|
264
|
-
<div
|
|
274
|
+
<div
|
|
275
|
+
key={planet.id}
|
|
276
|
+
className="flex items-center justify-between rounded-lg border p-4 bg-background shadow-sm hover:shadow-md transition-shadow"
|
|
277
|
+
>
|
|
265
278
|
<div className="flex-1">
|
|
266
279
|
<div className="flex items-center gap-2">
|
|
267
280
|
<span className="font-bold text-lg">{planet.name}</span>
|
|
268
|
-
<span className="text-xs bg-muted px-2 py-0.5 rounded-full text-muted-foreground">
|
|
281
|
+
<span className="text-xs bg-muted px-2 py-0.5 rounded-full text-muted-foreground">
|
|
282
|
+
ID: {planet.id}
|
|
283
|
+
</span>
|
|
269
284
|
</div>
|
|
270
|
-
<p className="text-sm text-muted-foreground">
|
|
285
|
+
<p className="text-sm text-muted-foreground">
|
|
286
|
+
{planet.description || "No description provided."}
|
|
287
|
+
</p>
|
|
271
288
|
<div className="mt-2 flex gap-4 text-xs text-muted-foreground font-mono">
|
|
272
289
|
<span>Distance: {planet.distanceFromSun} M km</span>
|
|
273
290
|
<span>Diameter: {planet.diameter} km</span>
|
|
@@ -287,5 +304,5 @@ function SSRORPC() {
|
|
|
287
304
|
)}
|
|
288
305
|
</div>
|
|
289
306
|
</div>
|
|
290
|
-
)
|
|
307
|
+
);
|
|
291
308
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Link, createFileRoute } from "@tanstack/react-router"
|
|
2
|
-
import { createServerFn } from "@tanstack/react-start"
|
|
3
|
-
import { Button } from "@workspace/ui/components/button"
|
|
4
|
-
import type { router } from "@workspace/orpc/router"
|
|
5
|
-
import type { InferRouterOutputs } from "@orpc/server"
|
|
6
|
-
import { orpc } from "@/lib/orpc"
|
|
1
|
+
import { Link, createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
3
|
+
import { Button } from "@workspace/ui/components/button";
|
|
4
|
+
import type { router } from "@workspace/orpc/router";
|
|
5
|
+
import type { InferRouterOutputs } from "@orpc/server";
|
|
6
|
+
import { orpc } from "@/lib/orpc";
|
|
7
7
|
|
|
8
|
-
type Outputs = InferRouterOutputs<typeof router
|
|
9
|
-
type Planet = Outputs["planets"]["getPlanets"][number]
|
|
8
|
+
type Outputs = InferRouterOutputs<typeof router>;
|
|
9
|
+
type Planet = Outputs["planets"]["getPlanets"][number];
|
|
10
10
|
|
|
11
11
|
const getHomeData = createServerFn({ method: "GET" }).handler(async () => {
|
|
12
12
|
const [helloRes, planets] = await Promise.all([
|
|
13
13
|
orpc.hello({ name: "Croissant Stack" }),
|
|
14
14
|
orpc.planets.getPlanets(),
|
|
15
|
-
])
|
|
15
|
+
]);
|
|
16
16
|
return {
|
|
17
17
|
message: helloRes.message,
|
|
18
18
|
planets,
|
|
19
|
-
}
|
|
20
|
-
})
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
21
|
|
|
22
22
|
export const Route = createFileRoute("/_public/")({
|
|
23
23
|
head: () => ({
|
|
@@ -46,26 +46,29 @@ export const Route = createFileRoute("/_public/")({
|
|
|
46
46
|
}),
|
|
47
47
|
loader: () => getHomeData(),
|
|
48
48
|
headers: () => ({
|
|
49
|
-
"Cache-Control":
|
|
50
|
-
"public, max-age=10, s-maxage=10, stale-while-revalidate=60",
|
|
49
|
+
"Cache-Control": "public, max-age=10, s-maxage=10, stale-while-revalidate=60",
|
|
51
50
|
}),
|
|
52
51
|
component: App,
|
|
53
|
-
})
|
|
52
|
+
});
|
|
54
53
|
|
|
55
54
|
function App() {
|
|
56
|
-
const { message, planets } = Route.useLoaderData()
|
|
55
|
+
const { message, planets } = Route.useLoaderData();
|
|
57
56
|
|
|
58
57
|
return (
|
|
59
58
|
<div className="flex min-h-svh p-6">
|
|
60
59
|
<div className="flex max-w-lg min-w-0 flex-col gap-4 text-sm leading-loose">
|
|
61
60
|
<div>
|
|
62
61
|
<h1 className="font-medium text-2xl mb-4">Project ready!</h1>
|
|
63
|
-
<p>
|
|
64
|
-
|
|
62
|
+
<p>
|
|
63
|
+
oRPC integration: <span className="font-bold">{message}</span>
|
|
64
|
+
</p>
|
|
65
|
+
|
|
65
66
|
<div className="mt-8">
|
|
66
67
|
<h2 className="text-xl font-semibold mb-2">Planets from Database:</h2>
|
|
67
68
|
{planets.length === 0 ? (
|
|
68
|
-
<p className="text-gray-500 italic">
|
|
69
|
+
<p className="text-gray-500 italic">
|
|
70
|
+
No planets found in the database. Run `db:push` and seed data if needed.
|
|
71
|
+
</p>
|
|
69
72
|
) : (
|
|
70
73
|
<ul className="grid grid-cols-1 gap-2">
|
|
71
74
|
{planets.map((planet: Planet) => (
|
|
@@ -89,5 +92,5 @@ function App() {
|
|
|
89
92
|
</div>
|
|
90
93
|
</div>
|
|
91
94
|
</div>
|
|
92
|
-
)
|
|
95
|
+
);
|
|
93
96
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createFileRoute } from "@tanstack/react-router"
|
|
2
|
-
import { LoginForm } from "@/components/login-form"
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { LoginForm } from "@/components/login-form";
|
|
3
3
|
|
|
4
4
|
export const Route = createFileRoute("/_public/login")({
|
|
5
5
|
head: () => ({
|
|
@@ -21,7 +21,7 @@ export const Route = createFileRoute("/_public/login")({
|
|
|
21
21
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400",
|
|
22
22
|
}),
|
|
23
23
|
component: Login,
|
|
24
|
-
})
|
|
24
|
+
});
|
|
25
25
|
|
|
26
26
|
function Login() {
|
|
27
27
|
return (
|
|
@@ -30,5 +30,5 @@ function Login() {
|
|
|
30
30
|
<LoginForm />
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
|
-
)
|
|
33
|
+
);
|
|
34
34
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createFileRoute } from "@tanstack/react-router"
|
|
2
|
-
import { SignupForm } from "@/components/signup-form"
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { SignupForm } from "@/components/signup-form";
|
|
3
3
|
|
|
4
4
|
export const Route = createFileRoute("/_public/signup")({
|
|
5
5
|
head: () => ({
|
|
@@ -9,7 +9,8 @@ export const Route = createFileRoute("/_public/signup")({
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
name: "description",
|
|
12
|
-
content:
|
|
12
|
+
content:
|
|
13
|
+
"Join Croissant Stack today. Create an account to start building with the best stack.",
|
|
13
14
|
},
|
|
14
15
|
],
|
|
15
16
|
}),
|
|
@@ -17,7 +18,7 @@ export const Route = createFileRoute("/_public/signup")({
|
|
|
17
18
|
"Cache-Control": "public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400",
|
|
18
19
|
}),
|
|
19
20
|
component: Signup,
|
|
20
|
-
})
|
|
21
|
+
});
|
|
21
22
|
|
|
22
23
|
function Signup() {
|
|
23
24
|
return (
|
|
@@ -26,5 +27,5 @@ function Signup() {
|
|
|
26
27
|
<SignupForm />
|
|
27
28
|
</div>
|
|
28
29
|
</div>
|
|
29
|
-
)
|
|
30
|
+
);
|
|
30
31
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Outlet, createFileRoute } from "@tanstack/react-router"
|
|
2
|
-
import { SidebarProvider, SidebarTrigger } from "@workspace/ui/components/sidebar"
|
|
3
|
-
import { PublicSidebar } from "@/components/app-sidebar"
|
|
1
|
+
import { Outlet, createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { SidebarProvider, SidebarTrigger } from "@workspace/ui/components/sidebar";
|
|
3
|
+
import { PublicSidebar } from "@/components/app-sidebar";
|
|
4
4
|
|
|
5
5
|
export const Route = createFileRoute("/_public")({
|
|
6
6
|
component: PublicLayout,
|
|
7
|
-
})
|
|
7
|
+
});
|
|
8
8
|
|
|
9
9
|
function PublicLayout() {
|
|
10
10
|
return (
|
|
@@ -19,5 +19,5 @@ function PublicLayout() {
|
|
|
19
19
|
</div>
|
|
20
20
|
</main>
|
|
21
21
|
</SidebarProvider>
|
|
22
|
-
)
|
|
22
|
+
);
|
|
23
23
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { auth } from
|
|
2
|
-
import { createFileRoute } from
|
|
1
|
+
import { auth } from "@workspace/auth/lib/auth";
|
|
2
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
3
3
|
|
|
4
|
-
export const Route = createFileRoute(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
},
|
|
4
|
+
export const Route = createFileRoute("/api/auth/$")({
|
|
5
|
+
server: {
|
|
6
|
+
handlers: {
|
|
7
|
+
GET: async ({ request }: { request: Request }) => {
|
|
8
|
+
return await auth.handler(request);
|
|
9
|
+
},
|
|
10
|
+
POST: async ({ request }: { request: Request }) => {
|
|
11
|
+
return await auth.handler(request);
|
|
12
|
+
},
|
|
14
13
|
},
|
|
15
|
-
}
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { RPCHandler } from
|
|
2
|
-
import { createFileRoute } from
|
|
3
|
-
import { onError } from
|
|
4
|
-
import { router } from
|
|
5
|
-
import { auth } from
|
|
1
|
+
import { RPCHandler } from "@orpc/server/fetch";
|
|
2
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
3
|
+
import { onError } from "@orpc/server";
|
|
4
|
+
import { router } from "@workspace/orpc/router";
|
|
5
|
+
import { auth } from "@workspace/auth/lib/auth";
|
|
6
6
|
|
|
7
7
|
const handler = new RPCHandler(router, {
|
|
8
8
|
interceptors: [
|
|
9
9
|
onError((error) => {
|
|
10
|
-
console.error(error)
|
|
10
|
+
console.error(error);
|
|
11
11
|
}),
|
|
12
12
|
],
|
|
13
|
-
})
|
|
13
|
+
});
|
|
14
14
|
|
|
15
|
-
export const Route = createFileRoute(
|
|
15
|
+
export const Route = createFileRoute("/api/rpc/$")({
|
|
16
16
|
server: {
|
|
17
17
|
handlers: {
|
|
18
18
|
ANY: async ({ request }) => {
|
|
19
19
|
const session = await auth.api.getSession({
|
|
20
20
|
headers: request.headers,
|
|
21
|
-
})
|
|
21
|
+
});
|
|
22
22
|
|
|
23
23
|
const { response } = await handler.handle(request, {
|
|
24
|
-
prefix:
|
|
24
|
+
prefix: "/api/rpc",
|
|
25
25
|
context: {
|
|
26
26
|
session,
|
|
27
27
|
},
|
|
28
|
-
})
|
|
28
|
+
});
|
|
29
29
|
|
|
30
|
-
return response ?? new Response(
|
|
30
|
+
return response ?? new Response("Not Found", { status: 404 });
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
-
})
|
|
34
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "@workspace/config-typescript/react.json",
|
|
3
|
-
"include": ["**/*.ts", "**/*.tsx", "vite.config.ts"
|
|
3
|
+
"include": ["**/*.ts", "**/*.tsx", "vite.config.ts"],
|
|
4
4
|
"compilerOptions": {
|
|
5
5
|
"target": "ES2022",
|
|
6
6
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { defineConfig } from "vite"
|
|
2
|
-
import { tanstackStart } from "@tanstack/react-start/plugin/vite"
|
|
3
|
-
import viteReact from "@vitejs/plugin-react"
|
|
4
|
-
import tailwindcss from "@tailwindcss/vite"
|
|
5
|
-
import { nitro } from "nitro/vite"
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
3
|
+
import viteReact from "@vitejs/plugin-react";
|
|
4
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
5
|
+
import { nitro } from "nitro/vite";
|
|
6
6
|
|
|
7
7
|
const config = defineConfig({
|
|
8
8
|
plugins: [
|
|
@@ -18,7 +18,7 @@ const config = defineConfig({
|
|
|
18
18
|
],
|
|
19
19
|
resolve: {
|
|
20
20
|
tsconfigPaths: true,
|
|
21
|
-
}
|
|
22
|
-
})
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
23
|
|
|
24
|
-
export default config
|
|
24
|
+
export default config;
|
package/template/package.json
CHANGED
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
"name": "croissant-stack",
|
|
3
3
|
"version": "0.0.1",
|
|
4
4
|
"private": true,
|
|
5
|
+
"workspaces": [
|
|
6
|
+
"apps/*",
|
|
7
|
+
"packages/*"
|
|
8
|
+
],
|
|
5
9
|
"scripts": {
|
|
6
10
|
"build": "turbo build",
|
|
7
11
|
"dev": "turbo dev",
|
|
8
|
-
"lint": "
|
|
9
|
-
"
|
|
12
|
+
"lint": "oxlint --ignore-path .oxlintignore .",
|
|
13
|
+
"lint:fix": "oxlint --fix --ignore-path .oxlintignore .",
|
|
14
|
+
"format": "oxfmt --check --ignore-path .oxlintignore",
|
|
15
|
+
"format:fix": "oxfmt --ignore-path .oxlintignore .",
|
|
16
|
+
"quality": "turbo quality",
|
|
17
|
+
"quality:fix": "turbo quality:fix",
|
|
10
18
|
"typecheck": "turbo typecheck",
|
|
11
19
|
"ci": "npm run lint && npm run typecheck && npm run build",
|
|
12
20
|
"db:up": "docker compose up -d",
|
|
@@ -21,32 +29,26 @@
|
|
|
21
29
|
},
|
|
22
30
|
"devDependencies": {
|
|
23
31
|
"@better-auth/core": "^1.6.9",
|
|
24
|
-
"@
|
|
32
|
+
"@types/react": "^19.2.7",
|
|
33
|
+
"@types/react-dom": "^19.2.3",
|
|
25
34
|
"arktype": "^2.2.0",
|
|
26
|
-
"
|
|
35
|
+
"expo": "^55.0.17",
|
|
36
|
+
"expo-router": "~55.0.13",
|
|
27
37
|
"husky": "^9.1.7",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
38
|
+
"oxfmt": "^0.46.0",
|
|
39
|
+
"oxlint": "^1.61.0",
|
|
30
40
|
"turbo": "^2.9.6",
|
|
31
41
|
"typescript": "6.0.3",
|
|
32
|
-
"vite": "^8.0.10"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"@
|
|
36
|
-
"
|
|
42
|
+
"vite": "^8.0.10"
|
|
43
|
+
},
|
|
44
|
+
"overrides": {
|
|
45
|
+
"@noble/ciphers": "2.2.0",
|
|
46
|
+
"drizzle-orm": "^0.45.2",
|
|
47
|
+
"react": "19.2.5",
|
|
48
|
+
"react-dom": "19.2.5"
|
|
37
49
|
},
|
|
38
|
-
"packageManager": "npm@11.13.0",
|
|
39
50
|
"engines": {
|
|
40
51
|
"node": ">=20"
|
|
41
52
|
},
|
|
42
|
-
"
|
|
43
|
-
"apps/*",
|
|
44
|
-
"packages/*"
|
|
45
|
-
],
|
|
46
|
-
"overrides": {
|
|
47
|
-
"react": "19.2.5",
|
|
48
|
-
"react-dom": "19.2.5",
|
|
49
|
-
"@noble/ciphers": "2.2.0",
|
|
50
|
-
"drizzle-orm": "^0.45.2"
|
|
51
|
-
}
|
|
53
|
+
"packageManager": "npm@11.13.0"
|
|
52
54
|
}
|