create-puck-app 0.22.2 → 0.22.3
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/index.js +33 -25
- package/package.json +1 -1
- package/templates/next/README.md +94 -20
- package/templates/next-ai/README.md +141 -32
- package/templates/next-ai/app/[...puckPath]/client.tsx +4 -1
- package/templates/next-ai/app/api/puck/[...all]/route.ts +16 -1
- package/templates/next-ai/app/puck/[...puckPath]/client.tsx +18 -5
- package/templates/react-router/README.md +96 -18
- package/templates/react-router-ai/README.md +145 -30
- package/templates/react-router-ai/app/components/puck-render.tsx +4 -1
- package/templates/react-router-ai/app/routes/api.puck.ts +14 -0
- package/templates/react-router-ai/app/routes/puck-splat.tsx +25 -6
package/index.js
CHANGED
|
@@ -66,11 +66,18 @@ program
|
|
|
66
66
|
Explicitly tell the CLI to bootstrap the application using Yarn
|
|
67
67
|
`
|
|
68
68
|
)
|
|
69
|
+
.option(
|
|
70
|
+
"--ai",
|
|
71
|
+
`
|
|
72
|
+
|
|
73
|
+
Add Puck AI to the editor (requires a Puck Cloud account)
|
|
74
|
+
`
|
|
75
|
+
)
|
|
69
76
|
.action(async (_appName, options) => {
|
|
70
|
-
const
|
|
77
|
+
const questions = [];
|
|
71
78
|
|
|
72
79
|
if (!_appName) {
|
|
73
|
-
|
|
80
|
+
questions.push({
|
|
74
81
|
type: "input",
|
|
75
82
|
name: "appName",
|
|
76
83
|
message: "What is the name of your app?",
|
|
@@ -78,26 +85,27 @@ program
|
|
|
78
85
|
});
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
88
|
+
questions.push({
|
|
89
|
+
type: "list",
|
|
90
|
+
name: "recipe",
|
|
91
|
+
message: "Which recipe would you like to use?",
|
|
92
|
+
required: true,
|
|
93
|
+
default: "next",
|
|
94
|
+
choices: [
|
|
95
|
+
{
|
|
96
|
+
name: "Next.js",
|
|
97
|
+
value: "next",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "React Router",
|
|
101
|
+
value: "react-router",
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// If the user didn't specify the --ai flag, ask them if they want to add Puck AI to the editor.
|
|
107
|
+
if (!options.ai) {
|
|
108
|
+
questions.push({
|
|
101
109
|
type: "confirm",
|
|
102
110
|
name: "puckAi",
|
|
103
111
|
message: `Puck AI (beta) lets you generate pages using your own components. Learn more: ${ansiColors.cyan}https://puckeditor.com/docs/ai/overview${ansiColors.reset}
|
|
@@ -105,8 +113,8 @@ program
|
|
|
105
113
|
Add Puck AI to the editor? (Requires a Puck Cloud account)`,
|
|
106
114
|
required: true,
|
|
107
115
|
default: true,
|
|
108
|
-
}
|
|
109
|
-
|
|
116
|
+
});
|
|
117
|
+
}
|
|
110
118
|
|
|
111
119
|
const answers = await inquirer.prompt(questions);
|
|
112
120
|
|
|
@@ -120,7 +128,7 @@ program
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
const recipe = answers.recipe;
|
|
123
|
-
const usesPuckAi = answers.puckAi;
|
|
131
|
+
const usesPuckAi = answers.puckAi || !!options.ai;
|
|
124
132
|
|
|
125
133
|
// Copy template files to the new directory
|
|
126
134
|
const recipeName = `${recipe}${usesPuckAi ? "-ai" : ""}`;
|
package/package.json
CHANGED
package/templates/next/README.md
CHANGED
|
@@ -1,38 +1,112 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Puck + Next.js recipe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This recipe connects Puck to the [Next.js App Router](https://nextjs.org/docs/app), so you can create and edit pages for any route in this app.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- JSON database implementation with HTTP API
|
|
9
|
-
- Catch-all routes to use puck for any route on the platform
|
|
10
|
-
- Incremental static regeneration (ISR) for all Puck pages
|
|
7
|
+
## Core concepts
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
If you're new to Puck, this section introduces the core concepts you need to know.
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
### Puck
|
|
15
12
|
|
|
13
|
+
The Puck visual editor has three main parts: a config, the editor, and the renderer.
|
|
14
|
+
|
|
15
|
+
#### Config
|
|
16
|
+
|
|
17
|
+
The [config](https://puckeditor.com/docs/integrating-puck/component-configuration) registers the components users can use to build pages in the editor and the fields they can edit.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
const config = {
|
|
21
|
+
components: {
|
|
22
|
+
HeadingBlock: {
|
|
23
|
+
fields: {
|
|
24
|
+
title: { type: "text" },
|
|
25
|
+
},
|
|
26
|
+
render: ({ title }) => <h1>{title}</h1>,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
16
30
|
```
|
|
17
|
-
|
|
31
|
+
|
|
32
|
+
#### The editor
|
|
33
|
+
|
|
34
|
+
The [`<Puck>`](https://puckeditor.com/docs/api-reference/components/puck) component renders the editor. It uses a config, exports [pages as JSON](https://puckeditor.com/docs/api-reference/data-model/data), and accepts initial page data for editing existing pages.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Puck
|
|
38
|
+
config={config} // The components available to the editor
|
|
39
|
+
data={data} // The page JSON to edit
|
|
40
|
+
onPublish={(data) => {
|
|
41
|
+
// Save data to your database
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
18
44
|
```
|
|
19
45
|
|
|
20
|
-
|
|
46
|
+
#### The renderer
|
|
21
47
|
|
|
48
|
+
The [`<Render>`](https://puckeditor.com/docs/api-reference/components/render) component renders pages. It expects the page JSON and the config used to create that page.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Render
|
|
52
|
+
config={config} // The components used to create the page
|
|
53
|
+
data={data} // The page JSON to render
|
|
54
|
+
/>
|
|
22
55
|
```
|
|
23
|
-
|
|
56
|
+
|
|
57
|
+
## Run the recipe
|
|
58
|
+
|
|
59
|
+
### 1. Start the development server
|
|
60
|
+
|
|
61
|
+
Run:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm run dev
|
|
24
65
|
```
|
|
25
66
|
|
|
26
|
-
|
|
67
|
+
Once the server is running, navigate to [http://localhost:3000](http://localhost:3000) to view the home page, or [http://localhost:3000/edit](http://localhost:3000/edit) to edit it with Puck.
|
|
68
|
+
|
|
69
|
+
### 2. Create a page
|
|
70
|
+
|
|
71
|
+
Navigate to [http://localhost:3000/edit](http://localhost:3000/edit), open the `Blocks` tab in the left sidebar and build your page by dragging components onto the canvas.
|
|
72
|
+
|
|
73
|
+
### 3. Publish the page
|
|
74
|
+
|
|
75
|
+
Once your page is ready, select **Publish** in the header to save the result, then navigate to [http://localhost:3000](http://localhost:3000) to view the published page.
|
|
76
|
+
|
|
77
|
+
You can also create a page at any path by navigating to `/your/path/edit` and publishing it. The route `/your/path` will render the page.
|
|
78
|
+
|
|
79
|
+
## How it works
|
|
80
|
+
|
|
81
|
+
When a URL ends in `/edit`, [`proxy.ts`](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) sends the request to the Puck editor route (`app/puck/[...puckPath]/page.tsx`). The editor loads the saved page, or starts with an empty page if the path is new.
|
|
82
|
+
|
|
83
|
+
Selecting **Publish** sends the page data to the `/puck/api` endpoint (`app/puck/api/route.ts`). The handler writes the JSON to `database.json` and clears the Next.js cache for that page. The catch-all route (`app/[...puckPath]/page.tsx`) then loads the same data and renders it with [`<Render>`](https://puckeditor.com/docs/api-reference/components/render).
|
|
84
|
+
|
|
85
|
+
The table below shows the files that implement this flow.
|
|
86
|
+
|
|
87
|
+
| File | Purpose |
|
|
88
|
+
| ----------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `puck.config.tsx` | Defines the components, fields, and default props available to Puck. Add your own components here. |
|
|
90
|
+
| `app/puck/[...puckPath]/page.tsx` | Loads page data for the editor. |
|
|
91
|
+
| `app/puck/[...puckPath]/client.tsx` | Renders the editor and publishes changes. |
|
|
92
|
+
| `app/[...puckPath]/page.tsx` | Loads and renders published pages. |
|
|
93
|
+
| `app/puck/api/route.ts` | Saves published pages. |
|
|
94
|
+
| `proxy.ts` | Routes URLs ending in `/edit` to `/puck/[...puckPath]/page.tsx`. |
|
|
95
|
+
| `lib/get-page.ts` | Reads page data from `database.json`. Replace this with your own data fetching logic. |
|
|
96
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
27
97
|
|
|
28
|
-
|
|
98
|
+
## Before deploying to production
|
|
29
99
|
|
|
30
|
-
|
|
100
|
+
Before deploying this recipe, make sure to:
|
|
31
101
|
|
|
32
|
-
|
|
102
|
+
- **Protect the editor and API.** The `/edit` routes and `/puck/api` endpoint are public by default. Add authentication and authorization so only trusted users can edit or publish pages.
|
|
103
|
+
- **Add your component library.** Replace the example `HeadingBlock` in `puck.config.tsx` with the components and fields your users need.
|
|
104
|
+
- **Use a real database.** Replace `database.json` in `lib/get-page.ts` and `app/puck/api/route.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
105
|
+
- **Choose a rendering strategy.** `app/[...puckPath]/page.tsx` uses `force-static`. Remove it if a page needs request-time data such as headers, cookies, or user sessions.
|
|
33
106
|
|
|
34
|
-
|
|
35
|
-
- Integrate your database into the API calls in `/app/puck/api/route.ts`
|
|
36
|
-
- Implement a custom puck configuration in `puck.config.tsx`
|
|
107
|
+
## Learn more
|
|
37
108
|
|
|
38
|
-
|
|
109
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
110
|
+
- [Getting started with Puck](https://puckeditor.com/docs/getting-started)
|
|
111
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
112
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -1,60 +1,169 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Puck AI + Next.js recipe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React. It lets you create page builders that use your own components.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[Puck AI](https://puckeditor.com/docs/ai/overview) builds on the same principles to let you generate pages by assembling your existing components or creating new ones on the fly, either as a copilot in the editor or headlessly.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Next.js App Router implementation
|
|
9
|
-
- JSON database implementation with HTTP API
|
|
10
|
-
- Catch-all routes to use puck for any route on the platform
|
|
11
|
-
- Incremental static regeneration (ISR) for all Puck pages
|
|
7
|
+
This recipe connects Puck and Puck AI to the [Next.js App Router](https://nextjs.org/docs/app), so you can create and edit pages for any route in this app.
|
|
12
8
|
|
|
13
|
-
##
|
|
9
|
+
## Core concepts
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
If you're new to Puck, this section introduces the core concepts you need to know.
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
npx create-puck-app my-app
|
|
13
|
+
### Puck
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
The Puck visual editor has three main parts: a config, the editor, and the renderer.
|
|
16
|
+
|
|
17
|
+
#### Config
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
The [config](https://puckeditor.com/docs/integrating-puck/component-configuration) registers the components users can use to build pages in the editor and the fields they can edit.
|
|
25
20
|
|
|
21
|
+
```tsx
|
|
22
|
+
const config = {
|
|
23
|
+
components: {
|
|
24
|
+
HeadingBlock: {
|
|
25
|
+
fields: {
|
|
26
|
+
title: { type: "text" },
|
|
27
|
+
},
|
|
28
|
+
render: ({ title }) => <h1>{title}</h1>,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
26
32
|
```
|
|
27
|
-
|
|
33
|
+
|
|
34
|
+
#### The editor
|
|
35
|
+
|
|
36
|
+
The [`<Puck>`](https://puckeditor.com/docs/api-reference/components/puck) component renders the editor. It uses a config, exports [pages as JSON](https://puckeditor.com/docs/api-reference/data-model/data), and accepts initial page data for editing existing pages.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Puck
|
|
40
|
+
config={config} // The components available to the editor
|
|
41
|
+
data={data} // The page JSON to edit
|
|
42
|
+
onPublish={(data) => {
|
|
43
|
+
// Save data to your database
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
28
46
|
```
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
#### The renderer
|
|
49
|
+
|
|
50
|
+
The [`<Render>`](https://puckeditor.com/docs/api-reference/components/render) component renders pages. It expects the page JSON and the config used to create that page.
|
|
31
51
|
|
|
52
|
+
```tsx
|
|
53
|
+
<Render
|
|
54
|
+
config={config} // The components used to create the page
|
|
55
|
+
data={data} // The page JSON to render
|
|
56
|
+
/>
|
|
32
57
|
```
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
|
|
59
|
+
### Puck AI
|
|
60
|
+
|
|
61
|
+
This recipe adds Puck AI as a copilot. It has two parts: the AI plugin (browser) and the Cloud Client (server).
|
|
62
|
+
|
|
63
|
+
#### The AI plugin
|
|
64
|
+
|
|
65
|
+
The [AI plugin](https://puckeditor.com/docs/api-reference/ai/ai-plugin/installation) renders the chat in the editor and sends each message to the Cloud Client on your server.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
const aiPlugin = createAiPlugin();
|
|
69
|
+
|
|
70
|
+
function Editor() {
|
|
71
|
+
return <Puck plugins={[aiPlugin]} config={config} data={data} />;
|
|
72
|
+
}
|
|
35
73
|
```
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
#### The Cloud Client
|
|
38
76
|
|
|
39
|
-
|
|
77
|
+
The [Cloud Client](https://puckeditor.com/docs/api-reference/ai/cloud-client/installation) provides APIs for connecting your server to the Puck cloud. This recipe uses its [`puckHandler`](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler) API, which receives each chat message, forwards it to the Puck cloud, and streams the response back to the plugin in the browser.
|
|
40
78
|
|
|
41
|
-
|
|
79
|
+
```ts
|
|
80
|
+
const handleRequest = (request: NextRequest) => {
|
|
81
|
+
return puckHandler(request, {
|
|
82
|
+
ai: {
|
|
83
|
+
context: "We are Google. You create Google landing pages.",
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
};
|
|
42
87
|
|
|
88
|
+
export const DELETE = handleRequest;
|
|
89
|
+
export const GET = handleRequest;
|
|
90
|
+
export const POST = handleRequest;
|
|
43
91
|
```
|
|
92
|
+
|
|
93
|
+
#### Puck AI modes
|
|
94
|
+
|
|
95
|
+
Puck AI can build pages in two ways:
|
|
96
|
+
|
|
97
|
+
- **Assembly mode** only builds pages using components from your config.
|
|
98
|
+
- **Design mode** can generate new components when needed.
|
|
99
|
+
|
|
100
|
+
This recipe comes with [Design mode](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler#aidesignmode) enabled out of the box.
|
|
101
|
+
|
|
102
|
+
## Run the recipe
|
|
103
|
+
|
|
104
|
+
### 1. Add a Puck API key
|
|
105
|
+
|
|
106
|
+
Start by creating an account, [generating an API key](https://cloud.puckeditor.com/api-keys), and adding it to a `.env.local` file:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
44
109
|
PUCK_API_KEY=your-api-key
|
|
45
110
|
```
|
|
46
111
|
|
|
47
|
-
|
|
112
|
+
### 2. Start the development server
|
|
113
|
+
|
|
114
|
+
Run:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
npm run dev
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Once the server is running, navigate to [http://localhost:3000](http://localhost:3000) to view the home page, or [http://localhost:3000/edit](http://localhost:3000/edit) to edit it with Puck.
|
|
121
|
+
|
|
122
|
+
### 3. Create a page with Puck AI
|
|
123
|
+
|
|
124
|
+
Navigate to [http://localhost:3000/edit](http://localhost:3000/edit), click the **AI** button in the left sidebar, enter a prompt, and press Enter.
|
|
125
|
+
|
|
126
|
+
### 4. Publish the page
|
|
127
|
+
|
|
128
|
+
Once your page is ready, select **Publish** in the header to save the result, then navigate to [http://localhost:3000](http://localhost:3000) to view the published page.
|
|
129
|
+
|
|
130
|
+
You can also create a page at any path by navigating to `/your/path/edit` and publishing it. The route `/your/path` will render the page.
|
|
131
|
+
|
|
132
|
+
## How it works
|
|
133
|
+
|
|
134
|
+
When a URL ends in `/edit`, [`proxy.ts`](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) sends the request to the Puck editor route (`app/puck/[...puckPath]/page.tsx`). The editor loads the saved page, or starts with an empty page if the path is new.
|
|
135
|
+
|
|
136
|
+
Selecting **Publish** sends the page data to the `/api/pages` endpoint (`app/api/pages/route.ts`). The handler writes the JSON to `database.json` and clears the Next.js cache for that page. The catch-all route (`app/[...puckPath]/page.tsx`) then loads the same data and renders it with [`<Render>`](https://puckeditor.com/docs/api-reference/components/render).
|
|
137
|
+
|
|
138
|
+
The table below shows the files that implement this flow.
|
|
139
|
+
|
|
140
|
+
| File | Purpose |
|
|
141
|
+
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `puck.config.tsx` | Defines the components, fields, and default props available to Puck and Assembly mode. Add your own components here. |
|
|
143
|
+
| `app/puck/[...puckPath]/page.tsx` | Loads page data for the editor. |
|
|
144
|
+
| `app/puck/[...puckPath]/client.tsx` | Renders the editor with the AI copilot, sends prompts to your server, and publishes changes. |
|
|
145
|
+
| `app/[...puckPath]/page.tsx` | Loads and renders published pages. |
|
|
146
|
+
| `app/api/pages/route.ts` | Saves published pages. |
|
|
147
|
+
| `app/api/puck/[...all]/route.ts` | Handles requests from the AI plugin and configures AI generation. |
|
|
148
|
+
| `proxy.ts` | Routes URLs ending in `/edit` to `/puck/[...puckPath]/page.tsx`. |
|
|
149
|
+
| `lib/get-page.ts` | Reads page data from `database.json`. Replace this with your own data fetching logic. |
|
|
150
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
48
151
|
|
|
49
|
-
|
|
152
|
+
## Before deploying to production
|
|
50
153
|
|
|
51
|
-
|
|
154
|
+
Before deploying this recipe, make sure to:
|
|
52
155
|
|
|
53
|
-
|
|
156
|
+
- **Protect the editor and APIs.** The `/edit`, `/api/pages`, and `/api/puck` routes are public by default. Add authentication, authorization, and rate limits to protect page data and AI usage.
|
|
157
|
+
- **Add your component library.** Replace the example `HeadingBlock` in `puck.config.tsx` with the components and fields your users need.
|
|
158
|
+
- **Set your business context.** Replace the example Google context in `app/api/puck/[...all]/route.ts` with clear information about your product, audience, and content rules.
|
|
159
|
+
- **Use a real database.** Replace `database.json` in `lib/get-page.ts` and `app/api/pages/route.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
160
|
+
- **Choose a rendering strategy.** `app/[...puckPath]/page.tsx` uses `force-static`. Remove it if a page needs request-time data such as headers, cookies, or user sessions.
|
|
54
161
|
|
|
55
|
-
|
|
56
|
-
- Integrate your database into the API calls in `/app/puck/api/route.ts`
|
|
57
|
-
- Implement a custom puck configuration in `puck.config.tsx`
|
|
58
|
-
- Add business context for the AI generation in `/app/api/puck/[...all]/route.ts`
|
|
162
|
+
## Learn more
|
|
59
163
|
|
|
60
|
-
|
|
164
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
165
|
+
- [Getting started with Puck](https://puckeditor.com/docs/getting-started)
|
|
166
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
167
|
+
- [Puck AI documentation](https://puckeditor.com/docs/ai/overview)
|
|
168
|
+
- [Getting started with Puck AI](https://puckeditor.com/docs/ai/getting-started)
|
|
169
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import type { Data } from "@puckeditor/core";
|
|
4
4
|
import { Render } from "@puckeditor/core";
|
|
5
|
+
import { withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
5
6
|
import config from "../../puck.config";
|
|
6
7
|
|
|
7
8
|
export function Client({ data }: { data: Data }) {
|
|
8
|
-
|
|
9
|
+
const configWithDesignedComponents = withDynamicConfig(config, data);
|
|
10
|
+
|
|
11
|
+
return <Render config={configWithDesignedComponents} data={data} />;
|
|
9
12
|
}
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
// Handles all requests for Puck AI
|
|
2
2
|
// Learn more: https://puckeditor.com/docs/ai/getting-started
|
|
3
|
+
import type { NextRequest } from "next/server";
|
|
3
4
|
import { puckHandler } from "@puckeditor/cloud-client";
|
|
4
5
|
|
|
5
|
-
const handleRequest = (request) => {
|
|
6
|
+
const handleRequest = (request: NextRequest): Promise<Response> => {
|
|
6
7
|
return puckHandler(request, {
|
|
7
8
|
ai: {
|
|
8
9
|
// Replace with your business context
|
|
9
10
|
context: "We are Google. You create Google landing pages.",
|
|
11
|
+
designMode: {
|
|
12
|
+
// Allow AI to generate new components using "design mode"
|
|
13
|
+
// Learn more: https://puckeditor.com/docs/ai/design-mode
|
|
14
|
+
allowed: true,
|
|
15
|
+
// Constrain component generation, replace with your own instructions
|
|
16
|
+
instructions: `
|
|
17
|
+
#### Color Palette
|
|
18
|
+
|
|
19
|
+
Always use the following colors:
|
|
20
|
+
|
|
21
|
+
* Primary: \`#1976d2\`
|
|
22
|
+
* Secondary: \`#9c27b0\`
|
|
23
|
+
`,
|
|
24
|
+
},
|
|
10
25
|
},
|
|
11
26
|
});
|
|
12
27
|
};
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import type { Data } from "@puckeditor/core";
|
|
4
|
-
import { Puck } from "@puckeditor/core";
|
|
5
|
-
import { createAiPlugin } from "@puckeditor/plugin-ai";
|
|
4
|
+
import { Puck, blocksPlugin, outlinePlugin } from "@puckeditor/core";
|
|
5
|
+
import { createAiPlugin, withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
6
6
|
|
|
7
7
|
import config from "../../../puck.config";
|
|
8
8
|
|
|
9
|
-
const aiPlugin = createAiPlugin(
|
|
9
|
+
const aiPlugin = createAiPlugin({
|
|
10
|
+
// Allow users to switch between design and assembly mode.
|
|
11
|
+
// Read more: https://puckeditor.com/docs/ai/design-mode
|
|
12
|
+
designMode: {
|
|
13
|
+
visible: true,
|
|
14
|
+
},
|
|
15
|
+
// Select design mode by default.
|
|
16
|
+
defaultMode: "design",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Place the ai plugin in the first position in the side nav.
|
|
20
|
+
const plugins = [aiPlugin, blocksPlugin(), outlinePlugin()];
|
|
10
21
|
|
|
11
22
|
export function Client({ path, data }: { path: string; data: Partial<Data> }) {
|
|
23
|
+
const configWithDesignedComponents = withDynamicConfig(config, data);
|
|
24
|
+
|
|
12
25
|
return (
|
|
13
26
|
<Puck
|
|
14
|
-
plugins={
|
|
15
|
-
config={config}
|
|
27
|
+
plugins={plugins}
|
|
16
28
|
data={data}
|
|
29
|
+
config={configWithDesignedComponents}
|
|
17
30
|
onPublish={async (data) => {
|
|
18
31
|
await fetch("/api/pages", {
|
|
19
32
|
method: "post",
|
|
@@ -1,35 +1,113 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Puck + React Router recipe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This recipe connects Puck to [React Router](https://reactrouter.com) in framework mode, so you can create and edit pages for any route in this app.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- JSON database implementation
|
|
9
|
-
- Splat route to use puck for any route on the platform
|
|
7
|
+
## Core concepts
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
If you're new to Puck, this section introduces the core concepts you need to know.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
### Puck
|
|
14
12
|
|
|
13
|
+
The Puck visual editor has three main parts: a config, the editor, and the renderer.
|
|
14
|
+
|
|
15
|
+
#### Config
|
|
16
|
+
|
|
17
|
+
The [config](https://puckeditor.com/docs/integrating-puck/component-configuration) registers the components users can use to build pages in the editor and the fields they can edit.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
const config = {
|
|
21
|
+
components: {
|
|
22
|
+
HeadingBlock: {
|
|
23
|
+
fields: {
|
|
24
|
+
title: { type: "text" },
|
|
25
|
+
},
|
|
26
|
+
render: ({ title }) => <h1>{title}</h1>,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
15
30
|
```
|
|
16
|
-
|
|
31
|
+
|
|
32
|
+
#### The editor
|
|
33
|
+
|
|
34
|
+
The [`<Puck>`](https://puckeditor.com/docs/api-reference/components/puck) component renders the editor. It uses a config, exports [pages as JSON](https://puckeditor.com/docs/api-reference/data-model/data), and accepts initial page data for editing existing pages.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Puck
|
|
38
|
+
config={config} // The components available to the editor
|
|
39
|
+
data={data} // The page JSON to edit
|
|
40
|
+
onPublish={(data) => {
|
|
41
|
+
// Save data to your database
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
17
44
|
```
|
|
18
45
|
|
|
19
|
-
|
|
46
|
+
#### The renderer
|
|
20
47
|
|
|
48
|
+
The [`<Render>`](https://puckeditor.com/docs/api-reference/components/render) component renders pages. It expects the page JSON and the config used to create that page.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Render
|
|
52
|
+
config={config} // The components used to create the page
|
|
53
|
+
data={data} // The page JSON to render
|
|
54
|
+
/>
|
|
21
55
|
```
|
|
22
|
-
|
|
56
|
+
|
|
57
|
+
## Run the recipe
|
|
58
|
+
|
|
59
|
+
### 1. Start the development server
|
|
60
|
+
|
|
61
|
+
Run:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm run dev
|
|
23
65
|
```
|
|
24
66
|
|
|
25
|
-
|
|
67
|
+
Once the server is running, navigate to [http://localhost:5173](http://localhost:5173) to view the home page, or [http://localhost:5173/edit](http://localhost:5173/edit) to edit it with Puck.
|
|
68
|
+
|
|
69
|
+
### 2. Create a page
|
|
70
|
+
|
|
71
|
+
Navigate to [http://localhost:5173/edit](http://localhost:5173/edit), open the `Blocks` tab in the left sidebar and build your page by dragging components onto the canvas.
|
|
72
|
+
|
|
73
|
+
### 3. Publish the page
|
|
74
|
+
|
|
75
|
+
Once your page is ready, select **Publish** in the header to save the result, then navigate to [http://localhost:5173](http://localhost:5173) to view the published page.
|
|
76
|
+
|
|
77
|
+
You can also create a page at any path by navigating to `/your/path/edit` and publishing it. The route `/your/path` will render the page.
|
|
78
|
+
|
|
79
|
+
## How it works
|
|
80
|
+
|
|
81
|
+
When a URL ends in `/edit`, `resolvePuckPath` (`app/lib/resolve-puck-path.server.ts`) returns the path of the page being edited. The loader in `app/routes/puck-splat.tsx` loads the saved page, or starts with an empty page if the path is new.
|
|
82
|
+
|
|
83
|
+
Selecting **Publish** sends the page data to the action in `app/routes/puck-splat.tsx`. The action writes the JSON to `database.json`. The route then loads the same data and renders it with [`<Render>`](https://puckeditor.com/docs/api-reference/components/render).
|
|
84
|
+
|
|
85
|
+
The table below shows the files that implement this flow.
|
|
86
|
+
|
|
87
|
+
| File | Purpose |
|
|
88
|
+
| ------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `puck.config.tsx` | Defines the components, fields, and default props available to Puck. Add your own components here. |
|
|
90
|
+
| `app/routes.ts` | Registers the home page and catch-all page route. |
|
|
91
|
+
| `app/routes/puck-splat.tsx` | Loads and saves page data, then renders the editor or published page. |
|
|
92
|
+
| `app/routes/_index.tsx` | Loads and renders the home page. |
|
|
93
|
+
| `app/lib/resolve-puck-path.server.ts` | Maps an `/edit` URL to the path of the page being edited. |
|
|
94
|
+
| `app/lib/pages.server.ts` | Reads and writes page data in `database.json`. Replace this with your own data fetching and saving logic. |
|
|
95
|
+
| `app/components/puck-render.tsx` | Renders saved page data with `<Render>`. |
|
|
96
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
97
|
+
|
|
98
|
+
## Before deploying to production
|
|
26
99
|
|
|
27
|
-
|
|
100
|
+
Before deploying this recipe, make sure to:
|
|
28
101
|
|
|
29
|
-
|
|
102
|
+
- **Protect the editor and publishing.** The `/edit` routes and publish action are public by default. Add authentication and authorization so only trusted users can edit or publish pages.
|
|
103
|
+
- **Add your component library.** Replace the example `HeadingBlock` in `puck.config.tsx` with the components and fields your users need.
|
|
104
|
+
- **Use a real database.** Replace `database.json` and the functions in `app/lib/pages.server.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
105
|
+
- **Choose a deployment strategy.** This recipe uses server-side rendering, loaders, and actions. Deploy it to a React Router-compatible server runtime.
|
|
30
106
|
|
|
31
|
-
|
|
107
|
+
## Learn more
|
|
32
108
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
109
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
110
|
+
- [Getting started with Puck](https://puckeditor.com/docs/getting-started)
|
|
111
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
112
|
+
- [React Router framework mode](https://reactrouter.com/start/framework/installation)
|
|
113
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -1,57 +1,172 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Puck AI + React Router recipe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React. It lets you create page builders that use your own components.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[Puck AI](https://puckeditor.com/docs/ai/overview) builds on the same principles to let you generate pages by assembling your existing components or creating new ones on the fly, either as a copilot in the editor or headlessly.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- React Router v7 (framework) implementation
|
|
9
|
-
- JSON database implementation
|
|
10
|
-
- Splat route to use puck for any route on the platform
|
|
7
|
+
This recipe connects Puck and Puck AI to [React Router](https://reactrouter.com) in framework mode, so you can create and edit pages for any route in this app.
|
|
11
8
|
|
|
12
|
-
##
|
|
9
|
+
## Core concepts
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
If you're new to Puck, this section introduces the core concepts you need to know.
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
npx create-puck-app my-app
|
|
13
|
+
### Puck
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
The Puck visual editor has three main parts: a config, the editor, and the renderer.
|
|
16
|
+
|
|
17
|
+
#### Config
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
The [config](https://puckeditor.com/docs/integrating-puck/component-configuration) registers the components users can use to build pages in the editor and the fields they can edit.
|
|
24
20
|
|
|
21
|
+
```tsx
|
|
22
|
+
const config = {
|
|
23
|
+
components: {
|
|
24
|
+
HeadingBlock: {
|
|
25
|
+
fields: {
|
|
26
|
+
title: { type: "text" },
|
|
27
|
+
},
|
|
28
|
+
render: ({ title }) => <h1>{title}</h1>,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
25
32
|
```
|
|
26
|
-
|
|
33
|
+
|
|
34
|
+
#### The editor
|
|
35
|
+
|
|
36
|
+
The [`<Puck>`](https://puckeditor.com/docs/api-reference/components/puck) component renders the editor. It uses a config, exports [pages as JSON](https://puckeditor.com/docs/api-reference/data-model/data), and accepts initial page data for editing existing pages.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Puck
|
|
40
|
+
config={config} // The components available to the editor
|
|
41
|
+
data={data} // The page JSON to edit
|
|
42
|
+
onPublish={(data) => {
|
|
43
|
+
// Save data to your database
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
27
46
|
```
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
#### The renderer
|
|
49
|
+
|
|
50
|
+
The [`<Render>`](https://puckeditor.com/docs/api-reference/components/render) component renders pages. It expects the page JSON and the config used to create that page.
|
|
30
51
|
|
|
52
|
+
```tsx
|
|
53
|
+
<Render
|
|
54
|
+
config={config} // The components used to create the page
|
|
55
|
+
data={data} // The page JSON to render
|
|
56
|
+
/>
|
|
31
57
|
```
|
|
32
|
-
|
|
33
|
-
|
|
58
|
+
|
|
59
|
+
### Puck AI
|
|
60
|
+
|
|
61
|
+
This recipe adds Puck AI as a copilot. It has two parts: the AI plugin (browser) and the Cloud Client (server).
|
|
62
|
+
|
|
63
|
+
#### The AI plugin
|
|
64
|
+
|
|
65
|
+
The [AI plugin](https://puckeditor.com/docs/api-reference/ai/ai-plugin/installation) renders the chat in the editor and sends each message to the Cloud Client on your server.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
const aiPlugin = createAiPlugin();
|
|
69
|
+
|
|
70
|
+
function Editor() {
|
|
71
|
+
return <Puck plugins={[aiPlugin]} config={config} data={data} />;
|
|
72
|
+
}
|
|
34
73
|
```
|
|
35
74
|
|
|
36
|
-
|
|
75
|
+
#### The Cloud Client
|
|
37
76
|
|
|
38
|
-
|
|
77
|
+
The [Cloud Client](https://puckeditor.com/docs/api-reference/ai/cloud-client/installation) provides APIs for connecting your server to the Puck cloud. This recipe uses its [`puckHandler`](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler) API, which receives each chat message, forwards it to the Puck cloud, and streams the response back to the plugin in the browser.
|
|
39
78
|
|
|
40
|
-
|
|
79
|
+
```ts
|
|
80
|
+
const options = {
|
|
81
|
+
ai: {
|
|
82
|
+
context: "We are Google. You create Google landing pages.",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
41
85
|
|
|
86
|
+
export function loader(args: LoaderFunctionArgs) {
|
|
87
|
+
return puckHandler(args.request, options);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function action(args: ActionFunctionArgs) {
|
|
91
|
+
return puckHandler(args.request, options);
|
|
92
|
+
}
|
|
42
93
|
```
|
|
94
|
+
|
|
95
|
+
#### Puck AI modes
|
|
96
|
+
|
|
97
|
+
Puck AI can build pages in two ways:
|
|
98
|
+
|
|
99
|
+
- **Assembly mode** only builds pages using components from your config.
|
|
100
|
+
- **Design mode** can generate new components when needed.
|
|
101
|
+
|
|
102
|
+
This recipe comes with [Design mode](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler#aidesignmode) enabled out of the box.
|
|
103
|
+
|
|
104
|
+
## Run the recipe
|
|
105
|
+
|
|
106
|
+
### 1. Add a Puck API key
|
|
107
|
+
|
|
108
|
+
Start by creating an account, [generating an API key](https://cloud.puckeditor.com/api-keys), and adding it to an `.env.local` file:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
43
111
|
PUCK_API_KEY=your-api-key
|
|
44
112
|
```
|
|
45
113
|
|
|
46
|
-
|
|
114
|
+
### 2. Start the development server
|
|
115
|
+
|
|
116
|
+
Run:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npm run dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Once the server is running, navigate to [http://localhost:5173](http://localhost:5173) to view the home page, or [http://localhost:5173/edit](http://localhost:5173/edit) to edit it with Puck.
|
|
123
|
+
|
|
124
|
+
### 3. Create a page with Puck AI
|
|
125
|
+
|
|
126
|
+
Navigate to [http://localhost:5173/edit](http://localhost:5173/edit), click the **AI** button in the left sidebar, enter a prompt, and press Enter.
|
|
127
|
+
|
|
128
|
+
### 4. Publish the page
|
|
129
|
+
|
|
130
|
+
Once your page is ready, select **Publish** in the header to save the result, then navigate to [http://localhost:5173](http://localhost:5173) to view the published page.
|
|
131
|
+
|
|
132
|
+
You can also create a page at any path by navigating to `/your/path/edit` and publishing it. The route `/your/path` will render the page.
|
|
133
|
+
|
|
134
|
+
## How it works
|
|
135
|
+
|
|
136
|
+
When a URL ends in `/edit`, `resolvePuckPath` (`app/lib/resolve-puck-path.server.ts`) returns the path of the page being edited. The loader in `app/routes/puck-splat.tsx` loads the saved page, or starts with an empty page if the path is new.
|
|
137
|
+
|
|
138
|
+
Selecting **Publish** sends the page data to the action in `app/routes/puck-splat.tsx`. The action writes the JSON to `database.json`. The route then loads the same data and renders it with [`<Render>`](https://puckeditor.com/docs/api-reference/components/render).
|
|
139
|
+
|
|
140
|
+
The table below shows the files that implement this flow.
|
|
141
|
+
|
|
142
|
+
| File | Purpose |
|
|
143
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| `puck.config.tsx` | Defines the components, fields, and default props available to Puck and Assembly mode. Add your own components here. |
|
|
145
|
+
| `app/routes.ts` | Registers the home page, Puck AI API, and catch-all page route. |
|
|
146
|
+
| `app/routes/puck-splat.tsx` | Loads and saves page data, then renders the editor or published page. |
|
|
147
|
+
| `app/routes/api.puck.ts` | Handles requests from the AI plugin and configures AI generation. |
|
|
148
|
+
| `app/routes/_index.tsx` | Loads and renders the home page. |
|
|
149
|
+
| `app/lib/resolve-puck-path.server.ts` | Maps an `/edit` URL to the path of the page being edited. |
|
|
150
|
+
| `app/lib/pages.server.ts` | Reads and writes page data in `database.json`. Replace this with your own data fetching and saving logic. |
|
|
151
|
+
| `app/components/puck-render.tsx` | Renders saved page data with `<Render>`. |
|
|
152
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
153
|
+
|
|
154
|
+
## Before deploying to production
|
|
47
155
|
|
|
48
|
-
|
|
156
|
+
Before deploying this recipe, make sure to:
|
|
49
157
|
|
|
50
|
-
|
|
158
|
+
- **Protect the editor and APIs.** The `/edit` routes, publish action, and `/api/puck` route are public by default. Add authentication, authorization, and rate limits to protect page data and AI usage.
|
|
159
|
+
- **Add your component library.** Replace the example `HeadingBlock` in `puck.config.tsx` with the components and fields your users need.
|
|
160
|
+
- **Set your business context.** Replace the example Google context in `app/routes/api.puck.ts` with clear information about your product, audience, and content rules.
|
|
161
|
+
- **Use a real database.** Replace `database.json` and the functions in `app/lib/pages.server.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
162
|
+
- **Choose a deployment strategy.** This recipe uses server-side rendering, loaders, and actions. Deploy it to a React Router-compatible server runtime.
|
|
51
163
|
|
|
52
|
-
|
|
164
|
+
## Learn more
|
|
53
165
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
166
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
167
|
+
- [Getting started with Puck](https://puckeditor.com/docs/getting-started)
|
|
168
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
169
|
+
- [Puck AI documentation](https://puckeditor.com/docs/ai/overview)
|
|
170
|
+
- [Getting started with Puck AI](https://puckeditor.com/docs/ai/getting-started)
|
|
171
|
+
- [React Router framework mode](https://reactrouter.com/start/framework/installation)
|
|
172
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { Data } from "@puckeditor/core";
|
|
2
2
|
import { Render } from "@puckeditor/core";
|
|
3
|
+
import { withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
3
4
|
|
|
4
5
|
import { config } from "../../puck.config";
|
|
5
6
|
|
|
6
7
|
export function PuckRender({ data }: { data: Data }) {
|
|
7
|
-
|
|
8
|
+
const configWithDesignedComponents = withDynamicConfig(config, data);
|
|
9
|
+
|
|
10
|
+
return <Render config={configWithDesignedComponents} data={data} />;
|
|
8
11
|
}
|
|
@@ -8,6 +8,20 @@ const options: PuckCloudOptions = {
|
|
|
8
8
|
ai: {
|
|
9
9
|
// Replace with your business context
|
|
10
10
|
context: "We are Google. You create Google landing pages.",
|
|
11
|
+
designMode: {
|
|
12
|
+
// Allow AI to generate new components using "design mode"
|
|
13
|
+
// Learn more: https://puckeditor.com/docs/ai/design-mode
|
|
14
|
+
allowed: true,
|
|
15
|
+
// Constrain component generation, replace with your own instructions
|
|
16
|
+
instructions: `
|
|
17
|
+
#### Color Palette
|
|
18
|
+
|
|
19
|
+
Always use the following colors:
|
|
20
|
+
|
|
21
|
+
* Primary: \`#1976d2\`
|
|
22
|
+
* Secondary: \`#9c27b0\`
|
|
23
|
+
`,
|
|
24
|
+
},
|
|
11
25
|
},
|
|
12
26
|
};
|
|
13
27
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
1
2
|
import { useFetcher, useLoaderData } from "react-router";
|
|
2
3
|
import type { Data } from "@puckeditor/core";
|
|
3
|
-
import { Puck,
|
|
4
|
-
import { createAiPlugin } from "@puckeditor/plugin-ai";
|
|
4
|
+
import { Puck, blocksPlugin, outlinePlugin } from "@puckeditor/core";
|
|
5
|
+
import { createAiPlugin, withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
5
6
|
|
|
6
7
|
import type { Route } from "./+types/puck-splat";
|
|
7
8
|
import { config } from "../../puck.config";
|
|
8
9
|
import { resolvePuckPath } from "~/lib/resolve-puck-path.server";
|
|
9
10
|
import { getPage, savePage } from "~/lib/pages.server";
|
|
11
|
+
import { PuckRender } from "~/components/puck-render";
|
|
12
|
+
|
|
10
13
|
import editorStyles from "@puckeditor/core/puck.css?url";
|
|
11
14
|
import pluginStyles from "@puckeditor/plugin-ai/styles.css?url";
|
|
12
15
|
|
|
@@ -57,19 +60,35 @@ export async function action({ params, request }: Route.ActionArgs) {
|
|
|
57
60
|
await savePage(path, body.data);
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
const aiPlugin = createAiPlugin(
|
|
63
|
+
const aiPlugin = createAiPlugin({
|
|
64
|
+
// Allow users to switch between design and assembly mode.
|
|
65
|
+
// Read more: https://puckeditor.com/docs/ai/design-mode
|
|
66
|
+
designMode: {
|
|
67
|
+
visible: true,
|
|
68
|
+
},
|
|
69
|
+
// Select design mode by default.
|
|
70
|
+
defaultMode: "design",
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Place the ai plugin in the first position in the side nav.
|
|
74
|
+
const plugins = [aiPlugin, blocksPlugin(), outlinePlugin()];
|
|
61
75
|
|
|
62
76
|
function Editor() {
|
|
63
77
|
const loaderData = useLoaderData<typeof loader>();
|
|
64
78
|
const fetcher = useFetcher<typeof action>();
|
|
65
79
|
|
|
80
|
+
const configWithDesignedComponents = useMemo(
|
|
81
|
+
() => withDynamicConfig(config, loaderData.data),
|
|
82
|
+
[config, loaderData.data]
|
|
83
|
+
);
|
|
84
|
+
|
|
66
85
|
return (
|
|
67
86
|
<>
|
|
68
87
|
<link rel="stylesheet" href={editorStyles} id="puck-css" />
|
|
69
88
|
<link rel="stylesheet" href={pluginStyles} id="puck-plugin-ai-css" />
|
|
70
89
|
<Puck
|
|
71
|
-
plugins={
|
|
72
|
-
config={
|
|
90
|
+
plugins={plugins}
|
|
91
|
+
config={configWithDesignedComponents}
|
|
73
92
|
data={loaderData.data}
|
|
74
93
|
onPublish={async (data) => {
|
|
75
94
|
await fetcher.submit(
|
|
@@ -94,7 +113,7 @@ export default function PuckSplatRoute({ loaderData }: Route.ComponentProps) {
|
|
|
94
113
|
{loaderData.isEditorRoute ? (
|
|
95
114
|
<Editor />
|
|
96
115
|
) : (
|
|
97
|
-
<
|
|
116
|
+
<PuckRender data={loaderData.data} />
|
|
98
117
|
)}
|
|
99
118
|
</div>
|
|
100
119
|
);
|