create-croissant 0.1.24 → 0.1.25
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 +1 -1
- package/template/apps/web/src/components/app-sidebar.tsx +7 -7
- package/template/apps/web/src/routes/_auth/examples/ssr-orpc-auth.tsx +11 -8
- package/template/apps/web/src/routes/_public/examples/isr.tsx +17 -12
- package/template/apps/web/src/routes/_public/examples/ssr-orpc.tsx +9 -5
- package/template/apps/web/src/routes/_public/index.tsx +17 -12
- package/template/packages/ui/src/components/sidebar.tsx +11 -1
package/package.json
CHANGED
|
@@ -163,25 +163,25 @@ export function AppSidebar({ items = authNavItems, ...props }: AppSidebarProps)
|
|
|
163
163
|
<span className="truncate text-xs">{user.email}</span>
|
|
164
164
|
</div>
|
|
165
165
|
<div className="flex items-center gap-1 ml-auto">
|
|
166
|
-
<
|
|
167
|
-
to="/account"
|
|
168
|
-
className="p-1 rounded hover:bg-sidebar-accent-foreground/10"
|
|
166
|
+
<SidebarMenuButton
|
|
167
|
+
render={<Link to="/account" />}
|
|
168
|
+
className="p-1 h-auto w-auto rounded hover:bg-sidebar-accent-foreground/10"
|
|
169
169
|
title="Account Settings"
|
|
170
170
|
>
|
|
171
171
|
<Settings className="h-4 w-4" />
|
|
172
|
-
</
|
|
173
|
-
<
|
|
172
|
+
</SidebarMenuButton>
|
|
173
|
+
<SidebarMenuButton
|
|
174
174
|
onClick={async (e) => {
|
|
175
175
|
e.preventDefault()
|
|
176
176
|
e.stopPropagation()
|
|
177
177
|
await authClient.signOut()
|
|
178
178
|
window.location.reload()
|
|
179
179
|
}}
|
|
180
|
-
className="p-1 rounded hover:bg-sidebar-accent-foreground/10"
|
|
180
|
+
className="p-1 h-auto w-auto rounded hover:bg-sidebar-accent-foreground/10"
|
|
181
181
|
title="Sign Out"
|
|
182
182
|
>
|
|
183
183
|
<LogOut className="h-4 w-4" />
|
|
184
|
-
</
|
|
184
|
+
</SidebarMenuButton>
|
|
185
185
|
</div>
|
|
186
186
|
</div>
|
|
187
187
|
</SidebarMenuButton>
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { createFileRoute, redirect } from "@tanstack/react-router"
|
|
2
|
+
import { createServerFn } from "@tanstack/react-start"
|
|
2
3
|
import { getSessionFn } from "@/lib/auth-utils"
|
|
3
4
|
import { orpc } from "@/lib/orpc"
|
|
4
5
|
|
|
6
|
+
const getSecretData = createServerFn({ method: "GET" }).handler(async () => {
|
|
7
|
+
try {
|
|
8
|
+
const secretData = await orpc.getSecretData()
|
|
9
|
+
return { secretData }
|
|
10
|
+
} catch (err) {
|
|
11
|
+
return { secretData: null, error: "Failed to fetch secret data" }
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
|
|
5
15
|
export const Route = createFileRoute("/_auth/examples/ssr-orpc-auth")({
|
|
6
16
|
beforeLoad: async () => {
|
|
7
17
|
const session = await getSessionFn()
|
|
@@ -15,14 +25,7 @@ export const Route = createFileRoute("/_auth/examples/ssr-orpc-auth")({
|
|
|
15
25
|
}
|
|
16
26
|
return { session }
|
|
17
27
|
},
|
|
18
|
-
loader:
|
|
19
|
-
try {
|
|
20
|
-
const secretData = await orpc.getSecretData()
|
|
21
|
-
return { secretData }
|
|
22
|
-
} catch (err) {
|
|
23
|
-
return { secretData: null, error: "Failed to fetch secret data" }
|
|
24
|
-
}
|
|
25
|
-
},
|
|
28
|
+
loader: () => getSecretData(),
|
|
26
29
|
component: SSRORPCAuth,
|
|
27
30
|
})
|
|
28
31
|
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router"
|
|
2
|
+
import { createServerFn } from "@tanstack/react-start"
|
|
2
3
|
import { orpc } from "@/lib/orpc"
|
|
3
4
|
|
|
5
|
+
const getISRData = createServerFn({ method: "GET" }).handler(async () => {
|
|
6
|
+
// In a real ISR scenario, this would be cached on the server
|
|
7
|
+
// For this example, we'll fetch planets via oRPC
|
|
8
|
+
const planets = await orpc.planets.getPlanets()
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
generatedAt: new Date().toISOString(),
|
|
12
|
+
planets,
|
|
13
|
+
message:
|
|
14
|
+
"This page is an example of ISR. In a production build with proper configuration, this data would be cached and updated in the background.",
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
4
18
|
export const Route = createFileRoute("/_public/examples/isr")({
|
|
5
19
|
head: () => ({
|
|
6
20
|
meta: [
|
|
@@ -9,21 +23,12 @@ export const Route = createFileRoute("/_public/examples/isr")({
|
|
|
9
23
|
},
|
|
10
24
|
{
|
|
11
25
|
name: "description",
|
|
12
|
-
content:
|
|
26
|
+
content:
|
|
27
|
+
"Experience high-performance page loads with ISR in Croissant Stack.",
|
|
13
28
|
},
|
|
14
29
|
],
|
|
15
30
|
}),
|
|
16
|
-
loader:
|
|
17
|
-
// In a real ISR scenario, this would be cached on the server
|
|
18
|
-
// For this example, we'll fetch planets via oRPC
|
|
19
|
-
const planets = await orpc.planets.getPlanets()
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
generatedAt: new Date().toISOString(),
|
|
23
|
-
planets,
|
|
24
|
-
message: "This page is an example of ISR. In a production build with proper configuration, this data would be cached and updated in the background.",
|
|
25
|
-
}
|
|
26
|
-
},
|
|
31
|
+
loader: () => getISRData(),
|
|
27
32
|
headers: () => ({
|
|
28
33
|
// Cache at CDN for 10 seconds, allow stale content for up to 1 minute
|
|
29
34
|
"Cache-Control": "public, max-age=10, s-maxage=10, stale-while-revalidate=60",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
2
|
import { createFileRoute, useRouter } from "@tanstack/react-router"
|
|
3
|
+
import { createServerFn } from "@tanstack/react-start"
|
|
3
4
|
import { Check, Pencil, Plus, Trash2 } from "lucide-react"
|
|
4
5
|
import { toast } from "sonner"
|
|
5
6
|
import { useForm } from "@tanstack/react-form"
|
|
@@ -27,6 +28,11 @@ const planetSchema = z.object({
|
|
|
27
28
|
diameter: z.string().refine((val) => !isNaN(parseFloat(val)), "Must be a number"),
|
|
28
29
|
})
|
|
29
30
|
|
|
31
|
+
const getPlanets = createServerFn({ method: "GET" }).handler(async () => {
|
|
32
|
+
const planets = await orpc.planets.getPlanets()
|
|
33
|
+
return { planets }
|
|
34
|
+
})
|
|
35
|
+
|
|
30
36
|
export const Route = createFileRoute("/_public/examples/ssr-orpc")({
|
|
31
37
|
head: () => ({
|
|
32
38
|
meta: [
|
|
@@ -35,14 +41,12 @@ export const Route = createFileRoute("/_public/examples/ssr-orpc")({
|
|
|
35
41
|
},
|
|
36
42
|
{
|
|
37
43
|
name: "description",
|
|
38
|
-
content:
|
|
44
|
+
content:
|
|
45
|
+
"Learn how to use Server-Side Rendering (SSR) with oRPC in Croissant Stack.",
|
|
39
46
|
},
|
|
40
47
|
],
|
|
41
48
|
}),
|
|
42
|
-
loader:
|
|
43
|
-
const planets = await orpc.planets.getPlanets()
|
|
44
|
-
return { planets }
|
|
45
|
-
},
|
|
49
|
+
loader: () => getPlanets(),
|
|
46
50
|
component: SSRORPC,
|
|
47
51
|
})
|
|
48
52
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Link, createFileRoute } from "@tanstack/react-router"
|
|
2
|
+
import { createServerFn } from "@tanstack/react-start"
|
|
2
3
|
import { Button } from "@workspace/ui/components/button"
|
|
3
4
|
import type { router } from "@workspace/orpc/router"
|
|
4
5
|
import type { InferRouterOutputs } from "@orpc/server"
|
|
@@ -7,6 +8,17 @@ import { orpc } from "@/lib/orpc"
|
|
|
7
8
|
type Outputs = InferRouterOutputs<typeof router>
|
|
8
9
|
type Planet = Outputs["planets"]["getPlanets"][number]
|
|
9
10
|
|
|
11
|
+
const getHomeData = createServerFn({ method: "GET" }).handler(async () => {
|
|
12
|
+
const [helloRes, planets] = await Promise.all([
|
|
13
|
+
orpc.hello({ name: "Croissant Stack" }),
|
|
14
|
+
orpc.planets.getPlanets(),
|
|
15
|
+
])
|
|
16
|
+
return {
|
|
17
|
+
message: helloRes.message,
|
|
18
|
+
planets,
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
10
22
|
export const Route = createFileRoute("/_public/")({
|
|
11
23
|
head: () => ({
|
|
12
24
|
meta: [
|
|
@@ -15,7 +27,8 @@ export const Route = createFileRoute("/_public/")({
|
|
|
15
27
|
},
|
|
16
28
|
{
|
|
17
29
|
name: "description",
|
|
18
|
-
content:
|
|
30
|
+
content:
|
|
31
|
+
"Build full-stack applications faster with Croissant Stack. Featuring TanStack Start, oRPC, and Better Auth.",
|
|
19
32
|
},
|
|
20
33
|
{
|
|
21
34
|
property: "og:title",
|
|
@@ -31,18 +44,10 @@ export const Route = createFileRoute("/_public/")({
|
|
|
31
44
|
},
|
|
32
45
|
],
|
|
33
46
|
}),
|
|
34
|
-
loader:
|
|
35
|
-
const [helloRes, planets] = await Promise.all([
|
|
36
|
-
orpc.hello({ name: "Croissant Stack" }),
|
|
37
|
-
orpc.planets.getPlanets(),
|
|
38
|
-
])
|
|
39
|
-
return {
|
|
40
|
-
message: helloRes.message,
|
|
41
|
-
planets,
|
|
42
|
-
}
|
|
43
|
-
},
|
|
47
|
+
loader: () => getHomeData(),
|
|
44
48
|
headers: () => ({
|
|
45
|
-
"Cache-Control":
|
|
49
|
+
"Cache-Control":
|
|
50
|
+
"public, max-age=10, s-maxage=10, stale-while-revalidate=60",
|
|
46
51
|
}),
|
|
47
52
|
component: App,
|
|
48
53
|
})
|
|
@@ -506,18 +506,28 @@ function SidebarMenuButton({
|
|
|
506
506
|
size = "default",
|
|
507
507
|
tooltip,
|
|
508
508
|
className,
|
|
509
|
+
onClick,
|
|
509
510
|
...props
|
|
510
511
|
}: useRender.ComponentProps<"button"> &
|
|
511
512
|
React.ComponentProps<"button"> & {
|
|
512
513
|
isActive?: boolean
|
|
513
514
|
tooltip?: string | React.ComponentProps<typeof TooltipContent>
|
|
514
515
|
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
|
515
|
-
const { isMobile, state } = useSidebar()
|
|
516
|
+
const { isMobile, state, setOpenMobile } = useSidebar()
|
|
517
|
+
|
|
518
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
519
|
+
if (isMobile) {
|
|
520
|
+
setOpenMobile(false)
|
|
521
|
+
}
|
|
522
|
+
onClick?.(event)
|
|
523
|
+
}
|
|
524
|
+
|
|
516
525
|
const comp = useRender({
|
|
517
526
|
defaultTagName: "button",
|
|
518
527
|
props: mergeProps<"button">(
|
|
519
528
|
{
|
|
520
529
|
className: cn(sidebarMenuButtonVariants({ variant, size }), className),
|
|
530
|
+
onClick: handleClick,
|
|
521
531
|
},
|
|
522
532
|
props
|
|
523
533
|
),
|